mirror of https://github.com/aamine/cbc
257 lines
6.6 KiB
Java
257 lines
6.6 KiB
Java
package net.loveruby.cflat.compiler;
|
|
import net.loveruby.cflat.ast.*;
|
|
import net.loveruby.cflat.entity.*;
|
|
import net.loveruby.cflat.type.*;
|
|
import net.loveruby.cflat.utils.ErrorHandler;
|
|
import net.loveruby.cflat.exception.*;
|
|
import java.util.*;
|
|
|
|
class DereferenceChecker extends Visitor {
|
|
// #@@range/ctor{
|
|
private final TypeTable typeTable;
|
|
private final ErrorHandler errorHandler;
|
|
|
|
public DereferenceChecker(TypeTable typeTable, ErrorHandler h) {
|
|
this.typeTable = typeTable;
|
|
this.errorHandler = h;
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/check_AST{
|
|
public void check(AST ast) throws SemanticException {
|
|
for (DefinedVariable var : ast.definedVariables()) {
|
|
checkToplevelVariable(var);
|
|
}
|
|
for (DefinedFunction f : ast.definedFunctions()) {
|
|
check(f.body());
|
|
}
|
|
if (errorHandler.errorOccured()) {
|
|
throw new SemanticException("compile failed.");
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
private void checkToplevelVariable(DefinedVariable var) {
|
|
checkVariable(var);
|
|
if (var.hasInitializer()) {
|
|
checkConstant(var.initializer());
|
|
}
|
|
}
|
|
|
|
private void checkConstant(ExprNode expr) {
|
|
if (! expr.isConstant()) {
|
|
errorHandler.error(expr.location(), "not a constant");
|
|
}
|
|
}
|
|
|
|
// #@@range/check{
|
|
private void check(StmtNode node) {
|
|
node.accept(this);
|
|
}
|
|
|
|
private void check(ExprNode node) {
|
|
node.accept(this);
|
|
}
|
|
// #@@}
|
|
|
|
//
|
|
// Statements
|
|
//
|
|
|
|
// #@@range/BlockNode{
|
|
public Void visit(BlockNode node) {
|
|
for (DefinedVariable var : node.variables()) {
|
|
checkVariable(var);
|
|
}
|
|
for (StmtNode stmt : node.stmts()) {
|
|
try {
|
|
check(stmt);
|
|
}
|
|
catch (SemanticError err) {
|
|
;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
// #@@}
|
|
|
|
private void checkVariable(DefinedVariable var) {
|
|
if (var.hasInitializer()) {
|
|
try {
|
|
check(var.initializer());
|
|
}
|
|
catch (SemanticError err) {
|
|
;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Assignment Expressions
|
|
//
|
|
|
|
public Void visit(AssignNode node) {
|
|
super.visit(node);
|
|
checkAssignment(node);
|
|
return null;
|
|
}
|
|
|
|
public Void visit(OpAssignNode node) {
|
|
super.visit(node);
|
|
checkAssignment(node);
|
|
return null;
|
|
}
|
|
|
|
private void checkAssignment(AbstractAssignNode node) {
|
|
if (! node.lhs().isAssignable()) {
|
|
semanticError(node.location(), "invalid lhs expression");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Expressions
|
|
//
|
|
|
|
public Void visit(PrefixOpNode node) {
|
|
super.visit(node);
|
|
if (! node.expr().isAssignable()) {
|
|
semanticError(node.expr().location(),
|
|
"cannot increment/decrement");
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public Void visit(SuffixOpNode node) {
|
|
super.visit(node);
|
|
if (! node.expr().isAssignable()) {
|
|
semanticError(node.expr().location(),
|
|
"cannot increment/decrement");
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public Void visit(FuncallNode node) {
|
|
super.visit(node);
|
|
if (! node.expr().isCallable()) {
|
|
semanticError(node.location(),
|
|
"calling object is not a function");
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public Void visit(ArefNode node) {
|
|
super.visit(node);
|
|
if (! node.expr().isPointer()) {
|
|
semanticError(node.location(),
|
|
"indexing non-array/pointer expression");
|
|
}
|
|
handleImplicitAddress(node);
|
|
return null;
|
|
}
|
|
|
|
public Void visit(MemberNode node) {
|
|
super.visit(node);
|
|
checkMemberRef(node.location(), node.expr().type(), node.member());
|
|
handleImplicitAddress(node);
|
|
return null;
|
|
}
|
|
|
|
public Void visit(PtrMemberNode node) {
|
|
super.visit(node);
|
|
if (! node.expr().isPointer()) {
|
|
undereferableError(node.location());
|
|
}
|
|
checkMemberRef(node.location(), node.dereferedType(), node.member());
|
|
handleImplicitAddress(node);
|
|
return null;
|
|
}
|
|
|
|
private void checkMemberRef(Location loc, Type t, String memb) {
|
|
if (! t.isCompositeType()) {
|
|
semanticError(loc, "accessing member `" + memb
|
|
+ "' for non-struct/union: " + t);
|
|
}
|
|
CompositeType type = t.getCompositeType();
|
|
if (! type.hasMember(memb)) {
|
|
semanticError(loc, type.toString()
|
|
+ " does not have member: " + memb);
|
|
}
|
|
}
|
|
|
|
// #@@range/DereferenceNode{
|
|
public Void visit(DereferenceNode node) {
|
|
super.visit(node);
|
|
if (! node.expr().isPointer()) {
|
|
undereferableError(node.location());
|
|
}
|
|
handleImplicitAddress(node);
|
|
return null;
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/AddressNode{
|
|
public Void visit(AddressNode node) {
|
|
super.visit(node);
|
|
if (! node.expr().isLvalue()) {
|
|
semanticError(node.location(), "invalid expression for &");
|
|
}
|
|
Type base = node.expr().type();
|
|
if (! node.expr().isLoadable()) {
|
|
// node.expr.type is already pointer.
|
|
node.setType(base);
|
|
}
|
|
else {
|
|
node.setType(typeTable.pointerTo(base));
|
|
}
|
|
return null;
|
|
}
|
|
// #@@}
|
|
|
|
public Void visit(VariableNode node) {
|
|
super.visit(node);
|
|
if (node.entity().isConstant()) {
|
|
checkConstant(node.entity().value());
|
|
}
|
|
handleImplicitAddress(node);
|
|
return null;
|
|
}
|
|
|
|
public Void visit(CastNode node) {
|
|
super.visit(node);
|
|
if (node.type().isArray()) {
|
|
semanticError(node.location(), "cast specifies array type");
|
|
}
|
|
return null;
|
|
}
|
|
|
|
//
|
|
// Utilities
|
|
//
|
|
|
|
private void handleImplicitAddress(LHSNode node) {
|
|
if (! node.isLoadable()) {
|
|
Type t = node.type();
|
|
if (t.isArray()) {
|
|
// int[4] ary; ary; should generate int*
|
|
node.setType(typeTable.pointerTo(t.baseType()));
|
|
}
|
|
else {
|
|
node.setType(typeTable.pointerTo(t));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void undereferableError(Location loc) {
|
|
semanticError(loc, "dereferencing non-pointer expression");
|
|
}
|
|
|
|
private void semanticError(Node n, String msg) {
|
|
semanticError(n.location(), msg);
|
|
}
|
|
|
|
private void semanticError(Location loc, String msg) {
|
|
errorHandler.error(loc, msg);
|
|
throw new SemanticError("invalid expr");
|
|
}
|
|
}
|