使用Lark定义C语言语法时闭括号终端匹配无对应项报错如何解决
问题根因分析
- 词法规则冲突:你在
program规则中将空参数列表写为"()",Lark会将连续的左右括号识别为一个独立的终结符,而非两个单独的(、)终结符,导致解析时遇到单独的)无法匹配。
- 词法规则冲突:你在
- 变量名匹配失败:
string规则的正则要求最少匹配2个字符/[a-zA-Z0-9_.-]{2,}/,但你测试代码里的a、b、c都是单个字符的变量名,无法匹配var规则,导致后续的)无法被正确识别上下文。
- 变量名匹配失败:
- 语法规则逻辑混乱:
close_par作为非终结符被用来统一匹配右括号,但在if、switch等规则中混用close_par和直接写)终结符,导致解析上下文的预期token混乱;同时预处理、头文件、程序主体的递归规则互相嵌套,存在递归逻辑错误。
- 语法规则逻辑混乱:
- 预处理规则缺失:
#define PI 3.14的规则没有定义常量部分的匹配逻辑,解析到3.14时就会出错,连带影响后续代码的解析。
- 预处理规则缺失:
修复步骤
1. 修复空参数列表的规则
把program规则里的"()"拆成单独的两个终结符,修改为:
program : data_type func "(" var ")" "{" codeblock close_par | data_type func "(" ")" "{" codeblock close_par
2. 修复string的匹配规则
放宽变量名的匹配长度,单独适配C语言变量名命名规范,修改为:
string : /[a-zA-Z_][a-zA-Z0-9_.-]*/
这样单个字母的变量名也能正常匹配。
3. 统一右括号的使用方式
要么所有右括号都直接使用终结符")"、"}"、"]",要么统一用close_par非终结符,不要混用。比如把if规则修改为:
if : ("if" "(" logical ")" codeblock)+ ("elseif" "(" logical ")" codeblock)* ["else" codeblock]
4. 修复预处理规则
给definition增加常量匹配逻辑,同时调整预处理、头文件的递归规则,避免互相嵌套:
definition : def string const? header_files : preprocessor_commands file_names | header_files preprocessor_commands file_names start : header_files program
修复后的最小可运行示例
from lark import Lark g=r'''start : header_files program preprocessor_commands : "#include" | definition definition : def string const? def : "#define" | "#undef" | "#ifdef" | "#ifndef" | "#if" | "#else" | "#elif" | "#endif" | "#error" | "#pragma" header_files : preprocessor_commands file_names | header_files preprocessor_commands file_names file_names : "<stdio.h>" | "<math.h>" | "<conio.h>" | "<stdlib.h>" | "<string.h>" | "<ctype.h>" | "<time.h>" | "<float.h>" | "<limits.h>" | "<wctype.h>" program : data_type func "(" var ")" "{" codeblock close_par | data_type func "(" ")" "{" codeblock close_par data_type : "void" | "int" | "float" | "double" | "long" | "char" | "string" | "long long" | "unsigned_int" func : "main" | string var : string codeblock : "return" var term | "return" const term | "return" func term | "return" "(" expressions ")" term | declarations | expressions | statements | call | print | codeblock codeblock declarations : data_type var assign const ";" | data_type var assign var ";" | data_type var ("," var)* ";" expressions : arithmetic | bitwise | assignment | logical arithmetic : add | sub | mul | div | mod | unary add : const "+" arithmetic | var "+" arithmetic | const "+" const | var "+" var sub : const "-" arithmetic | var "-" arithmetic | const "-" const | var "-" var mul : const "*" arithmetic | var "*" arithmetic | const "*" const | var "*" var div : const "/" arithmetic | var "/" arithmetic | const "/" const | var "/" var mod : const "%" arithmetic | var "%" arithmetic | const "%" const | var "%" var unary : inc | dec inc : "++" var | var "++" dec : "--" var | var "--" bitwise : and | or | xor | boc | ls | rs and : const "&" bitwise | var "&" bitwise | const "&" const | var "&" var or : const "|" bitwise | var "|" bitwise | const "|" const | var "|" var xor : const "^" bitwise | var "^" bitwise | const "^" const | var "^" var boc : var assign "~" const | var assign "~" var ls : const "<<" const | var "<<" const rs : const ">>" const | var ">>" const assignment : var assign arithmetic term | var assign logical term assign : "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" statements : if | switch | loop if : ("if" "(" logical ")" "{" codeblock "}")+ ("elseif" "(" logical ")" "{" codeblock "}")* ["else" "{" codeblock "}"] logical : land | lor | lnot | equ | gre | les | greq | leeq | neq land : logical "&&" logical | const "&&" const | var "&&" var lor : logical "||" logical | const "||" const | var "||" var lnot : "!" logical | "!" var | "!" const equ : logical "==" logical | const "==" const | var "==" var gre : logical ">" logical | const ">" const | var ">" var les : logical "<" logical | const "<" const | var "<" var greq : logical ">=" logical | const ">=" const | var ">=" var leeq : logical "<=" logical | const "<=" const | var "<=" var neq : logical "!=" logical | const "!=" const | var "!=" var switch : "switch" "(" expressions ")" "{" (switch_case)* ["default" ":" codeblock] "}" switch_case : "case" const ":" codeblock loop : for | while | do_while for : "for" "(" [[data_type] var assign const] ";" [logical] ";" [arithmetic] ")" "{" codeblock "}" | "for" "(" [[data_type] var assign const] ";" [logical] ";" [arithmetic] ")" codeblock while : "while" "(" logical ")" "{" codeblock "}" | "while" "(" logical ")" codeblock do_while : "do" "{" codeblock "}" "while" "(" logical ")" ";" call : func "(" var ("," var)* ")" term | var assign func "(" var ("," var)* ")" term | func "(" ")" term | var assign func "(" ")" term print : "printf" "(" (dcstring)* ")" term %import common.SIGNED_NUMBER %import common.FLOAT const : SIGNED_NUMBER | FLOAT term : ";" digit : "0".."9" nz_dig : "1".."9" integer : (digit)* (nz_dig)+ | "-" (digit)* (nz_dig)+ decimal : (digit)+ "." (digit)+ | "-" (digit)+ "." (digit)+ letter : "a".."z" | "A".."Z" char : letter | SIGNED_NUMBER string : /[a-zA-Z_][a-zA-Z0-9_.-]*/ dcstring : /"[^"]*"/ close_par : "}" | ")" | "]" WHITESPACE: " " | "\t" | "\f" | "\n" %ignore WHITESPACE+ COMMENT: "//" /[^\n]/* | "/*" /(\S|\s)*?/ "*/" %ignore COMMENT ''' parser=Lark(grammar=g,parser="earley") code='''#include<stdio.h> #define PI 3.14 void main() { int a,b; long c=1; if(a==b || b==c) return 2; } ''' print(parser.parse(code).pretty())
内容的提问来源于stack exchange,提问作者ThunderLord
相关产品推荐
相关产品推荐

