grammar SGI; options {language = 'CSharp2'; output=AST; } @header { using System.IO; } @members { static Registry registry; static System.Collections.ArrayList regArray; // used for precompile static Logger log; // used for logging messages static Logger regLog; // to log register updates static int numFound; // used to count resolved register names static int numResolved; //static double result; //static System.Collections.Stack argStack = new System.Collections.Stack(); //Register resultRegister; public Registry Registry { set { registry = value; } } public ArrayList RegArray { get { return regArray; } set { regArray = value; } } public Logger Log { set { log = value; } } public Logger RegLog { set { regLog = value; } } public static Register findRegisterByName(String str) { foreach (Register reg in regArray) { if (reg.FullName.Equals(str)) return reg; } return null; } // Math functions public int doMax(ArrayList list) { if (list.Count == 0) return 0; int max = ((Register)list[0]).ScaledValue; for (int i = 1; i < list.Count; i++) { int v = ((Register)list[i]).ScaledValue; if (v > max) max = v; } return max; } public int doMin(ArrayList list) { if (list.Count == 0) return 0; int min = ((Register)list[0]).ScaledValue; for (int i = 1; i < list.Count; i++) { int v = ((Register)list[i]).ScaledValue; if (v < min) min = v; } return min; } public int doAvg(ArrayList list) { if (list.Count == 0) return 0; int total = 0; foreach (Register r in list) total += r.ScaledValue; return total / list.Count; } // Dummy methods (for now) public int precompile() { return -1; } public int expression() { return -1; } public void ReInit() { } } @parser::namespace { SGIServer } @lexer::namespace { SGIServer } prog: (stat SEMI)+ ; /** Statement */ stat: REGISTER '=' expr { String regName = $REGISTER.text; Register reg = findRegisterByName(regName); if (reg != null) reg.ScaledValue = $expr.value; else log.writeErrText("Parser 'stat' id not find Register " + regName); } ; elist scope { ArrayList idlist; } : ids+=expr (COMMA ids+=expr)* { $elist::idlist = $ids; }; expr returns [int value] : e=multdiv {$value = $e.value} ( '+' e=multdiv {$value += $e.value;} | '-' e=multdiv {$value -= $e.value;} )* ; multdiv returns [int value] : e=atom {$value = $e.value;} ( '*' e=atom {$value *= $e.value;} | '/' e=atom {if ($e.value != 0) $value /= $e.value; else $value = 0;} )* ; atom returns [int value] : CONSTANT {$value = Convert.toInt32($CONSTANT.text);} | REGISTER { Register reg = findRegisterByName($REGISTER.text); if (reg != null) $value = reg.ScaledValue; else { log.writeErrText("Parser 'atom' did not find Register " + $REGISTER.text); $value = 0; } } | ('avg' | 'Avg') LPAREN elist RPAREN { $value = doAvg($elist::idlist); } | ('min' | 'Min') LPAREN elist RPAREN { $value = doMin($elist::idlist); } | ('max' | 'Max') LPAREN elist RPAREN { $value = doMax($elist::idlist); } | LPAREN expr RPAREN {$value = $expr.value;} ; WS : (' ' | '\t' | '\n' | '\r') { $channel = HIDDEN; } ; LPAREN : '(' ; RPAREN : ')' ; STAR : '*' ; DIV : '/' ; PLUS : '+' ; MINUS : '-' ; SEMI : ';' ; COMMA : ',' ; fragment DIGIT : '0'..'9' ; fragment LETTER : 'a'..'z' | 'A'..'Z' | '_' ; COMMENT : '/*' .* '*/' { $channel = HIDDEN; } ; LINE_COMMENT: '//' ~('\n' | '\r')* '\r'? '\n' { $channel = HIDDEN; } ; INT : (DIGIT)+ ; FLOAT : INT | INT '.' INT | '.' INT ; CONSTANT: FLOAT | FLOAT ('e' | 'E') ('+' | '-')? INT ; EXP : '**' ; AND : '&' ; OR : '|' ; XOR : '^' ; IDENT : LETTER (LETTER | DIGIT)* ; REGISTER: IDENT ('!'IDENT)* ;