I’m working on a DSL parser using Java CUP, and I’m getting this error when trying to compile my .cup grammar:
Error: Syntax error @ Symbol: PARSER (unknown:19/-5(-1) - unknown:19/1(-1))
Error : Internal error: Unexpected exception
Exception in thread "main" java.lang.NullPointerException
at java_cup.runtime.lr_parser.symbl_name_from_id(lr_parser.java:456)
at java_cup.runtime.lr_parser.report_expected_token_ids(lr_parser.java:446)
at java_cup.runtime.lr_parser.syntax_error(lr_parser.java:433)
at java_cup.runtime.lr_parser.parse(lr_parser.java:725)
at java_cup.Main.parse_grammar_spec(Main.java:496)
at java_cup.Main.main(Main.java:196)
This happens during grammar compilation, not at runtime.
CUP fails to report the real syntax error and triggers an NPE inside symbl_name_from_id, which makes it harder to locate the issue.
Below is the exact .cup grammar I’m compiling:
package edu.uelbosque.dsl.parser;
import java_cup.runtime.*;
import edu.uelbosque.dsl.ast.*;
terminal KW_PROTOCOLO, KW_META, KW_INCLUSION, KW_EXCLUSION, KW_OBJETIVOS, KW_PASOS,
KW_NOMBRE, KW_CUANDO, KW_ACCIONES, KW_MEDIDA, KW_EDUCACION, KW_TAREA,
KW_ORDEN_MED, KW_SEGURIDAD, KW_SEGUIMIENTO, KW_AJUSTE_DOSIS, KW_AGREGAR_MED,
KW_LABS, KW_ALERTAS_GLOBALES, KW_AUTOR, KW_VERSION, KW_VIGENCIA, KW_EVIDENCIA, KW_INTERACCION,
LBRACE, RBRACE, LSQUARE, RSQUARE, OPEN_BRACKET, CLOSE_BRACKET, COLON, COMMA,
DOT, ARROW, EQ, LT, GT, LE, GE, AND, OR, STRING, NUMBER, BOOLEAN, IDENT;
non terminal Document, Protocol, ProtocolBody, ProtocolItem, Meta, Inclusion, Exclusion, Objectives, Steps,
StepList, Step, StepBody, StepTail, ActionList, Actions, Action, Measure, Education, Task,
OrderMed, OrderMedTail, FollowUp, AdjustDose, AddMed, Labs, GlobalAlerts, AlertList, Alert,
Obj, Pairs, Pair, Key, Value, List, Values, StringList, Strings, CondList, Exprs, Expr,
OrExpr, AndExpr, RelExpr, Primary, CallOrIdent, CallTail, IdentChain, ArgList;
parser code {:
SymbolTable st = new SymbolTable();
:};
start with Document;
Document ::= Protocol EOF {: RESULT = new Document($1); :} ;
Protocol ::= KW_PROTOCOLO STRING LBRACE ProtocolBody RBRACE {: RESULT = new Protocol($2, $4); :} ;
ProtocolBody ::= ProtocolItem ProtocolBody {: RESULT = $2.prepend($1); :}
| /* empty */ {: RESULT = new ProtocolBody(); :} ;
ProtocolItem ::= Meta | Inclusion | Exclusion | Objectives | Steps | GlobalAlerts ;
Meta ::= KW_META COLON Obj {: RESULT = new Meta($3); :} ;
Inclusion ::= KW_INCLUSION COLON CondList {: RESULT = new Inclusion($3); :} ;
Exclusion ::= KW_EXCLUSION COLON CondList {: RESULT = new Exclusion($3); :} ;
Objectives ::= KW_OBJETIVOS COLON StringList {: RESULT = new Objectives($3); :} ;
Steps ::= KW_PASOS COLON LSQUARE StepList RSQUARE {: RESULT = new Steps($4); :}
| KW_PASOS COLON LSQUARE RSQUARE {: RESULT = new Steps(null); :} ;
StepList ::= Step {: RESULT = new StepList($1); :}
| Step COMMA StepList {: RESULT = $3.prepend($1); :} ;
Step ::= LBRACE StepBody RBRACE {: RESULT = new Step($2); :} ;
StepBody ::= KW_NOMBRE COLON STRING StepTail {: RESULT = new StepBody($3, $4); :} ;
StepTail ::= COMMA KW_CUANDO COLON CondList COMMA KW_ACCIONES COLON ActionList {: RESULT = new StepTail($4, $8); :}
| COMMA KW_ACCIONES COLON ActionList {: RESULT = new StepTail(null, $4); :} ;
ActionList ::= LSQUARE Actions RSQUARE {: RESULT = new ActionList($2); :}
| LSQUARE RSQUARE {: RESULT = new ActionList(null); :} ;
Actions ::= Action {: RESULT = new Actions($1); :}
| Action COMMA Actions {: RESULT = $3.prepend($1); :} ;
Action ::= Measure | Education | Task | OrderMed | FollowUp | AdjustDose | AddMed | Labs ;
Measure ::= LBRACE KW_MEDIDA COLON STRING RBRACE {: RESULT = new Measure($4); :} ;
Education ::= LBRACE KW_EDUCACION COLON STRING RBRACE {: RESULT = new Education($4); :} ;
Task ::= LBRACE KW_TAREA COLON STRING RBRACE {: RESULT = new Task($4); :} ;
OrderMed ::= LBRACE KW_ORDEN_MED COLON Obj OrderMedTail RBRACE {: RESULT = new OrderMed($4, $5); :}
| LBRACE KW_ORDEN_MED COLON Obj RBRACE {: RESULT = new OrderMed($4, null); :} ;
OrderMedTail ::= COMMA KW_SEGURIDAD COLON CondList {: RESULT = new OrderMedTail($4); :} ;
FollowUp ::= LBRACE KW_SEGUIMIENTO COLON Obj RBRACE {: RESULT = new FollowUp($4); :} ;
AdjustDose ::= LBRACE KW_AJUSTE_DOSIS COLON Obj RBRACE {: RESULT = new AdjustDose($4); :} ;
AddMed ::= LBRACE KW_AGREGAR_MED COLON Obj RBRACE {: RESULT = new AddMed($4); :} ;
Labs ::= LBRACE KW_LABS COLON StringList RBRACE {: RESULT = new Labs($4); :} ;
GlobalAlerts ::= KW_ALERTAS_GLOBALES COLON LSQUARE AlertList RSQUARE {: RESULT = new GlobalAlerts($4); :}
| KW_ALERTAS_GLOBALES COLON LSQUARE RSQUARE {: RESULT = new GlobalAlerts(null); :} ;
AlertList ::= Alert {: RESULT = new AlertList($1); :}
| Alert COMMA AlertList {: RESULT = $3.prepend($1); :} ;
Alert ::= Expr ARROW STRING {: RESULT = new Alert($1, $3); :}
| KW_INTERACCION COLON STRING ARROW STRING {: RESULT = new AlertInteraction($3, $5); :} ;
Obj ::= LBRACE Pairs RBRACE {: RESULT = new Obj($2); :}
| LBRACE RBRACE {: RESULT = new Obj(null); :} ;
Pairs ::= Pair {: RESULT = new Pairs($1); :}
| Pair COMMA Pairs {: RESULT = $3.prepend($1); :} ;
Pair ::= Key COLON Value {: RESULT = new Pair($1, $3); :} ;
Key ::= IDENT {: RESULT = new Key($1); :}
| KW_AUTOR {: RESULT = new Key($1); :}
| KW_VERSION {: RESULT = new Key($1); :}
| KW_VIGENCIA {: RESULT = new Key($1); :}
| KW_EVIDENCIA {: RESULT = new Key($1); :} ;
Value ::= STRING {: RESULT = new Value($1); :}
| NUMBER {: RESULT = new Value($1); :}
| BOOLEAN {: RESULT = new Value($1); :}
| Obj {: RESULT = new Value($1); :}
| List {: RESULT = new Value($1); :} ;
List ::= LSQUARE Values RSQUARE {: RESULT = new List($2); :}
| LSQUARE RSQUARE {: RESULT = new List(null); :} ;
Values ::= Value {: RESULT = new Values($1); :}
| Value COMMA Values {: RESULT = $3.prepend($1); :} ;
StringList ::= LSQUARE Strings RSQUARE {: RESULT = new StringList($2); :}
| LSQUARE RSQUARE {: RESULT = new StringList(null); :} ;
Strings ::= STRING {: RESULT = new Strings($1); :}
| STRING COMMA Strings {: RESULT = $3.prepend($1); :} ;
CondList ::= LSQUARE Exprs RSQUARE {: RESULT = new CondList($2); :}
| LSQUARE RSQUARE {: RESULT = new CondList(null); :} ;
Exprs ::= Expr {: RESULT = new Exprs($1); :}
| Expr COMMA Exprs {: RESULT = $3.prepend($1); :} ;
Expr ::= OrExpr {: RESULT = $1; :} ;
OrExpr ::= AndExpr {: RESULT = $1; :}
| AndExpr OR OrExpr {: RESULT = new OrExpr($1, $3); :} ;
AndExpr ::= RelExpr {: RESULT = $1; :}
| RelExpr AND AndExpr {: RESULT = new AndExpr($1, $3); :} ;
RelExpr ::= Primary {: RESULT = $1; :}
| Primary EQ Primary {: RESULT = new RelExpr($1, "==", $3); :}
| Primary LT Primary {: RESULT = new RelExpr($1, "<", $3); :}
| Primary GT Primary {: RESULT = new RelExpr($1, ">", $3); :}
| Primary LE Primary {: RESULT = new RelExpr($1, "<=", $3); :}
| Primary GE Primary {: RESULT = new RelExpr($1, ">=", $3); :} ;
Primary ::= NUMBER {: RESULT = new Primary($1); :}
| STRING {: RESULT = new Primary($1); :}
| BOOLEAN {: RESULT = new Primary($1); :}
| CallOrIdent {: RESULT = $1; :}
| OPEN_BRACKET Expr CLOSE_BRACKET {: RESULT = $2; :} ;
CallOrIdent ::= IdentChain CallTail {: RESULT = new CallOrIdent($1, $2); :}
| IdentChain {: RESULT = new CallOrIdent($1, null); :} ;
CallTail ::= OPEN_BRACKET ArgList CLOSE_BRACKET {: RESULT = new CallTail($2); :}
| OPEN_BRACKET CLOSE_BRACKET {: RESULT = new CallTail(null); :} ;
IdentChain ::= IDENT {: RESULT = new IdentChain($1); :}
| IDENT DOT IdentChain {: RESULT = $3.prepend($1); :} ;
ArgList ::= Expr {: RESULT = new ArgList($1); :}
| Expr COMMA ArgList {: RESULT = $3.prepend($1); :} ;
What I’ve tried:
Verified that all terminals and non-terminals are declared.
Checked that all
{::}action blocks are balanced.Checked for missing semicolons or commas in production lists.
Tried running CUP with
-expect 1to get better messages.Renamed some nonterminals (e.g.,
List,Document) to avoid collisions, but the error persists.
What kind of grammar issue causes CUP to emit:
Syntax error @ Symbol: PARSERfollowed by a
NullPointerExceptioninsymbl_name_from_id?
How can I locate the real syntax problem inside this grammar?
Any guidance on how to debug or a pointer to the likely broken production would be greatly appreciated.