//TypeCheckerLL import gi.*; /*\semantics*/import java.util.*; /*\off*/ class TypeCheckerLL extends LL1_Grammar { TypeCheckerLL() throws Exception { put("LITERAL", expression("[[:digit:]]+|true|false")); put("IDENTIFIER", expression("[[:alpha:]][[:alnum:]]*")); put("RELOP", expression("<|=|>|>=|<>|<=")); put("ADDOP", expression("\\+|-|or")); put("MULOP", expression("\\*|div|mod|and")); put("SPACE", expression("[[:space:]]+")); put("COMMENT", expression("\\{[^}]*\\}")); // /*\semantics*/semantic specification/*\off*/ //TypeCheckerLL.Program /*\semantics*/ final Map symbols = new HashMap(); Semantics declareProgram = new Semantics() { public void f(ParseTree t, int l) { symbols.put(t.child[l-1].value, "program"); } }; /*\off*/ put("Program", new Object[][]{ {"program", "IDENTIFIER", /*\semantics*/declareProgram, /*\off*/";", "Decls", "CompoundStmt", "."} }); //TypeCheckerLL.Decls put("Decls", new Object[][]{ {}, {"var", "DeclList"}, }); put("DeclList", new Object[][]{ {"Decl", "DeclList'"} }); put("DeclList'", new Object[][]{ {}, {"Decl", "DeclList'"}, }); //TypeCheckerLL.Decl /*\semantics*/ Semantics identity = new Semantics() { public void f(ParseTree t, int l) { t.value = t.child[l-1].value; } }; Semantics declareVariable= new Semantics() { public void f(ParseTree t, int l) throws Exception { String identifier = (String)t.child[l-2].value; String type = (String)t.child[l-1].value; String existing = (String)symbols.put(identifier, type); if (existing != null) throw new Exception( identifier + " already declared of type " + existing); t.value = type; } }; /*\off*/ put("Decl", new Object[][]{ {"IDENTIFIER", "IdList"/*\semantics*/, declareVariable/*\off*/} }); put("IdList", new Object[][]{ {":", "Type", /*\semantics*/identity, /*\off*/";"}, {",", "IDENTIFIER", "IdList"/*\semantics*/, declareVariable/*\off*/}, }); put("Type", new Object[][]{ {"integer"/*\semantics*/, identity/*\off*/}, {"boolean"/*\semantics*/, identity/*\off*/}, }); //TypeCheckerLL.CompountStmt put("CompoundStmt", new Object[][]{ {"begin", "StmtList", "end"} }); put("StmtList", new Object[][]{ {"Stmt", "StmtList'"} }); put("StmtList'", new Object[][]{ {}, {";", "Stmt", "StmtList'"}, }); //TypeCheckerLL.Stmt /*\semantics*/ Semantics checkAssignment = new Semantics() { public void f(ParseTree t, int l) throws Exception { String variable = (String)symbols.get(t.child[l-3].value); String expression = (String)t.child[l-1].value; if (variable == null) throw new Exception( "variable undeclared"); if (!expression.equals(variable)) throw new Exception( "assignment of incompatible types"); } }; Semantics checkCondition = new Semantics() { public void f(ParseTree t, int l) throws Exception { String type = (String)t.child[l-1].value; if (!type.equals("boolean")) throw new Exception( "condition expression must be boolean"); } }; /*\off*/ put("Stmt", new Object[][]{ {"Variable", ":=", "E"/*\semantics*/, checkAssignment/*\off*/}, {"if", "E", /*\semantics*/checkCondition, /*\off*/"then", "Stmt", "Stmt'"}, {"while", "E", /*\semantics*/checkCondition, /*\off*/"do", "Stmt"}, {"CompoundStmt"}, }); put("Stmt'", new Object[][]{ {}, {"else", "Stmt"}, }); put("Variable", new Object[][]{ {"IDENTIFIER"/*\semantics*/, identity/*\off*/} }); //TypeCheckerLL.E /*\semantics*/ Semantics inherit = new Semantics() { public void f(ParseTree t, int l) { t.child[l+1].value = t.child[l-1].value; } }; Semantics checkRelop = new Semantics() { public void f(ParseTree t, int l) throws Exception { String left = (String)t.value; String right = (String)t.child[l-1].value; if (!left.equals("integer") || !right.equals("integer")) throw new Exception( "relational operands must be integer"); t.value = "boolean"; } }; /*\off*/ put("E", new Object[][]{ {"A", /*\semantics*/inherit, /*\off*/"E'"/*\semantics*/, identity/*\off*/} }); put("E'", new Object[][]{ {}, {"RELOP", "A"/*\semantics*/, checkRelop/*\off*/}, }); //TypeCheckerLL.A /*\semantics*/ Semantics checkSign = new Semantics() { public void f(ParseTree t, int l) throws Exception { String sign = (String)t.child[l-2].value; String type = (String)t.child[l-1].value; if (sign.equals("or")) throw new Exception( "or is an invalid unary operator"); if (!type.equals("integer")) throw new Exception( "sign operand must be integer"); t.child[l+1].value = type; } }; Semantics checkAddop = new Semantics() { public void f(ParseTree t, int l) throws Exception { String left = (String)t.value; String addop = (String)t.child[l-2].value; String right = (String)t.child[l-1].value; if (addop.equals("or")) { if (!left.equals("boolean") || !right.equals("boolean")) throw new Exception( "or operands must be boolean"); } else { if (!left.equals("integer") || !right.equals("integer")) throw new Exception( "arithmetic operands must be integer"); } t.child[l+1].value = left; } }; /*\off*/ put("A", new Object[][]{ {"T", /*\semantics*/inherit, /*\off*/"A'"/*\semantics*/, identity/*\off*/}, {"Sign", "T", /*\semantics*/checkSign, /*\off*/"A'"/*\semantics*/, identity/*\off*/}, }); put("A'", new Object[][]{ {}, {"ADDOP", "T", /*\semantics*/checkAddop, /*\off*/"A'"/*\semantics*/, identity/*\off*/}, }); put("Sign", new Object[][]{ {"ADDOP"/*\semantics*/, identity/*\off*/} }); //TypeCheckerLL.T /*\semantics*/ Semantics checkMulop = new Semantics() { public void f(ParseTree t, int l) throws Exception { String left = (String)t.value; String mulop = (String)t.child[l-2].value; String right = (String)t.child[l-1].value; if (mulop.equals("and")) { if (!left.equals("boolean") || !right.equals("boolean")) throw new Exception( "and operands must be boolean"); } else { if (!left.equals("integer") || !right.equals("integer")) throw new Exception( "arithmetic operands must be integer"); } t.child[l+1].value = left; } }; /*\off*/ put("T", new Object[][]{ {"F", /*\semantics*/inherit, /*\off*/"T'"/*\semantics*/, identity/*\off*/} }); put("T'", new Object[][]{ {}, {"MULOP", "F", /*\semantics*/checkMulop, /*\off*/"T'"/*\semantics*/, identity/*\off*/}, }); //TypeCheckerLL.F /*\semantics*/ Semantics literalType = new Semantics() { public void f(ParseTree t, int l) { String literal = (String)t.child[l-1].value; t.value = (literal.equals("true") || literal.equals("false")) ? "boolean" : "integer"; } }; Semantics checkIdentifier = new Semantics() { public void f(ParseTree t, int l) throws Exception { t.value = symbols.get(t.child[l-1].value); if (t.value == null) throw new Exception( "identifier undeclared"); } }; Semantics checkNot = new Semantics() { public void f(ParseTree t, int l) throws Exception { String type = (String)t.child[l-1].value; if (!type.equals("boolean")) throw new Exception( "not operand must be boolean"); t.value = "boolean"; } }; /*\off*/ put("F", new Object[][]{ {"LITERAL"/*\semantics*/, literalType/*\off*/}, {"IDENTIFIER"/*\semantics*/, checkIdentifier/*\off*/}, {"(", "E", /*\semantics*/identity, /*\off*/")"}, {"not", "F"/*\semantics*/, checkNot/*\off*/}, }); //TypeCheckerLL debug = PARSE_TREE; } public static void main(String[] arguments) throws Exception { new TypeCheckerLL().interpret(arguments); } }