I am working on learning ANTLR to create a domain specific language. One of the requirements is to translate this DSL to C. I was able to get a basic grammar that recognizes DSL, however I am having problems translating this to C. Basically, my problem is trying to translate the DSL if statement to the C if statement . I tried using print instructions in grammar, to no avail (I use C #).
Here is the grammar I tested:
**ifTest.g** grammar ifTest; options { backtrack=true; output=AST; language=CSharp2; } prog : lambda | statements EOF; lambda : ; statements : statement+; statement : logical | assignment | NEWLINE; logical : IF a=logical_Expr THEN b=statements { System.Console.Write("\tif (" + $a.text + ")\n\t{\n\t" + "\t" + $b.text + "\n\n\t}"); } ( ELSE c=statements { System.Console.Write("\n\telse {\n\t\t\t" + $c.text + "\n\t}"); } )? ENDIF { System.Console.Write("\n}"); } ; logical_Expr : expr ; expr : (simple_Expr) (op expr)* ; simple_Expr : MINUS expr | identifier | number ; identifier : parameter | VARIABLE ; parameter : norm_parameter ; norm_parameter : spec_label | reserved_parm ; spec_label : LABEL ; reserved_parm : RES_PARM ; op : PLUS | MINUS | MULT | DIV | EQUALS | GT | LT | GE | LE ; number : INT | FLOAT | HEX ; assignment : identifier GETS expr ; WS : (' '|'\t')+ {$channel=HIDDEN;}; COMMENT : '/*' (options {greedy=false;}:.)* '*/' {$channel=HIDDEN;} ; LINECOMMENT : '#' ~('\n'|'\r')* NEWLINE {$channel=HIDDEN;} ; NEWLINE : '\r'?'\n' {$channel=HIDDEN;}; IF : IF; THEN : THEN; ELSE : ELSE; ENDIF : ENDIF; PLUS : '+'; MINUS : '-'; MULT : '*'; DIV : '/'; EQUALS : '='; GT : '>'; LT : '<'; GE : '>='; LE : '<='; ULINE : '_'; DOT : '.'; GETS : ':='; LABEL : (LETTER|ULINE)(LETTER|DIGIT|ULINE)*; INT : '-'?DIGIT+; FLOAT : '-'? DIGIT* DOT DIGIT+; HEX : ('0x'|'0X')(HEXDIGIT)HEXDIGIT*; RES_PARM: DIGIT LABEL; VARIABLE: '\$' LABEL; fragment A:'A'|'a'; fragment B:'B'|'b'; fragment C:'C'|'c'; fragment D:'D'|'d'; fragment E:'E'|'e'; fragment F:'F'|'f'; fragment G:'G'|'g'; fragment H:'H'|'h'; fragment I:'I'|'i'; fragment J:'J'|'j'; fragment K:'K'|'k'; fragment L:'L'|'l'; fragment M:'M'|'m'; fragment N:'N'|'n'; fragment O:'O'|'o'; fragment P:'P'|'p'; fragment Q:'Q'|'q'; fragment R:'R'|'r'; fragment S:'S'|'s'; fragment T:'T'|'t'; fragment U:'U'|'u'; fragment V:'V'|'v'; fragment W:'W'|'w'; fragment X:'X'|'x'; fragment Y:'Y'|'y'; fragment Z:'Z'|'z'; fragment DIGIT : '0'..'9'; fragment LETTER : A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z; fragment HEXDIGIT : '0..9'|'a..f'|'A'..'F';
When testing this class C #
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Antlr.Runtime; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string inputString = "if $variable1 = 0 then\n if $variable2 > 250 then\n $variable3 := 0\n endif\n endif"; Console.WriteLine("Here is the input string:\n " + inputString + "\n"); ANTLRStringStream input = new ANTLRStringStream(inputString); ifTestLexer lexer = new ifTestLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); ifTestParser parser = new ifTestParser(tokens); parser.prog(); Console.Read(); } } }
The solution is not quite as I imagined.
**Output** if ($variable2 > 250) { $variable3 := 0 } } if ($variable1 = 0) { if $variable2 > 250 then $variable3 := 0 endif } }
The problem is that the second if statement prints twice, but not in the order I was hoping. I suppose this is because I'm just trying to emit a block of statements in print operations, but I'm not quite sure how to do this to work correctly. Am I reading on a StringTemplate or creating an AST and using the Tree Walker to walk it, but still, to fix the above conclusion, to see something like this?
if ($variable1 = 0) { if ($variable2 > 250) { $variable3 := 0 } }
Any help in which direction I should take would be greatly appreciated. Would it be better if I jumped into a StringTemplate, or is there a way to do this using the base action code? If I left any information, please feel free to ask.
source share