JISON编写简单语法时解析'('报Syntax error问题咨询
该报错是语法产生式设计缺陷导致,和词法规则无关——既然你已经确认词法分析可以正确输出所有token(对应序列为{、CALL、IDENTIFIER(add)、(、NUMBER(2)、,、NUMBER(3)、)、}),就不需要在词法逻辑上浪费时间。
核心问题是语法规则没有覆盖「被调用对象(标识符/表达式)后跟左括号」的函数调用结构:解析器处理到add标识符时,会按照现有规则将其归约为合法的表达式/语句片段,之后读取到下一个token(时,会检查当前语法状态下(是否为合法的后续token——如果你的语法里没有定义任何匹配Xxx '(' ...的产生式,解析器没有可用的移进/归约动作,就会直接在(位置抛出语法错误,和你遇到的报错位置完全吻合。
1. call语句规则设计错误
如果你的语法中把call关键字的调用规则写成了直接跟参数列表,就会出现这个问题:
// 错误写法:期望call后直接接左括号,和`call add(2,3)`的结构不匹配 stmt: CALL '(' argList ')'
修复方案:调整规则,让call后接实际的调用表达式:
stmt: CALL call_expr ; // 如果仅支持直接调用标识符函数,用这个规则即可 call_expr: IDENTIFIER '(' argList? ')'
2. 通用表达式规则缺失后缀调用产生式(90%以上同类报错的原因)
如果你把call设计为通用的调用关键字,后面可以接任意表达式,大概率是表达式规则漏写了函数调用的后缀匹配:
// 错误写法:expr仅支持字面量、标识符、call后跟expr,没有定义expr后接(的结构 expr: NUMBER | STRING | IDENTIFIER | CALL expr ;
修复方案:用左递归补全后缀函数调用规则,同时在优先级声明部分把函数调用的优先级设为最高(放在所有运算符声明的最前面),避免LALR解析出现移进/归约冲突:
// 优先级声明,越靠上优先级越高 %left '(' ')' %left '*' '/' %left '+' '-' expr: NUMBER | STRING | IDENTIFIER | expr '(' argList? ')' // 补全这行,支持任意表达式后跟括号的调用形式 | CALL expr ; // 参数列表规则 argList: expr (',' expr)* ;
3. 左括号优先级配置错误
如果你已经写了上述函数调用规则,但JISON编译语法文件时出现shift/reduce冲突,通常是(的优先级配置过低,导致解析器无法判断是要做函数调用归约还是做其他表达式运算,把'(' ')'的优先级声明移到所有运算符优先级声明的最顶部即可解决。
修复后重新生成解析器,只要你的块规则是block: '{' stmt* '}',即可正常解析测试文本:
{ call add(2, 3) }
解析后的结构为:代码块 -> call语句 -> 函数调用add -> 参数2、参数3。
内容的提问来源于stack exchange,提问作者user18303981

