import java_cup.runtime.*; import java.util.*; import java.io.*; init with {: table = new HashMap>(); :}; parser code {: public HashMap> table; public void report_error(String message, Object info) { StringBuffer m = new StringBuffer(message); if (info instanceof Symbol) { if (((Symbol)info).left != 1 && ((Symbol)info).right != 1) { if (((Symbol)info).left != -1 && ((Symbol)info).right != -1) { int line = (((Symbol)info).left) + 1; int column = (((Symbol)info).right) + 1; m.append(" (line " + line + " column " + column + ")"); } } System.err.println(m); } } public Object stack(int position) { return (((Symbol)stack.elementAt(tos + position)).value); } :}; ////////////////////////////////// ///// SYMBOLS DECLARATION ///////////////////////////////// terminal TOKEN1, TOKEN2, TOKEN3, M, MS, MINMAX, PART, ARROW, SEP; terminal EQ, PIPE, CM, S, COL, RO, RC, SO, SC; terminal String QSTRING; terminal Integer UINT; non terminal prog, header, token1_l, cars, car, race, print_min_max_l, min_max; non terminal Object[] section_names, performances; non terminal HashMap speeds; non terminal Float drive_stats, parts, part; non terminal String NT0, NT1; ////////////////////////////////// ///// GRAMMAR ///////////////////////////////// start with prog; prog ::= header SEP cars SEP race; /******************/ /* Header section */ /******************/ header ::= token1_l TOKEN2 S token1_l TOKEN3 S token1_l | token1_l TOKEN3 S token1_l TOKEN2 S token1_l ; token1_l ::= token1_l TOKEN1 S | /* epsilon */; /****************/ /* Cars section */ /****************/ cars ::= car car | cars car car; car ::= QSTRING:s SO speeds:tab SC {: parser.table.put(s, tab); :} ; speeds ::= QSTRING:s EQ UINT:u MS {: RESULT = new HashMap(); RESULT.put(s, u); :} | speeds:tab CM QSTRING:s EQ UINT:u MS {: tab.put(s, u); RESULT = tab; :} ; /****************/ /* Race section */ /****************/ race ::= print_min_max_l performances:s {: System.out.println("WINNER: " + s[0] + " " + s[1] + " s"); :} ; /* Management of PRINT_MIN_MAX function */ print_min_max_l ::= | print_min_max_l min_max; min_max ::= MINMAX RO QSTRING:s RC RO section_names:m RC S {: System.out.println("MIN: " + m[0] + " MAX: " + m[1]); :} ; section_names ::= QSTRING:s {: String car = (String)parser.stack(-3); HashMap speeds = parser.table.get(car); Integer speed = (Integer)speeds.get(s); RESULT = new Object[2]; RESULT[0] = speed; // Current min value RESULT[1] = speed; // Current max value :} | section_names:m CM QSTRING:s {: String car = (String)parser.stack(-5); HashMap speeds = parser.table.get(car); Integer speed = (Integer)speeds.get(s); RESULT = new Object[2]; // Update current min and max values if (speed < (Integer)m[0]) { // New min RESULT[0] = speed; RESULT[1] = m[1]; } else if (speed > (Integer)m[1]) { // New max RESULT[0] = m[0]; RESULT[1] = speed; } else { // No change in min and max RESULT[0] = m[0]; RESULT[1] = m[1]; } :} ; /* Part regarding performances */ performances ::= QSTRING:s {: System.out.println(s); :} ARROW parts:x S {: System.out.println("TOTAL: " + x + " s"); // To detect the winner car RESULT = new Object[2]; RESULT[0] = s; // car name RESULT[1] = x; // result :} | performances:perf QSTRING:s {: System.out.println(s); :} ARROW parts:x S {: System.out.println("TOTAL: " + x + " s"); RESULT = new Object[2]; // Check if this car is the current winner if ((Float)perf[1] < x) { // Current winner is an old car RESULT[0] = perf[0]; RESULT[1] = perf[1]; } else { // Current winner is this car RESULT[0] = s; RESULT[1] = x; } :} ; // The two markers are used to transfer the car name semantic value in the symbol that preceeds the non terminal "part" parts ::= NT0 part:x {: RESULT = x; :} | parts:res PIPE NT1 part:x {: RESULT = res + x; :} ; NT0 ::= {: RESULT = (String)parser.stack(-2); :}; NT1 ::= {: RESULT = (String)parser.stack(-4); :}; part ::= PART UINT:x COL drive_stats:stat {: RESULT = stat; System.out.println("PART" + x + ": " + stat + " s"); :}; drive_stats ::= QSTRING:s UINT:u M {: String car = (String)parser.stack(-6); HashMap speeds = parser.table.get(car); Integer speed = (Integer)speeds.get(s); float result = (float)u.intValue() / (float)speed.intValue(); RESULT = new Float(result); :} | drive_stats:stat CM QSTRING:s UINT:u M {: String car = (String)parser.stack(-8); HashMap speeds = parser.table.get(car); Integer speed = (Integer)speeds.get(s); float result = (float)u.intValue() / (float)speed.intValue(); RESULT = new Float(result); RESULT += stat; /* Accumulate the time in result */ :} ;