Parsing 解析过程调用玩具语言
我有一种特定的玩具语言,它使用EBNF语法定义过程和过程调用:Parsing 解析过程调用玩具语言,parsing,compiler-construction,recursive-descent,Parsing,Compiler Construction,Recursive Descent,我有一种特定的玩具语言,它使用EBNF语法定义过程和过程调用: program = procedure, {procedure} ; procedure = "procedure", NAME, bracedblock ; bracedBlock = "{" , statementlist , "}" ; statementlist = statement, { statement } ; statement = define | if
program = procedure, {procedure} ;
procedure = "procedure", NAME, bracedblock ;
bracedBlock = "{" , statementlist , "}" ;
statementlist = statement, { statement } ;
statement = define | if | while | call | // others omitted for brevity ;
define = NAME, "=", expression, ";"
if = "if", conditionalblock, "then", bracedBlock, "else", bracedBlock
call = "call" , NAME, ";" ;
// other definitions omitted for brevity
该语言中的程序的标记器已经实现,并返回一个标记向量
现在,在没有过程调用的情况下解析所述程序相当简单:可以直接使用上述语法定义递归下降解析器,并简单地通过标记进行解析。一些进一步的说明:
B
可以在A
之后定义,A
可以调用B
,反之亦然)
define
语句每个只有一个行号,而if
语句本身是两个语句列表的父语句,它有多个行号。例如:
LN码
程序A{
1.a=5;
2.b=7;
3.c=3;
4.5.如果(b2){
9.d=d+1;}
}
程序C{
10.e=10;
11.f=8;
12.呼叫B;
}
整个程序中的行数是连续的;只有程序定义和<代码> E/SCOR>关键字没有被分配给行编号。行数是由语法定义的,而不是它们在源代码中的位置:例如,考虑“行”<代码> 4 < /代码>和<代码> 5 < /代码> .<
C
将具有行号<代码>6至8
包括在内,而不是10
至12
包括在内
另一个解决方案是按顺序解析整个程序一次,维护一个toposort过程调用,然后按照所述toposort进行第二次解析。由于实现细节,这是有问题的
有没有更好的方法可以做到这一点?尝试在一个在线过程中完全处理程序文本总是很有诱惑力的。不幸的是,这实际上从来不是最简单的解决方案。尝试在线性级数中同时处理每件事会导致一种交织计算的意大利面,并使其全部工作正常t总是对语言进行不必要的限制,这将在以后被证明是不幸的 因此,我鼓励您重新考虑一些设计决策。如果您使用解析器只是构建程序的某种结构表示——无论是抽象语法树还是三地址码向量,或者其他替代方案——然后在该结构上进行一系列单用途传递的进一步处理在这些表示中,您可能会发现代码是:
- 更简单,因为计算不必混合
- 更一般,因为每个过程都可以以最方便的顺序进行,而不是限制输入以适应线性顺序
- 更具可读性和可维护性
LN CODE
procedure A {
1. a = 5;
2. b = 7;
3. c = 3;
4. 5. if (b < c) then { call C; } else {
6. call B;
}
procedure B {
7. d = 5;
8. while (d > 2) {
9. d = d + 1; }
}
procedure C {
10. e = 10;
11. f = 8;
12. call B;
}