diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..ee586be --- /dev/null +++ b/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..7373f04 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + SELMA + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/antlr-3.3-complete.jar b/antlr-3.3-complete.jar new file mode 100644 index 0000000..d5a65ae Binary files /dev/null and b/antlr-3.3-complete.jar differ diff --git a/comm_dec_ass_print.SELMA b/comm_dec_ass_print.SELMA new file mode 100644 index 0000000..e0aadfd --- /dev/null +++ b/comm_dec_ass_print.SELMA @@ -0,0 +1,31 @@ + //Comment Testen +/* dit is +een comment +met meerdere +regels +*/ +begin //start program +2*3; + //compound expression +var i: integer; //single var int decaration + +5*8; +2*3*4; +5*i; +5>=6; +if true; then 5; fi; +if false; then 8; else 3; fi; +i := i := 5; //single assignment +print(i); //single print +var x,y: boolean; //double var bool declaration +var j: integer; //single var int declaration +j := i := j := 7; //double int assignment +print(i,j); //double print +const a: character = 'g'; //single const declaration +//const b: integer = 'l'; //single const declaration +const c: integer = 1; //single const declaration +j := i := 5*c; //double assignment & arith +j := i := 5;//true; +j := j := i; +print(i,j,c); //triple print +end. //end program diff --git a/g-files/Copy of SELMACode.stg b/g-files/Copy of SELMACode.stg new file mode 100644 index 0000000..0965736 --- /dev/null +++ b/g-files/Copy of SELMACode.stg @@ -0,0 +1,68 @@ +//SELMA string template + +group SELMA; + +program(instructions) ::= << +; TAM assembler code generated by SELMACompiler +; comments at 50 whitespaces + ; start of program + +HALT ; end of program +>> + +compound(instructions) ::= << + ; start compound + + ; end compound +>> + + +//Calculations +Expr(e1,op)::=<< + ; e1 for operation +CALL ; operation +>> + +biExpr(e1,e2,op)::=<< + ; e1 for operation + ; e2 for operation +CALL ; operation +>> + +//Declare +declareConst(id,val,type,addr)::=<< +LOADL ; declare var : = @ [SB] +>> + +declareVar(id,type,addr)::=<< +PUSH 1 ; declare var : @ [SB] +>> + +//Load +loadNum(val)::=<< +LOADL ; loadNum +>> + +loadVal(id,addr)::=<< +LOAD(1) [SB] ; loadVal from [SB] +>> + +//Assign +assign(id,type,addr,e1)::=<< + ; e1 right hand for assignment +STORE(1) [SB] ; assign e1 to : @ [SB] +>> + +//conditionals +if(ec1,ec2,ec3)::=<< + ; e1 right hand for assignment + ; e2 right hand for assignment + ; e3 right hand for assignment +hier hoort een if +>> + +while(ec1,ec2)::=<< +// ; e1 right hand for assignment +// ; e2 right hand for assignment +//hier hoort een while +>> diff --git a/g-files/SELMA.g b/g-files/SELMA.g new file mode 100644 index 0000000..e2c3ee2 --- /dev/null +++ b/g-files/SELMA.g @@ -0,0 +1,280 @@ +grammar SELMA; + + +options { + k=1; // LL(1) - do not use LL(*) + language=Java; // target language is Java (= default) + output=AST; // build an AST +} + +tokens { + COLON = ':'; + SEMICOLON = ';'; + LPAREN = '('; + RPAREN = ')'; + LCURLY = '{'; + RCURLY = '}'; + COMMA = ','; + EQ = '='; + APOSTROPHE = '\''; + + //arethemithic + NOT = '!'; + + MULT = '*'; + DIV = '/'; + MOD = '%'; + + PLUS = '+'; + MINUS = '-'; + + RELS = '<'; + RELSE = '<='; + RELGE = '>='; + RELG = '>'; + RELE = '=='; + RELNE = '<>'; + + AND = '&&'; + + OR = '||'; + + //expressions + BECOMES = ':='; + PRINT = 'print'; + READ = 'read'; + + //declaration + VAR = 'var'; + CONST = 'const'; + + //types + INT = 'integer'; + BOOL = 'boolean'; + CHAR = 'character'; + + // keywords + BEGIN = 'begin'; + END = 'end.'; + + IF = 'if'; + THEN = 'then'; + ELSE = 'else'; + FI = 'fi'; + + WHILE = 'while'; + DO = 'do'; + OD = 'od'; + + PROC = 'procedure'; + FUNC = 'function'; + + UMIN; + UPLUS; + + COMPOUND; + +} + + +@header { + package SELMA; +} + +@lexer::header { + package SELMA; +} + +// Parser rules + +program + : BEGIN compoundexpression END EOF + -> ^(BEGIN compoundexpression END) + ; + +compoundexpression + : cmp -> ^(COMPOUND cmp) + ; + +cmp + : ((declaration SEMICOLON!)* expression SEMICOLON!)+ + ; + +//declaration + +declaration +// : VAR^ identifier (COMMA! identifier)* COLON! type +// | CONST^ identifier (COMMA! identifier)* COLON! type EQ! unsignedConstant + : VAR identifier (COMMA identifier)* COLON type + -> ^(VAR type identifier)+ + | CONST identifier (COMMA identifier)* COLON type EQ unsignedConstant + -> ^(CONST type unsignedConstant identifier)+ + ; + +type + : INT + | BOOL + | CHAR + ; + +//expression +// note: +// - arithmetic can be "invisible" due to all the *-s that's why it is nested +// - assignment can be "invisible" due to the ? that's why it can also be only a identifier + +expression + : expr_assignment + ; + +expr_assignment + : expr_arithmetic (BECOMES^ expression)? + ; + +expr_arithmetic + : expr_al1 + ; + + expr_al1 //expression arithmetic level 1 + : expr_al2 (OR^ expr_al2)* + ; + + expr_al2 + : expr_al3 (AND^ expr_al3)* + ; + + expr_al3 + : expr_al4 ((RELS|RELSE|RELG|RELGE|RELE|RELNE)^ expr_al4)* + ; + + expr_al4 + : expr_al5 ((PLUS|MINUS)^ expr_al5)* + ; + + expr_al5 + : expr_al6 ((MULT|DIV|MOD)^ expr_al6)* + ; + + expr_al6 +// : (PLUS|MINUS|NOT)? expr_al7 + : PLUS expr_al7 + -> UPLUS expr_al7 + | MINUS expr_al7 + -> UMIN expr_al7 + | NOT expr_al7 + | expr_al7 + ; + + expr_al7 + : unsignedConstant + | identifier +// | expr_assignment //can be identifier + | expr_read + | expr_print + | expr_if + | expr_while + | expr_closedcompound + | expr_closed + ; + +expr_read + : READ^ LPAREN! identifier (COMMA! identifier)* RPAREN! + ; + +expr_print + : PRINT^ LPAREN! expression (COMMA! expression)* RPAREN! + ; + +expr_if + : IF^ compoundexpression THEN compoundexpression (ELSE compoundexpression)? FI! + ; + +expr_while + : WHILE^ compoundexpression DO compoundexpression OD + ; + +expr_closedcompound + : LCURLY compoundexpression RCURLY + ; + +expr_closed + : LPAREN! expression RPAREN! + ; + +unsignedConstant + : boolval + | charval + | intval + ; + +intval + : NUMBER + ; + +boolval + : BOOLEAN + ; + +charval + : CHARV + ; + +identifier + : ID + ; + +CHARV + : APOSTROPHE LETTER APOSTROPHE + ; + +BOOLEAN + : TRUE + | FALSE + ; + +ID + : LETTER (LETTER | DIGIT)* + ; + +NUMBER + : DIGIT+ + ; + +COMMENT + : '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;} + | '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;} + ; +WS + : ( ' ' + | '\t' + | '\r' + | '\n' + ) {$channel=HIDDEN;} + ; + +fragment DIGIT + : ('0'..'9') + ; + +fragment LOWER + : ('a'..'z') + ; + +fragment UPPER + : ('A'..'Z') + ; + +fragment LETTER + : LOWER + | UPPER + ; + +fragment TRUE + : 'true' + ; + +fragment FALSE + : 'false' + ; + + +//EOF diff --git a/g-files/SELMAChecker.g b/g-files/SELMAChecker.g new file mode 100644 index 0000000..8e4928c --- /dev/null +++ b/g-files/SELMAChecker.g @@ -0,0 +1,299 @@ +tree grammar SELMAChecker; + +options { + tokenVocab=SELMA; + ASTLabelType=SELMATree; + output=AST; +} + +@header { + package SELMA; + import SELMA.SELMATree.SR_Type; + import SELMA.SELMATree.SR_Kind; +} + +// Alter code generation so catch-clauses get replaced with this action. +@rulecatch { + catch (RecognitionException re) { + throw re; + } +} + +@members { + public SymbolTable st = new SymbolTable(); +} + +program + : ^(BEGIN {st.openScope();} compoundexpression {st.closeScope();} END) + ; + +compoundexpression //do not open and close scope here (IF/WHILE) + : ^(node=COMPOUND (declaration|expression)+) + { + SELMATree e1 = (SELMATree)node.getChild(node.getChildCount()-1); + if (e1.SR_type==SR_Type.VOID) { + $node.SR_type=SR_Type.VOID; + $node.SR_kind=null; + } else { + $node.SR_type=e1.SR_type; + $node.SR_kind=e1.SR_kind; + } + } + ; + +declaration + : ^(node=VAR type id=ID) + { + int type = node.getChild(0).getType(); + + switch (type){ + case INT: + st.enter($id,new CheckerEntry(SR_Type.INT,SR_Kind.VAR)); + break; + case BOOL: + st.enter($id,new CheckerEntry(SR_Type.BOOL,SR_Kind.VAR)); + break; + case CHAR: + st.enter($id,new CheckerEntry(SR_Type.CHAR,SR_Kind.VAR)); + break; + } + } + | ^(node=CONST type val id=ID) + { + int type = node.getChild(0).getType(); + int val = node.getChild(1).getType(); + + switch (type){ + case INT: + if (val!=NUMBER) throw new SELMAException(id,"Expecting int-value"); + st.enter($id,new CheckerEntry(SR_Type.INT,SR_Kind.CONST)); + break; + case BOOL: + if (val!=BOOLEAN) throw new SELMAException(id,"Expecting bool-value"); + st.enter($id,new CheckerEntry(SR_Type.BOOL,SR_Kind.CONST)); + break; + case CHAR: + if (val!=CHARV) throw new SELMAException(id,"Expecting char-value"); + st.enter($id,new CheckerEntry(SR_Type.CHAR,SR_Kind.CONST)); + break; + } + } + ; + +type + : INT + | BOOL + | CHAR + ; + +val + : NUMBER + | CHARV + | BOOLEAN + ; + +expression + : ^(node=(MULT|DIV|MOD|PLUS|MINUS) expression expression) + { + SELMATree e1 = (SELMATree)node.getChild(0); + SELMATree e2 = (SELMATree)node.getChild(1); + + if (e1.SR_type!=SR_Type.INT || e2.SR_type!=SR_Type.INT) + throw new SELMAException($node,"Wrong type must be int"); + $node.SR_type=SR_Type.INT; + + if (e1.SR_kind==SR_Kind.CONST && e2.SR_kind==SR_Kind.CONST) + $node.SR_kind=SR_Kind.CONST; + else + $node.SR_kind=SR_Kind.VAR; + } + + | ^(node=(RELS|RELSE|RELG|RELGE) expression expression) + { + SELMATree e1 = (SELMATree)node.getChild(0); + SELMATree e2 = (SELMATree)node.getChild(1); + + if (e1.SR_type!=SR_Type.INT || e2.SR_type!=SR_Type.INT) + throw new SELMAException($node,"Wrong type must be int"); + $node.SR_type=SR_Type.BOOL; + + if (e1.SR_kind==SR_Kind.CONST && e2.SR_kind==SR_Kind.CONST) + $node.SR_kind=SR_Kind.CONST; + else + $node.SR_kind=SR_Kind.VAR; + } + + | ^(node=(OR|AND) expression expression) + { + SELMATree e1 = (SELMATree)node.getChild(0); + SELMATree e2 = (SELMATree)node.getChild(1); + + if (e1.SR_type!=SR_Type.BOOL || e2.SR_type!=SR_Type.BOOL) + throw new SELMAException($node,"Wrong type must be bool"); + $node.SR_type=SR_Type.BOOL; + + if (e1.SR_kind==SR_Kind.CONST && e2.SR_kind==SR_Kind.CONST) + $node.SR_kind=SR_Kind.CONST; + else + $node.SR_kind=SR_Kind.VAR; + } + + | ^(node=(RELE|RELNE) expression expression) + { + SELMATree e1 = (SELMATree)node.getChild(0); + SELMATree e2 = (SELMATree)node.getChild(1); + + if (e1.SR_type!=e2.SR_type||e1.SR_type==SR_Type.VOID) + throw new SELMAException($node,"Types must match and can't be void"); + $node.SR_type=SR_Type.BOOL; + + if (e1.SR_kind==SR_Kind.CONST && e2.SR_kind==SR_Kind.CONST) + $node.SR_kind=SR_Kind.CONST; + else + $node.SR_kind=SR_Kind.VAR; + } + + | ^(node=(UPLUS|UMIN) expression) + { + SELMATree e1 = (SELMATree)node.getChild(0); + + if (e1.SR_type!=SR_Type.INT) + throw new SELMAException($node,"Wrong type must be int"); + $node.SR_type=SR_Type.INT; + + $node.SR_kind=e1.SR_kind; + } + + | ^(node=(NOT) expression) + { + SELMATree e1 = (SELMATree)node.getChild(0); + + if (e1.SR_type!=SR_Type.BOOL) + throw new SELMAException($node,"Wrong type must be bool"); + $node.SR_type=SR_Type.BOOL; + + $node.SR_kind=e1.SR_kind; + } + + | ^(node=IF {st.openScope();} compoundexpression + THEN {st.openScope();} compoundexpression {st.closeScope();} + (ELSE {st.openScope();} compoundexpression {st.closeScope();})? + {st.closeScope();}) + { + SELMATree e1 = (SELMATree)node.getChild(0); + SELMATree e2 = (SELMATree)node.getChild(2); + SELMATree e3 = (SELMATree)node.getChild(4); + + if (e1.SR_type!=SR_Type.BOOL) + throw new SELMAException(e1,"Expression must be boolean"); + + if (e3==null) { //no else + $node.SR_type=SR_Type.VOID; + $node.SR_kind=null; + } else { // there is a else + if (e2.SR_type==e3.SR_type) { + $node.SR_type=e3.SR_type; + if (e2.SR_kind==SR_Kind.CONST && e3.SR_kind==SR_Kind.CONST) + $node.SR_kind=SR_Kind.CONST; + else + $node.SR_kind=SR_Kind.VAR; + } else { + $node.SR_type=SR_Type.VOID; + $node.SR_kind=null; + } + } + } + + | ^(node=WHILE {st.openScope();}compoundexpression + DO {st.openScope();} compoundexpression {st.closeScope();} + OD{st.closeScope();}) + { + SELMATree e1 = (SELMATree)node.getChild(0); + SELMATree e2 = (SELMATree)node.getChild(2); + + if (e1.SR_type!=SR_Type.BOOL) + throw new SELMAException(e1,"Expression must be boolean"); + + $node.SR_type=SR_Type.VOID; + $node.SR_kind=null; + + } + + | ^(node=READ (id=ID + { + if (st.retrieve($id).kind!=SR_Kind.VAR) + throw new SELMAException($id,"Must be a variable"); + })+ + { + if ($node.getChildCount()==1){ + $node.SR_type=((SELMATree)node.getChild(0)).SR_type; + $node.SR_kind=SR_Kind.VAR; + } else { + $node.SR_type=SR_Type.VOID; + $node.SR_kind=null; + } + } + ) + + | ^(node=PRINT expression+ + { + for (int i=0; i<((SELMATree)node).getChildCount(); i++){ + if (((SELMATree)node.getChild(i)).SR_type==SR_Type.VOID) + throw new SELMAException($node,"Can not be of type void"); + } + if ($node.getChildCount()==1){ + $node.SR_type=((SELMATree)node.getChild(0)).SR_type; + $node.SR_kind=SR_Kind.VAR; + } else { + $node.SR_type=SR_Type.VOID; + $node.SR_kind=null; + } + }) + + | ^(node=BECOMES expression expression) + { + SELMATree e1 = (SELMATree)node.getChild(0); + SELMATree e2 = (SELMATree)node.getChild(1); + if (e1.getType()!=ID) + throw new SELMAException(e1,"Must be a identifier"); + + CheckerEntry ident = st.retrieve(e1); + + if (ident.kind!=SR_Kind.VAR) + throw new SELMAException(e1,"Must be a variable"); + if (ident.type!=e2.SR_type) + throw new SELMAException(e1,"Right side must be the same type "+ident.type+"/"+e2.SR_type); + + $node.SR_type=ident.type; + $node.SR_kind=SR_Kind.VAR; + } + + | LCURLY {st.openScope();} compoundexpression {st.closeScope();} RCURLY + + | node=NUMBER + { + $node.SR_type=SR_Type.INT; + $node.SR_kind=SR_Kind.CONST; + } + + | node=BOOLEAN + { + $node.SR_type=SR_Type.BOOL; + $node.SR_kind=SR_Kind.CONST; + } + + | node=LETTER + { + $node.SR_type=SR_Type.CHAR; + $node.SR_kind=SR_Kind.CONST; + } + + | node=ID + { + CheckerEntry entry = st.retrieve($node); + $node.SR_type=entry.type; + $node.SR_kind=entry.kind; + } + ; + + diff --git a/g-files/SELMACode.stg b/g-files/SELMACode.stg new file mode 100644 index 0000000..2c746f1 --- /dev/null +++ b/g-files/SELMACode.stg @@ -0,0 +1,73 @@ +//SELMA string template + +group SELMA; + +program(instructions) ::= << +; TAM assembler code generated by SELMACompiler +; comments at 50 whitespaces + ; start of program + +HALT + ; end of program +>> + +compound(instructions) ::= << + ; start compound + + ; end compound +>> + + +//Calculations +Expr(e1,op)::=<< + ; e1 for operation +CALL ; single operation +>> + +biExpr(e1,e2,op)::=<< + ; e1 for operation + ; e2 for operation +CALL ; binary operation +>> + +//Declare +declareConst(id,val,type,addr)::=<< + ; declare var : = @ [SB] +LOADL +>> + +declareVar(id,type,addr)::=<< + ; declare var : @ [SB] +PUSH 1 +>> + +//Load +loadNum(val)::=<< + ; loadNum +LOADL +>> + +loadVal(id,addr)::=<< + ; loadVal from [SB] +LOAD(1) [SB] +>> + +//Assign +assign(id,type,addr,e1)::=<< + ; e1 right hand for assignment +STORE(1) [SB] ; assign e1 to : @ [SB] +>> + +//conditionals +if(ec1,ec2,ec3)::=<< + ; e1 condition + ; e2 if true expression + ; e3 if false expression +hier hoort een if +>> + +while(ec1,ec2)::=<< + ; e1 while condition + ; e2 expression to evaluate +hier hoort een while +>> diff --git a/g-files/SELMACompiler.g b/g-files/SELMACompiler.g new file mode 100644 index 0000000..b922d8c --- /dev/null +++ b/g-files/SELMACompiler.g @@ -0,0 +1,147 @@ +tree grammar SELMACompiler; + +options { + language = Java; + output = template; + tokenVocab = SELMA; + ASTLabelType = SELMATree; +} + +@header { + package SELMA; + import SELMA.SELMATree.SR_Type; + import SELMA.SELMATree.SR_Kind; +} + +@rulecatch { + catch (RecognitionException re) { + throw re; + } +} + +@members { + public SymbolTable st = new SymbolTable(); +} + +program + : ^(BEGIN {st.openScope();} compoundexpression {st.closeScope();} END) + -> program( instructions={$compoundexpression.st} ) + ; + +compoundexpression + : ^(node=COMPOUND (s+=declaration | s+=expression)+) + -> compound(instructions={$s}) + ; + +declaration + : ^(node=VAR INT id=ID) + {st.enter($id,new CompilerEntry(SR_Type.INT,SR_Kind.VAR,st.nextAddr())); } + -> declareVar(id={$id.text},type={"INT"},addr={st.nextAddr()-1}) + + | ^(node=VAR BOOL id=ID) + {st.enter($id,new CompilerEntry(SR_Type.BOOL,SR_Kind.VAR,st.nextAddr())); } + -> declareVar(id={$id.text},type={"BOOL"},addr={st.nextAddr()-1}) + + | ^(node=VAR CHAR id=ID) + {st.enter($id,new CompilerEntry(SR_Type.CHAR,SR_Kind.VAR,st.nextAddr())); } + -> declareVar(id={$id.text},type={"CHAR"},addr={st.nextAddr()-1}) + + // store the const at a address? LOAD Or just copy LOADL? + | ^(node=CONST INT val=NUMBER (id=ID)+) + {st.enter($id,new CompilerEntry(SR_Type.INT,SR_Kind.CONST,st.nextAddr())); } + -> declareConst(id={$id.text},value={$val.text},type={"INT"},addr={st.nextAddr()-1}) + + | ^(node=CONST BOOL BOOLEAN (id=ID)+) + {st.enter($id,new CompilerEntry(SR_Type.BOOL,SR_Kind.CONST,st.nextAddr()-1)); } + -> declareConst(id={$id.text},value={($val.text.equals("true"))?"1":"0"},type={"BOOL"},addr={st.nextAddr()}) + + | ^(node=CONST CHAR CHARV (id=ID)+) + {st.enter($id,new CompilerEntry(SR_Type.CHAR,SR_Kind.CONST,st.nextAddr())); } + -> declareConst(id={$id.text},value={Character.getNumericValue($val.text.charAt(1))},type={"CHAR"},addr={st.nextAddr()-1}) + ; + +expression +//double arg expression + : ^(MULT e1=expression e2=expression) + -> biExpr(e1={$e1.st},e2={$e2.st},op={"mult"}) + + | ^(DIV e1=expression e2=expression) + -> biExpr(e1={$e1.st},e2={$e2.st},op={"div"}) + + | ^(MOD e1=expression e2=expression) + -> biExpr(e1={$e1.st},e2={$e2.st},op={"mod"}) + + | ^(PLUS e1=expression e2=expression) + -> biExpr(e1={$e1.st},e2={$e2.st},op={"add"}) + + | ^(MINUS e1=expression e2=expression) + -> biExpr(e1={$e1.st},e2={$e2.st},op={"sub"}) + + | ^(RELS e1=expression e2=expression) + -> biExpr(e1={$e1.st},e2={$e2.st},op={"lt"}) + + | ^(RELSE e1=expression e2=expression) + -> biExpr(e1={$e1.st},e2={$e2.st},op={"le"}) + + | ^(RELG e1=expression e2=expression) + -> biExpr(e1={$e1.st},e2={$e2.st},op={"gt"}) + + | ^(RELGE e1=expression e2=expression) + -> biExpr(e1={$e1.st},e2={$e2.st},op={"ge"}) + + | ^(OR e1=expression e2=expression) + -> biExpr(e1={$e1.st},e2={$e2.st},op={"or"}) + + | ^(AND e1=expression e2=expression) + -> biExpr(e1={$e1.st},e2={$e2.st},op={"and"}) + + | ^(RELE e1=expression e2=expression) + -> biExpr(e1={$e1.st},e2={$e2.st},op={"eq"}) + + | ^(RELNE e1=expression e2=expression) + -> biExpr(e1={$e1.st},e2={$e2.st},op={"neq"}) + +//single arg expression + | ^(UPLUS e1=expression) + {$st=$e1.st;} + + | ^(UMIN e1=expression) + -> Expr(e1={$e1.st},op={"neg"}) + + | ^(NOT e1=expression) + -> Expr(e1={$e1.st},op={"not"}) + +//CONDITIONAL + | ^(IF ec1=compoundexpression THEN ec2=compoundexpression (ELSE ec3=compoundexpression)?) + -> if(ec1={$ec1.st},ec2={$ec2.st},ec3={$ec3.st}) + | ^(WHILE ec1=compoundexpression DO ec2=compoundexpression OD) + -> while(ec1={$ec1.st},ec2={$ec2.st}) + +//IO + | ^(READ (id=ID)+) + + | ^(PRINT expression+) + +//ASSIGN +// | ^(BECOMES expression expression) + | ^(BECOMES node=ID e1=expression) + -> assign(id={$node.text},type={$node.type},addr={st.retrieve($node).addr},e1={$e1.st}) + +//closedcompound + | LCURLY {st.openScope();} compoundexpression {st.closeScope();} RCURLY + +//VALUES + | node=NUMBER + -> loadNum(val={$node.text}) + + | node=BOOLEAN + -> loadNum(val={($node.type==TRUE)?1:0}) + + | node=LETTER + -> loadNum(val={Character.getNumericValue($node.text.charAt(1))}) + + | node=ID + -> loadVal(id={$node.text}, addr={st.retrieve($node).addr}) + ; + + diff --git a/jasmin.jar b/jasmin.jar new file mode 100755 index 0000000..7897e7f Binary files /dev/null and b/jasmin.jar differ diff --git a/simple.SELMA b/simple.SELMA new file mode 100644 index 0000000..bf42fc8 --- /dev/null +++ b/simple.SELMA @@ -0,0 +1,20 @@ + //Comment Testen +/* dit is +een comment +met meerdere +regels +*/ +begin //start program +var i: integer; //single var int decaration +2*3; +i := 1; + +5*8; +2*3*4; +5*i; +5>=6; +while true; do 5; od; +if true; then 5; else 6; fi; +if false; then 7; fi; + +end. //end program diff --git a/src/SELMA/CheckerEntry.java b/src/SELMA/CheckerEntry.java new file mode 100644 index 0000000..cef8fee --- /dev/null +++ b/src/SELMA/CheckerEntry.java @@ -0,0 +1,60 @@ +package SELMA; + +import SELMA.SELMATree.SR_Kind; +import SELMA.SELMATree.SR_Type; + +public class CheckerEntry extends IdEntry { + public SR_Type type; + public SR_Kind kind; + + public CheckerEntry(SR_Type type, SR_Kind kind) { + super(); + this.type=type; + this.kind=kind; + } + public String toString() { + String s = ""; + s += " ["; + + s+=level; + + s+=","; + + if (type == null) + s+="NULL"; + else + switch (type){ + case BOOL: + s+="bool"; + break; + case INT: + s+="int"; + break; + case CHAR: + s+="char"; + break; + case VOID: + s+="void"; + break; + } + + s+=","; + + if (kind == null) + s+="NULL"; + else + switch (kind){ + case VAR: + s+="var"; + break; + case CONST: + s+="const"; + break; + } + + s+="]"; + + return s; + } + +} diff --git a/src/SELMA/CompilerEntry.java b/src/SELMA/CompilerEntry.java new file mode 100644 index 0000000..f84cf2f --- /dev/null +++ b/src/SELMA/CompilerEntry.java @@ -0,0 +1,13 @@ +package SELMA; + +import SELMA.SELMATree.SR_Kind; +import SELMA.SELMATree.SR_Type; + +public class CompilerEntry extends CheckerEntry { + public int addr; + public CompilerEntry(SR_Type type, SR_Kind kind, int addr) { + super(type, kind); + this.addr=addr; + } + +} diff --git a/src/SELMA/IdEntry.java b/src/SELMA/IdEntry.java new file mode 100644 index 0000000..f8defb9 --- /dev/null +++ b/src/SELMA/IdEntry.java @@ -0,0 +1,10 @@ +package SELMA; + +public class IdEntry { + public int level = -1; + public IdEntry(){ + } + public String toString() { + return " ["+level+"]"; + } +} diff --git a/src/SELMA/SELMA.java b/src/SELMA/SELMA.java new file mode 100644 index 0000000..6a84ab1 --- /dev/null +++ b/src/SELMA/SELMA.java @@ -0,0 +1,111 @@ +package SELMA; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; + +import org.antlr.runtime.*; // ANTLR runtime library +import org.antlr.runtime.tree.*; // For ANTLR's Tree classes +import org.antlr.stringtemplate.*; // For the DOTTreeGenerator + + + +public class SELMA { + private static boolean opt_ast = false, + opt_dot = false, + opt_no_checker = false, + opt_code_generator = false; + + public static void parseOptions(String[] args) { + for (int i=0; i0 ) { + buf.append(' '); + } + buf.append(t.toStringTree(level+1)); + } + if ( !isNil() ) { + buf.append(")"); + buf.append("\n"); + char[] c = new char[level]; + Arrays.fill(c, '\t'); + buf.append(c); + } + return buf.toString(); + } + + + public String toString() { + String s = super.toString(); + s += " ["; + + if (SR_type == null) + s+="NULL"; + else + switch (SR_type){ + case BOOL: + s+="bool"; + break; + case INT: + s+="int"; + break; + case CHAR: + s+="char"; + break; + case VOID: + s+="void"; + break; + } + + s+=","; + + if (SR_kind == null) + s+="NULL"; + else + switch (SR_kind){ + case VAR: + s+="var"; + break; + case CONST: + s+="const"; + break; + } + + s+="]"; + + return s; + } +} + diff --git a/src/SELMA/SELMATreeAdaptor.java b/src/SELMA/SELMATreeAdaptor.java new file mode 100644 index 0000000..17e439d --- /dev/null +++ b/src/SELMA/SELMATreeAdaptor.java @@ -0,0 +1,12 @@ +package SELMA; +import org.antlr.runtime.tree.*; +import org.antlr.runtime.Token; + +public class SELMATreeAdaptor extends CommonTreeAdaptor { + public Object create(Token t) { + return new SELMATree(t); + } + public Object dupNode (Object t) { + return new SELMATree((SELMATree)t); + } +} diff --git a/src/SELMA/SymbolTable.java b/src/SELMA/SymbolTable.java new file mode 100644 index 0000000..4a95c37 --- /dev/null +++ b/src/SELMA/SymbolTable.java @@ -0,0 +1,126 @@ +package SELMA; + +import java.util.*; + +import org.antlr.runtime.RecognitionException; +import org.antlr.runtime.tree.Tree; + +public class SymbolTable { + private int nextAddr = 0; + private int currentLevel; + private Map> entries; + + + public int nextAddr(){ + return nextAddr; + } + + /** + * Constructor. + * @ensure this.currentLevel() == -1 + */ + public SymbolTable() { + currentLevel = -1; + entries = new HashMap>(); + } + + /** + * Opens a new scope. + * @ensure this.currentLevel() == old.currentLevel()+1 + */ + public void openScope() { + currentLevel++; + } + + /** + * Closes the current scope. All identifiers in + * the current scope will be removed from the SymbolTable. + * @require old.currentLevel() > -1 + * @ensure this.currentLevel() == old.currentLevel()-1 + */ + public void closeScope() { + for (Map.Entry> entry: entries.entrySet()){ + Stack stack = entry.getValue(); + if ((stack != null) && (!stack.isEmpty()) && (stack.peek().level >= currentLevel)){ + stack.pop(); + nextAddr--; + } + } + currentLevel--; + } + + /** Returns the current scope level. */ + public int currentLevel() { + return currentLevel; + } + + /** + * Enters an id together with an entry into this SymbolTable using the + * current scope level. The entry's level is set to currentLevel(). + * @require String != null && String != "" && entry != null + * @ensure this.retrieve(id).getLevel() == currentLevel() + * @throws SymbolTableException when there is no valid current scope level, + * or when the id is already declared on the current level. + */ + public void enter(Tree tree, Entry entry) throws SymbolTableException { + String id = tree.getText(); + if (currentLevel < 0) { + throw new SymbolTableException(tree, "Not in a valid scope."); + } + Stack s = entries.get(id); + if (s==null) { + s = new Stack(); + entry.level=currentLevel; + s.push(entry); + entries.put(id, s); + nextAddr++; + } else if (s.isEmpty() || s.peek().level != currentLevel){ + entry.level=currentLevel; + s.push(entry); + nextAddr++; + } else { + throw new SymbolTableException(tree, "Entry "+id+" already exists in current scope."); + } + } + + + /** + * Get the Entry corresponding with id whose level is the highest. + * In other words, the method returns the Entry that is defined last. + * @return Entry of this id on the highest level + * null if this SymbolTable does not contain id + */ + public Entry retrieve(Tree tree) throws SymbolTableException{ + String id = tree.getText(); + Stack s = entries.get(id); + if (s==null||s.isEmpty()) + throw new SymbolTableException(tree, "Entry not found: "+id); + return s.peek(); + } + + public String toString(){ + String s = ""; + for (Map.Entry> entry: entries.entrySet()){ + Stack stack = entry.getValue(); + s+=entry.getKey(); + s+=stack.toString(); + } + return s; + } +} + +/** Exception class to signal problems with the SymbolTable */ +class SymbolTableException extends RecognitionException { + public static final long serialVersionUID = 24362462L; // for Serializable + private String msg; + public SymbolTableException(Tree tree, String msg) { + super(); + this.msg = tree.getText() + + " (" + tree.getLine() + + ":" + tree.getCharPositionInLine() + + ") " + msg; + } + public String getMessage() { + return msg; + } +} \ No newline at end of file