mirror of https://github.com/aamine/cbc
* net/loveruby/cflat/compiler/TypeChecker.java: fork DereferenceChecker, to reduce catch(SemanticError).
* net/loveruby/cflat/compiler/DereferenceChecker.java: new class. * net/loveruby/cflat/ast/ExprNode.java (isAssignable, isDereferable): catch SemanticError which may occuer on type.isXXXX. * net/loveruby/cflat/compiler/Visitor.java: refactoring: rename method: #resolve -> #visitNode. * net/loveruby/cflat/compiler/Visitor.java: refactoring: rename method: #resolveNodeList -> #visitNodeList. * net/loveruby/cflat/compiler/JumpResolver.java: ditto. * net/loveruby/cflat/compiler/LocalReferenceResolver.java: ditto. * net/loveruby/cflat/compiler/TypeResolver.java: ditto. * net/loveruby/cflat/compiler/TypeChecker.java: ditto. * net/loveruby/cflat/compiler/Compiler.java: parse command line options more precisely. * net/loveruby/cflat/compiler/Compiler.java: new option --compile. * net/loveruby/cflat/compiler/Compiler.java: new option --dump-reference. * net/loveruby/cflat/compiler/Compiler.java: new option --dump-semantic. * net/loveruby/cflat/ast/VariableNode.java (dump): show resolved or not. * net/loveruby/cflat/ast/TypeNode.java (dump): ditto. * net/loveruby/cflat/ast/Dumper.java (printMember): ditto. git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@3819 1b9489fe-b721-0410-924e-b54b9192deb8
This commit is contained in:
parent
a88b9a2bca
commit
fd5caed6fc
43
ChangeLog
43
ChangeLog
|
@ -1,3 +1,46 @@
|
|||
Sun Jan 13 04:48:28 2008 Minero Aoki <aamine@loveruby.net>
|
||||
|
||||
* net/loveruby/cflat/compiler/TypeChecker.java: fork
|
||||
DereferenceChecker, to reduce catch(SemanticError).
|
||||
|
||||
* net/loveruby/cflat/compiler/DereferenceChecker.java: new class.
|
||||
|
||||
* net/loveruby/cflat/ast/ExprNode.java (isAssignable,
|
||||
isDereferable): catch SemanticError which may occuer on
|
||||
type.isXXXX.
|
||||
|
||||
* net/loveruby/cflat/compiler/Visitor.java: refactoring: rename
|
||||
method: #resolve -> #visitNode.
|
||||
|
||||
* net/loveruby/cflat/compiler/Visitor.java: refactoring: rename
|
||||
method: #resolveNodeList -> #visitNodeList.
|
||||
|
||||
* net/loveruby/cflat/compiler/JumpResolver.java: ditto.
|
||||
|
||||
* net/loveruby/cflat/compiler/LocalReferenceResolver.java: ditto.
|
||||
|
||||
* net/loveruby/cflat/compiler/TypeResolver.java: ditto.
|
||||
|
||||
* net/loveruby/cflat/compiler/TypeChecker.java: ditto.
|
||||
|
||||
* net/loveruby/cflat/compiler/Compiler.java: parse command line
|
||||
options more precisely.
|
||||
|
||||
* net/loveruby/cflat/compiler/Compiler.java: new option --compile.
|
||||
|
||||
* net/loveruby/cflat/compiler/Compiler.java: new option
|
||||
--dump-reference.
|
||||
|
||||
* net/loveruby/cflat/compiler/Compiler.java: new option
|
||||
--dump-semantic.
|
||||
|
||||
* net/loveruby/cflat/ast/VariableNode.java (dump): show resolved
|
||||
or not.
|
||||
|
||||
* net/loveruby/cflat/ast/TypeNode.java (dump): ditto.
|
||||
|
||||
* net/loveruby/cflat/ast/Dumper.java (printMember): ditto.
|
||||
|
||||
Sun Jan 13 04:47:12 2008 Minero Aoki <aamine@loveruby.net>
|
||||
|
||||
* net/loveruby/cflat/type/Type.java: make #isCompatible and
|
||||
|
|
6
ToDo
6
ToDo
|
@ -181,8 +181,10 @@
|
|||
- --dump-tokens
|
||||
- --dump-ast
|
||||
- print node location in error message
|
||||
* parse command line option more precisely
|
||||
* --dump-semantic
|
||||
- parse command line option more precisely
|
||||
- --dump-reference
|
||||
- --dump-semantic
|
||||
* add standard load path
|
||||
* generate IR
|
||||
* --dump-ir
|
||||
* control flow graph
|
||||
|
|
|
@ -58,8 +58,13 @@ public class Dumper {
|
|||
printPair(name, (t == null ? "null" : t.toString()));
|
||||
}
|
||||
|
||||
public void printMember(String name, String str, boolean isResolved) {
|
||||
printPair(name, TextUtils.escapeString(str)
|
||||
+ (isResolved ? " (resolved)" : ""));
|
||||
}
|
||||
|
||||
public void printMember(String name, String str) {
|
||||
printPair(name, TextUtils.escapeString(str));
|
||||
printMember(name, str, false);
|
||||
}
|
||||
|
||||
protected void printPair(String name, String value) {
|
||||
|
@ -69,7 +74,8 @@ public class Dumper {
|
|||
|
||||
public void printMember(String name, TypeNode n) {
|
||||
printIndent();
|
||||
stream.println(name + ": " + n.typeRef());
|
||||
stream.println(name + ": " + n.typeRef()
|
||||
+ (n.isResolved() ? " (resolved)" : ""));
|
||||
}
|
||||
|
||||
public void printMember(String name, Node n) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package net.loveruby.cflat.ast;
|
||||
import net.loveruby.cflat.type.Type;
|
||||
import net.loveruby.cflat.asm.*;
|
||||
import net.loveruby.cflat.exception.*;
|
||||
|
||||
abstract public class ExprNode extends Node {
|
||||
public ExprNode() {
|
||||
|
@ -10,11 +11,21 @@ abstract public class ExprNode extends Node {
|
|||
abstract public Type type();
|
||||
|
||||
public boolean isCallable() {
|
||||
return type().isCallable();
|
||||
try {
|
||||
return type().isCallable();
|
||||
}
|
||||
catch (SemanticError err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDereferable() {
|
||||
return type().isDereferable();
|
||||
try {
|
||||
return type().isDereferable();
|
||||
}
|
||||
catch (SemanticError err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConstant() {
|
||||
|
|
|
@ -15,10 +15,6 @@ public class TypeNode extends Node {
|
|||
this.type = type;
|
||||
}
|
||||
|
||||
public void resolve(TypeTable tbl) {
|
||||
// FIXME
|
||||
}
|
||||
|
||||
public TypeRef typeRef() {
|
||||
return typeRef;
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@ public class VariableNode extends ExprNode {
|
|||
return name;
|
||||
}
|
||||
|
||||
public void setEntity(Entity ent) {
|
||||
entity = ent;
|
||||
public boolean isResolved() {
|
||||
return (entity != null);
|
||||
}
|
||||
|
||||
public Entity entity() {
|
||||
|
@ -28,6 +28,10 @@ public class VariableNode extends ExprNode {
|
|||
return entity;
|
||||
}
|
||||
|
||||
public void setEntity(Entity ent) {
|
||||
entity = ent;
|
||||
}
|
||||
|
||||
public Type type() {
|
||||
return entity().type();
|
||||
}
|
||||
|
@ -53,7 +57,7 @@ public class VariableNode extends ExprNode {
|
|||
}
|
||||
|
||||
protected void _dump(Dumper d) {
|
||||
d.printMember("name", name);
|
||||
d.printMember("name", name, isResolved());
|
||||
}
|
||||
|
||||
public void accept(ASTVisitor visitor) {
|
||||
|
|
|
@ -29,36 +29,72 @@ public class Compiler {
|
|||
errorHandler = h;
|
||||
}
|
||||
|
||||
public void commandMain(String[] args) {
|
||||
public void commandMain(String[] origArgs) {
|
||||
// parse options
|
||||
String mode = null;
|
||||
List args = listFromArray(origArgs);
|
||||
ListIterator it = args.listIterator();
|
||||
while (it.hasNext()) {
|
||||
String arg = (String)it.next();
|
||||
if (arg.startsWith("-")) {
|
||||
if (arg.equals("--compile")
|
||||
|| arg.equals("--check-syntax")
|
||||
|| arg.equals("--dump-tokens")
|
||||
|| arg.equals("--dump-ast")
|
||||
|| arg.equals("--dump-reference")
|
||||
|| arg.equals("--dump-semantic")) {
|
||||
if (mode != null) {
|
||||
errorExit(mode + " option and " +
|
||||
arg + " option is exclusive");
|
||||
}
|
||||
mode = arg;
|
||||
it.remove();
|
||||
}
|
||||
else if (arg.equals("--help")) {
|
||||
printUsage(System.out);
|
||||
System.exit(0);
|
||||
}
|
||||
else {
|
||||
System.err.println("unknown option: " + arg);
|
||||
printUsage(System.err);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mode == null) {
|
||||
mode = "--compile";
|
||||
}
|
||||
if (args.size() == 0) errorExit("no input file");
|
||||
if (args.size() > 1) errorExit("too many input files");
|
||||
String inputFile = (String)args.get(0);
|
||||
|
||||
// execute
|
||||
try {
|
||||
if (args.length == 0) errorExit("no argument given");
|
||||
if (args[0].equals("--dump-tokens")) {
|
||||
if (args.length != 2) {
|
||||
errorExit("no file input or too many files");
|
||||
}
|
||||
dumpTokensFromFile(args[1]);
|
||||
if (mode.equals("--compile")) {
|
||||
compileFile(inputFile);
|
||||
}
|
||||
else if (args[0].equals("--dump-ast")) {
|
||||
if (args.length != 2) {
|
||||
errorExit("no file input or too many files");
|
||||
}
|
||||
dumpASTFromFile(args[1]);
|
||||
}
|
||||
else if (args[0].equals("--check-syntax")) {
|
||||
if (args.length != 2) {
|
||||
errorExit("no file input or too many files");
|
||||
}
|
||||
if (isValidSyntax(args[1])) {
|
||||
else if (mode.equals("--check-syntax")) {
|
||||
if (isValidSyntax(inputFile)) {
|
||||
System.out.println("Syntax OK");
|
||||
System.exit(0);
|
||||
} else {
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
else if (mode.equals("--dump-tokens")) {
|
||||
dumpTokensFromFile(inputFile);
|
||||
}
|
||||
else if (mode.equals("--dump-ast")) {
|
||||
dumpASTFromFile(inputFile);
|
||||
}
|
||||
else if (mode.equals("--dump-reference")) {
|
||||
dumpReferenceFromFile(inputFile);
|
||||
}
|
||||
else if (mode.equals("--dump-semantic")) {
|
||||
dumpSemanticFromFile(inputFile);
|
||||
}
|
||||
else {
|
||||
if (args.length != 1)
|
||||
errorExit("no file input or too many files");
|
||||
compileFile(args[0]);
|
||||
throw new Error("unknown mode: " + mode);
|
||||
}
|
||||
}
|
||||
catch (CompileException ex) {
|
||||
|
@ -67,6 +103,24 @@ public class Compiler {
|
|||
}
|
||||
}
|
||||
|
||||
protected void printUsage(PrintStream out) {
|
||||
// --dump-reference is hidden option
|
||||
out.println("Usage: cbc [option] file");
|
||||
out.println(" --check-syntax Syntax check only.");
|
||||
out.println(" --dump-tokens Parses source file and dumps tokens.");
|
||||
out.println(" --dump-ast Parses source file and dumps AST.");
|
||||
out.println(" --dump-semantic Check semantics and dumps AST.");
|
||||
out.println(" --help Prints this message and quit.");
|
||||
}
|
||||
|
||||
private List listFromArray(Object[] a) {
|
||||
List list = new ArrayList();
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
list.add(a[i]);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private void errorExit(String msg) {
|
||||
errorHandler.error(msg);
|
||||
System.exit(1);
|
||||
|
@ -111,9 +165,27 @@ public class Compiler {
|
|||
parseFile(path).dump();
|
||||
}
|
||||
|
||||
public void dumpReferenceFromFile(String path) throws CompileException {
|
||||
AST ast = parseFile(path);
|
||||
TypeTable typeTable = defaultTypeTable();
|
||||
JumpResolver.resolve(ast, errorHandler);
|
||||
LocalReferenceResolver.resolve(ast, errorHandler);
|
||||
TypeResolver.resolve(ast, typeTable, errorHandler);
|
||||
typeTable.semanticCheck(errorHandler);
|
||||
DereferenceChecker.check(ast, errorHandler);
|
||||
ast.dump();
|
||||
}
|
||||
|
||||
public void dumpSemanticFromFile(String path) throws CompileException {
|
||||
AST ast = parseFile(path);
|
||||
TypeTable typeTable = defaultTypeTable();
|
||||
semanticAnalysis(ast, typeTable);
|
||||
ast.dump();
|
||||
}
|
||||
|
||||
public void compileFile(String path) throws CompileException {
|
||||
AST ast = parseFile(path);
|
||||
TypeTable typeTable = TypeTable.ilp32();
|
||||
TypeTable typeTable = defaultTypeTable();
|
||||
semanticAnalysis(ast, typeTable);
|
||||
String asm = CodeGenerator.generate(ast, typeTable, errorHandler);
|
||||
writeFile(asmFileName(path), asm);
|
||||
|
@ -126,9 +198,14 @@ public class Compiler {
|
|||
LocalReferenceResolver.resolve(ast, errorHandler);
|
||||
TypeResolver.resolve(ast, typeTable, errorHandler);
|
||||
typeTable.semanticCheck(errorHandler);
|
||||
DereferenceChecker.check(ast, errorHandler);
|
||||
TypeChecker.check(ast, typeTable, errorHandler);
|
||||
}
|
||||
|
||||
private TypeTable defaultTypeTable() {
|
||||
return TypeTable.ilp32();
|
||||
}
|
||||
|
||||
public AST parseFile(String path) throws CompileException {
|
||||
return Parser.parseFile(new File(path), loader, errorHandler);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
package net.loveruby.cflat.compiler;
|
||||
import net.loveruby.cflat.ast.*;
|
||||
import net.loveruby.cflat.type.*;
|
||||
import net.loveruby.cflat.exception.*;
|
||||
import java.util.*;
|
||||
|
||||
class DereferenceChecker extends Visitor {
|
||||
static public void check(AST ast, ErrorHandler h)
|
||||
throws SemanticException {
|
||||
new DereferenceChecker(h).visit(ast);
|
||||
}
|
||||
|
||||
protected ErrorHandler errorHandler;
|
||||
|
||||
public DereferenceChecker(ErrorHandler h) {
|
||||
this.errorHandler = h;
|
||||
}
|
||||
|
||||
protected void check(Node node) {
|
||||
visitNode(node);
|
||||
}
|
||||
|
||||
public void visit(AST ast) throws SemanticException {
|
||||
Iterator vars = ast.variables();
|
||||
while (vars.hasNext()) {
|
||||
DefinedVariable var = (DefinedVariable)vars.next();
|
||||
checkVariable(var);
|
||||
}
|
||||
Iterator funcs = ast.functions();
|
||||
while (funcs.hasNext()) {
|
||||
DefinedFunction f = (DefinedFunction)funcs.next();
|
||||
check(f.body());
|
||||
}
|
||||
if (errorHandler.errorOccured()) {
|
||||
throw new SemanticException("compile failed.");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Statements
|
||||
//
|
||||
|
||||
protected void checkVariable(DefinedVariable var) {
|
||||
if (var.hasInitializer()) {
|
||||
check(var.initializer());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Assignment Expressions
|
||||
//
|
||||
|
||||
public void visit(AssignNode node) {
|
||||
super.visit(node);
|
||||
checkAssignment(node);
|
||||
}
|
||||
|
||||
public void visit(OpAssignNode node) {
|
||||
super.visit(node);
|
||||
checkAssignment(node);
|
||||
// check as operator
|
||||
}
|
||||
|
||||
protected void checkAssignment(AbstractAssignNode node) {
|
||||
if (! node.lhs().isAssignable()) {
|
||||
error(node, "invalid lhs expression");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Expressions
|
||||
//
|
||||
|
||||
public void visit(FuncallNode node) {
|
||||
super.visit(node);
|
||||
if (! node.expr().isCallable()) {
|
||||
error(node, "calling object is not a function");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void visit(ArefNode node) {
|
||||
super.visit(node);
|
||||
if (! node.expr().isDereferable()) {
|
||||
error(node, "is not indexable: " + node.expr().type());
|
||||
return;
|
||||
}
|
||||
check(node.index());
|
||||
}
|
||||
|
||||
public void visit(MemberNode node) {
|
||||
super.visit(node);
|
||||
checkMemberRef(node, node.expr().type(), node.member());
|
||||
}
|
||||
|
||||
public void visit(PtrMemberNode node) {
|
||||
super.visit(node);
|
||||
if (! node.expr().isDereferable()) {
|
||||
undereferableError(node, node.expr().type());
|
||||
return;
|
||||
}
|
||||
checkMemberRef(node, node.dereferedType(), node.member());
|
||||
}
|
||||
|
||||
protected void checkMemberRef(Node node, Type t, String memb) {
|
||||
if (! t.isComplexType()) {
|
||||
error(node, "is not struct/union: " + t);
|
||||
return;
|
||||
}
|
||||
ComplexType type = t.getComplexType();
|
||||
if (! type.hasMember(memb)) {
|
||||
error(node, type.toString() + " does not have member " + memb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void visit(DereferenceNode node) {
|
||||
super.visit(node);
|
||||
if (! node.expr().isDereferable()) {
|
||||
undereferableError(node, node.expr().type());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void visit(AddressNode node) {
|
||||
super.visit(node);
|
||||
if (! node.expr().isAssignable()) {
|
||||
error(node, "invalid LHS expression for &");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Utilities
|
||||
//
|
||||
|
||||
protected void undereferableError(Node n, Type type) {
|
||||
error(n, "dereferencing non-pointer expression: " + type);
|
||||
}
|
||||
|
||||
protected void warn(Node n, String msg) {
|
||||
errorHandler.warn(n.location(), msg);
|
||||
}
|
||||
|
||||
protected void error(Node n, String msg) {
|
||||
errorHandler.error(n.location(), msg);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ import java.util.*;
|
|||
public class JumpResolver extends Visitor {
|
||||
static public void resolve(AST ast, ErrorHandler h)
|
||||
throws SemanticException {
|
||||
new JumpResolver(h).resolveAST(ast);
|
||||
new JumpResolver(h).resolve(ast);
|
||||
}
|
||||
|
||||
protected ErrorHandler errorHandler;
|
||||
|
@ -19,7 +19,7 @@ public class JumpResolver extends Visitor {
|
|||
errorHandler = h;
|
||||
}
|
||||
|
||||
public void resolveAST(AST ast) throws SemanticException {
|
||||
public void resolve(AST ast) throws SemanticException {
|
||||
breakTargetStack = new LinkedList();
|
||||
continueTargetStack = new LinkedList();
|
||||
Iterator funcs = ast.functions();
|
||||
|
@ -33,6 +33,10 @@ public class JumpResolver extends Visitor {
|
|||
}
|
||||
}
|
||||
|
||||
protected void resolve(Node n) {
|
||||
visitNode(n);
|
||||
}
|
||||
|
||||
private BreakableStmt currentBreakTarget()
|
||||
throws SemanticException {
|
||||
if (breakTargetStack.isEmpty()) {
|
||||
|
@ -52,7 +56,7 @@ public class JumpResolver extends Visitor {
|
|||
public void visit(SwitchNode node) {
|
||||
resolve(node.cond());
|
||||
breakTargetStack.add(node);
|
||||
resolveNodeList(node.cases());
|
||||
visitNodeList(node.cases());
|
||||
breakTargetStack.removeLast();
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import java.util.*;
|
|||
public class LocalReferenceResolver extends Visitor {
|
||||
static public void resolve(AST ast, ErrorHandler handler)
|
||||
throws SemanticException {
|
||||
new LocalReferenceResolver(handler).resolveAST(ast);
|
||||
new LocalReferenceResolver(handler).resolve(ast);
|
||||
}
|
||||
|
||||
protected ErrorHandler errorHandler;
|
||||
|
@ -18,7 +18,11 @@ public class LocalReferenceResolver extends Visitor {
|
|||
this.errorHandler = h;
|
||||
}
|
||||
|
||||
public void resolveAST(AST ast) throws SemanticException {
|
||||
protected void resolve(Node n) {
|
||||
visitNode(n);
|
||||
}
|
||||
|
||||
public void resolve(AST ast) throws SemanticException {
|
||||
toplevel = ast.scope();
|
||||
scopeStack = new LinkedList();
|
||||
scopeStack.add(toplevel);
|
||||
|
|
|
@ -19,7 +19,7 @@ class TypeChecker extends Visitor {
|
|||
}
|
||||
|
||||
protected void check(Node node) {
|
||||
resolve(node);
|
||||
visitNode(node);
|
||||
}
|
||||
|
||||
public void visit(AST ast) throws SemanticException {
|
||||
|
@ -70,12 +70,7 @@ class TypeChecker extends Visitor {
|
|||
Iterator stmts = node.stmts();
|
||||
while (stmts.hasNext()) {
|
||||
Node n = (Node)stmts.next();
|
||||
try {
|
||||
check(n);
|
||||
}
|
||||
catch (SemanticError err) {
|
||||
// ignore semantic errors
|
||||
}
|
||||
check(n);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,18 +80,13 @@ class TypeChecker extends Visitor {
|
|||
return;
|
||||
}
|
||||
if (var.hasInitializer()) {
|
||||
try {
|
||||
if (isInvalidLHSType(var.type())) {
|
||||
error(var, "invalid LHS type: " + var.type());
|
||||
return;
|
||||
}
|
||||
check(var.initializer());
|
||||
var.setInitializer(
|
||||
checkRHSType(var.initializer(), var.type()));
|
||||
}
|
||||
catch (SemanticError err) {
|
||||
// ignore semantic errors
|
||||
if (isInvalidLHSType(var.type())) {
|
||||
error(var, "invalid LHS type: " + var.type());
|
||||
return;
|
||||
}
|
||||
check(var.initializer());
|
||||
var.setInitializer(
|
||||
checkRHSType(var.initializer(), var.type()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,10 +164,6 @@ class TypeChecker extends Visitor {
|
|||
protected void checkAssignment(AbstractAssignNode node) {
|
||||
check(node.lhs());
|
||||
check(node.rhs());
|
||||
if (! node.lhs().isAssignable()) {
|
||||
error(node, "invalid lhs expression");
|
||||
return;
|
||||
}
|
||||
if (isInvalidLHSType(node.lhs().type())) {
|
||||
error(node, "invalid lhs type");
|
||||
return;
|
||||
|
@ -354,36 +340,31 @@ class TypeChecker extends Visitor {
|
|||
|
||||
// +, -, !, ~
|
||||
public void visit(UnaryOpNode node) {
|
||||
check(node.expr());
|
||||
super.visit(node);
|
||||
mustBeInteger(node.expr());
|
||||
}
|
||||
|
||||
// ++, --
|
||||
public void visit(PrefixOpNode node) {
|
||||
check(node.expr());
|
||||
super.visit(node);
|
||||
mustBeScalar(node.expr());
|
||||
}
|
||||
|
||||
// ++, --
|
||||
public void visit(SuffixOpNode node) {
|
||||
check(node.expr());
|
||||
super.visit(node);
|
||||
mustBeScalar(node.expr());
|
||||
}
|
||||
|
||||
/**
|
||||
* For EXPR(ARG), checks:
|
||||
*
|
||||
* * EXPR is callable (a pointer to a function).
|
||||
* * The number of argument matches function prototype.
|
||||
* * ARG matches function prototype.
|
||||
* * ARG is neither a struct nor an union.
|
||||
*/
|
||||
public void visit(FuncallNode node) {
|
||||
check(node.expr());
|
||||
if (! node.expr().isCallable()) {
|
||||
error(node, "calling object is not a function");
|
||||
return;
|
||||
}
|
||||
super.visit(node);
|
||||
FunctionType type = node.functionType();
|
||||
if (! type.acceptsArgc(node.numArgs())) {
|
||||
error(node, "wrong number of argments: " + node.numArgs());
|
||||
|
@ -407,65 +388,13 @@ class TypeChecker extends Visitor {
|
|||
node.replaceArgs(newArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the type of base expression of EXPR[IDX] is valid.
|
||||
* EXPR must be an array or a pointer. IDX must be an integer.
|
||||
*/
|
||||
public void visit(ArefNode node) {
|
||||
check(node.expr());
|
||||
if (! node.expr().isDereferable()) {
|
||||
error(node, "is not indexable: " + node.expr().type());
|
||||
return;
|
||||
}
|
||||
check(node.index());
|
||||
super.visit(node);
|
||||
mustBeInteger(node.index());
|
||||
}
|
||||
|
||||
public void visit(MemberNode node) {
|
||||
check(node.expr());
|
||||
checkMemberRef(node, node.expr().type(), node.member());
|
||||
}
|
||||
|
||||
public void visit(PtrMemberNode node) {
|
||||
check(node.expr());
|
||||
if (! node.expr().isDereferable()) {
|
||||
undereferableError(node, node.expr().type());
|
||||
return;
|
||||
}
|
||||
checkMemberRef(node, node.dereferedType(), node.member());
|
||||
}
|
||||
|
||||
protected void checkMemberRef(Node node, Type t, String memb) {
|
||||
if (! t.isComplexType()) {
|
||||
error(node, "is not struct/union: " + t);
|
||||
return;
|
||||
}
|
||||
ComplexType type = t.getComplexType();
|
||||
if (! type.hasMember(memb)) {
|
||||
error(node, type.toString() + " does not have member " + memb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void visit(DereferenceNode node) {
|
||||
check(node.expr());
|
||||
if (! node.expr().isDereferable()) {
|
||||
undereferableError(node, node.expr().type());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void visit(AddressNode node) {
|
||||
check(node.expr());
|
||||
Type t = typeTable.pointerTo(node.expr().type());
|
||||
node.setType(t);
|
||||
if (! node.expr().isAssignable()) {
|
||||
error(node, "invalid LHS expression for &");
|
||||
}
|
||||
}
|
||||
|
||||
public void visit(CastNode node) {
|
||||
check(node.expr());
|
||||
super.visit(node);
|
||||
if (! node.expr().type().isCastableTo(node.type())) {
|
||||
incompatibleTypeError(node, node.expr().type(), node.type());
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package net.loveruby.cflat.compiler;
|
||||
import net.loveruby.cflat.ast.*;
|
||||
import net.loveruby.cflat.type.*;
|
||||
import net.loveruby.cflat.exception.*;
|
||||
import java.util.*;
|
||||
|
||||
public class TypeResolver extends Visitor {
|
||||
|
@ -19,9 +20,9 @@ public class TypeResolver extends Visitor {
|
|||
|
||||
public void resolveProgram(AST ast) {
|
||||
defineTypes(ast.types());
|
||||
resolveNodeList(ast.types());
|
||||
resolveNodeList(ast.declarations());
|
||||
resolveNodeList(ast.entities());
|
||||
visitNodeList(ast.types());
|
||||
visitNodeList(ast.declarations());
|
||||
visitNodeList(ast.entities());
|
||||
}
|
||||
|
||||
private void defineTypes(Iterator deftypes) {
|
||||
|
@ -66,9 +67,7 @@ public class TypeResolver extends Visitor {
|
|||
|
||||
public void visit(DefinedVariable var) {
|
||||
bindType(var.typeNode());
|
||||
if (var.isInitialized()) {
|
||||
resolve(var.initializer());
|
||||
}
|
||||
super.visit(var); // resolve initializer
|
||||
}
|
||||
|
||||
public void visit(UndefinedVariable var) {
|
||||
|
@ -77,8 +76,8 @@ public class TypeResolver extends Visitor {
|
|||
|
||||
public void visit(DefinedFunction func) {
|
||||
resolveFunctionHeader(func);
|
||||
resolveLocalVariables(func);
|
||||
resolve(func.body());
|
||||
//resolveLocalVariables(func);
|
||||
visitNode(func.body());
|
||||
}
|
||||
|
||||
public void visit(UndefinedFunction func) {
|
||||
|
@ -101,6 +100,20 @@ public class TypeResolver extends Visitor {
|
|||
}
|
||||
}
|
||||
|
||||
public void visit(AddressNode node) {
|
||||
super.visit(node);
|
||||
// to avoid SemanticError which occurs when getting type of
|
||||
// expr which is not assignable.
|
||||
try {
|
||||
Type t = typeTable.pointerTo(node.expr().type());
|
||||
node.setType(t);
|
||||
}
|
||||
catch (SemanticError err) {
|
||||
Type t = typeTable.pointerTo(typeTable.voidType());
|
||||
node.setType(t);
|
||||
}
|
||||
}
|
||||
|
||||
public void visit(CastNode node) {
|
||||
bindType(node.typeNode());
|
||||
super.visit(node);
|
||||
|
|
|
@ -6,14 +6,14 @@ abstract public class Visitor implements ASTVisitor {
|
|||
public Visitor() {
|
||||
}
|
||||
|
||||
protected void resolve(Node node) {
|
||||
protected void visitNode(Node node) {
|
||||
node.accept(this);
|
||||
}
|
||||
|
||||
protected void resolveNodeList(Iterator ns) {
|
||||
protected void visitNodeList(Iterator ns) {
|
||||
while (ns.hasNext()) {
|
||||
Node n = (Node)ns.next();
|
||||
resolve(n);
|
||||
visitNode(n);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,9 @@ abstract public class Visitor implements ASTVisitor {
|
|||
//
|
||||
|
||||
public void visit(DefinedVariable var) {
|
||||
if (var.hasInitializer()) {
|
||||
visitNode(var.initializer());
|
||||
}
|
||||
}
|
||||
|
||||
public void visit(UndefinedVariable var) {
|
||||
|
@ -50,46 +53,44 @@ abstract public class Visitor implements ASTVisitor {
|
|||
Iterator vars = node.variables();
|
||||
while (vars.hasNext()) {
|
||||
DefinedVariable var = (DefinedVariable)vars.next();
|
||||
if (var.hasInitializer()) {
|
||||
resolve(var.initializer());
|
||||
}
|
||||
visit(var);
|
||||
}
|
||||
resolveNodeList(node.stmts());
|
||||
visitNodeList(node.stmts());
|
||||
}
|
||||
|
||||
public void visit(IfNode n) {
|
||||
resolve(n.cond());
|
||||
resolve(n.thenBody());
|
||||
visitNode(n.cond());
|
||||
visitNode(n.thenBody());
|
||||
if (n.elseBody() != null) {
|
||||
resolve(n.elseBody());
|
||||
visitNode(n.elseBody());
|
||||
}
|
||||
}
|
||||
|
||||
public void visit(SwitchNode n) {
|
||||
resolve(n.cond());
|
||||
resolveNodeList(n.cases());
|
||||
visitNode(n.cond());
|
||||
visitNodeList(n.cases());
|
||||
}
|
||||
|
||||
public void visit(CaseNode n) {
|
||||
resolveNodeList(n.values());
|
||||
resolve(n.body());
|
||||
visitNodeList(n.values());
|
||||
visitNode(n.body());
|
||||
}
|
||||
|
||||
public void visit(WhileNode n) {
|
||||
resolve(n.cond());
|
||||
resolve(n.body());
|
||||
visitNode(n.cond());
|
||||
visitNode(n.body());
|
||||
}
|
||||
|
||||
public void visit(DoWhileNode n) {
|
||||
resolve(n.body());
|
||||
resolve(n.cond());
|
||||
visitNode(n.body());
|
||||
visitNode(n.cond());
|
||||
}
|
||||
|
||||
public void visit(ForNode n) {
|
||||
resolve(n.init());
|
||||
resolve(n.cond());
|
||||
resolve(n.incr());
|
||||
resolve(n.body());
|
||||
visitNode(n.init());
|
||||
visitNode(n.cond());
|
||||
visitNode(n.incr());
|
||||
visitNode(n.body());
|
||||
}
|
||||
|
||||
public void visit(BreakNode n) {
|
||||
|
@ -102,12 +103,12 @@ abstract public class Visitor implements ASTVisitor {
|
|||
}
|
||||
|
||||
public void visit(LabelNode n) {
|
||||
resolve(n.stmt());
|
||||
visitNode(n.stmt());
|
||||
}
|
||||
|
||||
public void visit(ReturnNode n) {
|
||||
if (n.expr() != null) {
|
||||
resolve(n.expr());
|
||||
visitNode(n.expr());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,78 +117,78 @@ abstract public class Visitor implements ASTVisitor {
|
|||
//
|
||||
|
||||
public void visit(CondExprNode n) {
|
||||
resolve(n.cond());
|
||||
resolve(n.thenExpr());
|
||||
visitNode(n.cond());
|
||||
visitNode(n.thenExpr());
|
||||
if (n.elseExpr() != null) {
|
||||
resolve(n.elseExpr());
|
||||
visitNode(n.elseExpr());
|
||||
}
|
||||
}
|
||||
|
||||
public void visit(LogicalOrNode node) {
|
||||
resolve(node.left());
|
||||
resolve(node.right());
|
||||
visitNode(node.left());
|
||||
visitNode(node.right());
|
||||
}
|
||||
|
||||
public void visit(LogicalAndNode node) {
|
||||
resolve(node.left());
|
||||
resolve(node.right());
|
||||
visitNode(node.left());
|
||||
visitNode(node.right());
|
||||
}
|
||||
|
||||
public void visit(AssignNode n) {
|
||||
resolve(n.lhs());
|
||||
resolve(n.rhs());
|
||||
visitNode(n.lhs());
|
||||
visitNode(n.rhs());
|
||||
}
|
||||
|
||||
public void visit(OpAssignNode n) {
|
||||
resolve(n.lhs());
|
||||
resolve(n.rhs());
|
||||
visitNode(n.lhs());
|
||||
visitNode(n.rhs());
|
||||
}
|
||||
|
||||
public void visit(BinaryOpNode n) {
|
||||
resolve(n.left());
|
||||
resolve(n.right());
|
||||
visitNode(n.left());
|
||||
visitNode(n.right());
|
||||
}
|
||||
|
||||
public void visit(UnaryOpNode node) {
|
||||
resolve(node.expr());
|
||||
visitNode(node.expr());
|
||||
}
|
||||
|
||||
public void visit(PrefixOpNode node) {
|
||||
resolve(node.expr());
|
||||
visitNode(node.expr());
|
||||
}
|
||||
|
||||
public void visit(SuffixOpNode node) {
|
||||
resolve(node.expr());
|
||||
visitNode(node.expr());
|
||||
}
|
||||
|
||||
public void visit(FuncallNode node) {
|
||||
resolve(node.expr());
|
||||
resolveNodeList(node.arguments());
|
||||
visitNode(node.expr());
|
||||
visitNodeList(node.arguments());
|
||||
}
|
||||
|
||||
public void visit(ArefNode node) {
|
||||
resolve(node.expr());
|
||||
resolve(node.index());
|
||||
visitNode(node.expr());
|
||||
visitNode(node.index());
|
||||
}
|
||||
|
||||
public void visit(MemberNode node) {
|
||||
resolve(node.expr());
|
||||
visitNode(node.expr());
|
||||
}
|
||||
|
||||
public void visit(PtrMemberNode node) {
|
||||
resolve(node.expr());
|
||||
visitNode(node.expr());
|
||||
}
|
||||
|
||||
public void visit(DereferenceNode node) {
|
||||
resolve(node.expr());
|
||||
visitNode(node.expr());
|
||||
}
|
||||
|
||||
public void visit(AddressNode node) {
|
||||
resolve(node.expr());
|
||||
visitNode(node.expr());
|
||||
}
|
||||
|
||||
public void visit(CastNode node) {
|
||||
resolve(node.expr());
|
||||
visitNode(node.expr());
|
||||
}
|
||||
|
||||
public void visit(VariableNode node) {
|
||||
|
|
Loading…
Reference in New Issue