header { } options { language = "CSharp"; namespace = "Ob51.Parsing"; } /*************************** LEXICAL ANALISYS ***************************/ class Ob51Lexer extends Lexer; options { k = 2; caseSensitive = true; testLiterals = false; charVocabulary = '\u0001'..'\uFFFD'; } /* Extra tokens not defined by ANTLR lexer rules but used in syntax */ tokens { BOOLEAN; SHORTCHAR; CHAR; BYTE; SHORTINT; INTEGER; LONGINT; SHORTREAL; REAL; SET; MODULEID; } /* Extra code in the lexer class */ { interface IModuleIDChecker { bool IsModuleID(string id); } IModuleIDChecker ModuleIDChecker = null; bool IsModuleID(string id) { if (ModuleIDChecker != null) { return ModuleIDChecker.IsModuleID(id); } else { return false; } } } WS: ( '\t' | ' ' | '\r' | ('\n' | '\f' | '\u0085' | '\u2028' | '\u2029') { newline(); } )+ { $setType(Token.SKIP); }; protected COMMENTTEXT: ( options { greedy=true; } : ~('(' | '*' | '\n' | '\f' | '\u0085' | '\u2028' | '\u2029') | ('\n' | '\f' | '\u0085' | '\u2028' | '\u2029') { newline(); } | { LA(2) != ')' }? '*' | { LA(2) != '*' }? '(' )*; COMMENT: "(*" COMMENTTEXT (COMMENT COMMENTTEXT)* "*)" { $setType(Token.SKIP); }; protected DIGIT: '0'..'9'; protected HEXDIGIT: 'A'..'F' | DIGIT; protected LETTER: 'a'..'z' | 'A'..'Z'; // comment ID options { testLiterals = true; } : (LETTER | '_') (LETTER | DIGIT | '_')* { if (IsModuleID($getText)) $setType(MODULEID); }; protected INTEGER: (DIGIT (HEXDIGIT)* ('H' | 'L') ) => DIGIT (HEXDIGIT)* ('H' {$setToken(NumericToken.MakeHexInt($getText));} | 'L' {$setToken(NumericToken.MakeHexLong($getText));} ) | (DIGIT)+ {$setToken(NumericToken.MakeInt($getText));}; protected REAL: (DIGIT)+ '.' (DIGIT)* (SCALEFACTOR)?; protected SCALEFACTOR: 'E' ('+' | '-')(DIGIT)+; protected CHAR : DIGIT (HEXDIGIT)* 'X'; NUM_VALUE: ((DIGIT)+ '.') => REAL {$setToken(NumericToken.MakeReal($getText));} | ( (DIGIT) (HEXDIGIT)* 'X' ) => CHAR {$setToken(NumericToken.MakeChar($getText));} | INTEGER ; STRING: '"' (~'"')* '"' | '\'' (~'\'')* '\''; PUNCTUATION options { testLiterals = true; } : ';' | '.' | ':' | ',' | ":=" | '^' | '|' | '$' | '+' | '-' | '*' | '/' | '&' | '~' | '=' | '#' | '<' | '>' | "<=" | ">=" | ".." | '(' | ')' | '[' | ']' | '{' | '}'; /*************************** SYNTAX ANALISYS ***************************/ class Ob51Parser extends Parser; options { k = 2; buildAST = true; ASTLabelType = "Ob51.Parsing.NewAST"; } tokens { ConstDeclToken; CycleToken; DeclsSeqToken; EmptyToken; IfToken; ModuleToken; OperationToken; ProcDeclToken; StatsSeqToken; TypeDeclToken; VarDeclToken; //STAR; } /* Module heading and imports*/ module: { } "MODULE"^ ID ";"! (importList)? declsSeq ("BEGIN" statementsSeq)? ("CLOSE" statementsSeq)? "END"! ID "."! EOF!; importList: "IMPORT"! ( ( id1_:ID ":=" )? id2_:ID )+ ";" ; /* Declarations */ identDef: ID ("*" | "-")?; qualident: MODULEID "." ID | ID; declsSeq: /* vars: */( "CONST" ( constDecl ";"! )* | "TYPE"! ( typeDecl ";"! )* | "VAR"! ( varDecl ";"! )* )* /* procs: */ ( procDecl ";"! | forwardDecl ";"! )* { #declsSeq = #([DeclsSeqToken], #declsSeq); } ; constDecl!: identDef_ : identDef "="! constExpr_ : constExpr { #constDecl = #([ConstDeclToken], identDef_, constExpr_); } ; typeDecl!: identDef_ : identDef "="! type_ : type { #typeDecl = #([TypeDeclToken], identDef_, type_); } ; varDecl!: identList_ : identList ":"! type_ : type {#varDecl = #([VarDeclToken], identList_, type_); } ; identList: identDef //("AT" constExpr ":" constExpr)? ( ","! identDef /*("AT" constExpr ":" constExpr)?*/ )*; procDecl: "PROCEDURE" (receiver)? IdentDef (formalParams)? methAttributes (";" declsSeq "BEGIN" statementsSeq)? "END" ID; forwardDecl: "PROCEDURE" "^" (receiver)? IdentDef (formalParams)? methAttributes; formalParams: "(" fpSection (";" fpSection)* ")" (":" type)?; fpSection: ("VAR" | "IN" | "OUT") ID ("," ID)* ":" type; receiver: "(" ("VAR" | "IN") ID ":" ID ")"; methAttributes: ("," "NEW")? ("," "ABSTRACT" | "EMPTY" | "EXTENSIBLE")? ("," "HANDLER" "OF" constExpr)?; type: qualident | "ARRAY" (constExpr (","! constExpr)*)? "OF"! type | ("ABSTRACT" | "EXTENSIBLE" | "LIMITED")? "RECORD" ("(" qualident ")")? fieldsDef (";" fieldsDef)? "END" | "POINTER" "TO" type | "PROCEDURE" (formalParams)?; fieldsDef: IdentList ":" type; /* Statements */ statementsSeq: statement (";"! statement )* { #statementsSeq = #([StatsSeqToken], #statementsSeq); } ; statement: designator (":="! expr | "("! exprsList ")"!) | "IF"^ expr "THEN"! statementsSeq ( "ELSIF"! expr "THEN"! statementsSeq )* ("ELSE"! statementsSeq )? //{ #statement = #([IfToken], #exprIf1_, #statSeqIf1_, #elsIf_, statSeqIf3_);} "END"! | "CASE" expr "OF"! caseVariant ("|" caseVariant)* ("ELSE" statementsSeq)? "END" | "WHILE"^ expr "DO"! statementsSeq "END"! //{ #statement = #(statement, [EmptyToken]); } //{ #statement = #([CycleToken], #exprWhile_, #statSeqWhile_, [EmptyToken]); } | "REPEAT"^ statementsSeq "UNTIL" expr //{ #statement = #([CycleToken], [EmptyToken], #exprRepeat_, #statSeqRepeat_); } | "FOR"^ ("VAR" ID ":" TYPE | ID) ":="! expr "TO"! expr ("BY"! constExpr)? "DO"! statementsSeq "END"! | "LOOP" statementsSeq "END"! | "WITH" (guard "DO" statementsSeq)? ("|" guard "DO" statementsSeq)* ("ELSE" statementsSeq)? "END" | "EXIT" | "RETURN" expr ; caseVariant: caseLabel ("," caseLabel)* ":" statementsSeq; caseLabel: constExpr (".." constExpr)?; /* Expressions */ constExpr: expr //need to check for being constant ; guard: qualident ":" qualident; expr! { string opName; }: expr1_ : simpleExpr { #expr = #expr1_; } ( rel_ : relation { opName = #rel_.getText(); } expr2_ : simpleExpr { #expr = #([OperationToken, opName], #expr, #expr2_); })?; relation: "=" //{ code = OpCodes.EQ; } | "#" //{ code = OpCodes.NEQ; } | "<" //{ code = OpCodes.LE; } | "<=" //{ code = OpCodes.LEQ; } | ">" //{ code = OpCodes.GE; } | ">=" //{ code = OpCodes.GEQ; } | "IN" //{ code = OpCodes.IN; } | "IS" //{ code = OpCodes.IS; } ; simpleExpr! { string opName = null; }: ("+" | head_ : "-" {opName = #head_.getText();})? term1_ : term { if (!String.IsNullOrEmpty(opName)) #simpleExpr = #([OperationToken, opName], #term1_); } ( add_ : addOp { opName = #add_.getText(); } term2_ : term { #simpleExpr = #([OperationToken, opName], #simpleExpr, #term2_); } )*; addOp: "+" | "-" | "OR" ; term: factor ( mulOp factor )*; mulOp: "*" //{ code = OpCodes.MUL; } | "/" //{ code = OpCodes.SLASH; } | "DIV" //{ code = OpCodes.DIV; } | "MOD" //{ code = OpCodes.MOD; } | "&" //{ code = OpCodes.AND; } ; factor: designator | NUM_VALUE | CHARACTER | STRING | "NIL" | set | "("! expr ")"! | "~" factor; set: "{"! (setElement (","! setElement)*)? "}"!; setElement: expr (".." expr)?; designator: qualident ( options { greedy = true; } : /* options needed to disambiguate designator and "(" */ "." ID | "[" exprsList "]" | "^" | "(" exprsList ")" /* qualident should be an alternative to exprList, but it conflicts */ )* ("$")?; exprsList: expr ("," expr)*;