header { using TokenStreamRewriteEngine = antlr.TokenStreamRewriteEngine; using TokenWithIndex = antlr.TokenWithIndex; } options { language = "CSharp"; } class TinyCParser extends Parser; options { //importVocab=TinyC; // use vocab generated by lexer } { TokenStreamRewriteEngine engine; public TinyCParser(TokenStreamRewriteEngine lexer) : this(lexer, 1) { engine = lexer; } } program : ( declaration )* EOF ; declaration : (globalVariable) => globalVariable | function ; declarator : id:ID | STAR id2:ID ; variable : type declarator SEMI ; /** Convert "int foo;" into "extern int foo;" */ globalVariable : {engine.insertBefore(LT(1), "extern ");} variable ; /** Convert "int foo() {...}" into "extern int foo();" */ function { int rcurly = 0; } : {engine.insertBefore(LT(1), "extern ");} type id:ID LPAREN (formalParameter (COMMA formalParameter)*)? RPAREN block[true] ; formalParameter : type declarator ; type: "int" | "char" | ID ; block[bool functionLevel] : a:LCURLY ( statement )* b:RCURLY { if ( functionLevel ) { int prevTokenIndex = ((TokenWithIndex) a).getIndex()-1; TokenWithIndex prevToken = engine.getToken(prevTokenIndex); if ( prevToken.Type == RPAREN ) { engine.replace(a, b, ";"); } else { engine.replace(prevToken, b, ";"); // replace whitespace too } } } ; statement : (variable)=>variable | expr SEMI | "if" LPAREN expr RPAREN statement ( "else" statement )? | "while" LPAREN expr RPAREN statement | block[false] ; expr: assignExpr ; assignExpr : aexpr (ASSIGN assignExpr)? ; aexpr : mexpr (PLUS mexpr)* ; mexpr : atom (STAR atom)* ; atom: ID | INT | CHAR_LITERAL | STRING_LITERAL ; class TinyCLexer extends Lexer; options { k = 2; charVocabulary = '\3'..'\377'; } WS : (' ' | '\t' | '\n' {newline();} | '\r')+ ; SL_COMMENT : "//" (~'\n')* '\n' { $setType(Token.SKIP); newline(); } ; ML_COMMENT : "/*" ( { LA(2)!='/' }? '*' | '\n' { newline(); } | ~('*'|'\n') )* "*/" { $setType(Token.SKIP); } ; LPAREN : '(' ; RPAREN : ')' ; LCURLY: '{' ; RCURLY: '}' ; STAR: '*' ; PLUS: '+' ; ASSIGN : '=' ; SEMI: ';' ; COMMA : ',' ; CHAR_LITERAL : '\'' (options {greedy=false;}:.)* '\'' ; STRING_LITERAL : '"' (options {greedy=false;}:.)* '"' ; protected DIGIT : '0'..'9' ; INT : (DIGIT)+ ; ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')* ;