/* **********************************************
 * Duale Hochschule Baden-Württemberg Karlsruhe
 * Prof. Dr. Jörn Eisenbiegler
 * 
 * Vorlesung Übersetzerbau
 * Praxis ANTLR-Parser für X
 * - Grammatik für Scanner und Parser
 * 
 * **********************************************
 */

grammar X; 
  
options {
  language = Java;
  output = AST;
  ASTLabelType = CommonTree;
  backtrack = true;
}
 
// AST-Tokens
tokens { 
  ID;
  INTCONST;
  FLOATCONST;
  WS;
  MODIFIER;
  DECLIST;
  PROGRAM;
  DECL;
  TYPE;
  STAT;
  STATLIST;
  EXPR;
  INVALID;
} 

@parser::header {package de.dhbw.compiler.antlrxparser;}
@lexer::header  {package de.dhbw.compiler.antlrxparser;}

// Anmerkung: Es müssen Lexer- UND Parser-Regeln stehen, da sonst das Generieren nicht funktionieren
// Lexer stuff
ID:         ('a'..'z' | 'A'..'Z')
            (options {
              greedy = true; // Lese alle möglichen Zeichen ein -> Zahlen in ID -> bleibt weiterhin ID
            }: 'a'..'z' | 'A'..'Z' | '0'..'9')*;

INTCONST:       '0' | ('1'..'9') ('0'..'9')*;
FLOATCONST:     INTCONST ('.' DIGIT*)? ('e'|'E')('+' |'-' )? INTCONST
                | INTCONST ('.' DIGIT*)?;

STRINGCONST:    '"' (ESCAPE | ~('\\' | '"'))* '"';
ESCAPE:         '\\' ('\"' |'\'' | '\\');

WS:             ('\t' | ' ' | '\r' | '\n' | '\f')+          { skip(); };

INVALID:        .;

fragment DIGIT: ('0'..'9');


// -- Parser stuff
program:        'program' ID ';' decllist statlist '.' EOF -> ^(PROGRAM ID decllist statlist);

// Declaration
decllist:       decl decllist -> ^(DECLIST decl decllist);
decl:           modifier ID ':' type ';' -> ^(DECL modifier ID type);
modifier:       'read' 'print'? | 'read' | 'print';
type:           'int' | 'float' | 'string';

// Block
statlist:       'begin' (stat ';')* 'end' -> ^(STATLIST stat*);
stat:           assignstat | condstat | whilestat | forstat | statlist;
assignstat:     ID ':=' expr -> ^(':=' ID expr);
condstat:       'if' cond 'then' stat condElseStat? -> ^('if' cond stat condElseStat? );
condElseStat:   'else' stat -> ^('else' stat);
whilestat:      'while' '(' cond ')' stat -> ^('while' cond stat);
forstat:        'for' '(' assignstat ';' cond ';' assignstat ')' stat
                -> ^('for' assignstat cond assignstat stat);

expr:       expr2 '+' expr        -> ^('+' expr2 expr)
            | expr2 '-' expr     -> ^('-' expr2 expr)
            | expr2                 -> ^(expr2);
expr2:      expr3 '*' expr2   -> ^('*' expr3 expr2)
            | expr3 '/' expr2   -> ^('/' expr3 expr2)
            | expr3                 -> ^(expr3);
expr3:      number | '-' number | STRINGCONST | '('! expr^ ')';
number:     INTCONST | FLOATCONST;

compOp:     '<' | '>' | '=';
cond:       expr cond2;
cond2:      compOp expr;

// -- Dummy rules
// Das sollte dafür sorgen, dass implizite Tokens auch ihre Tokens bekommen
// TODO: Remove this
minus:      '-';
div:      '/';
multiply:      '*';
plus:       '+';
