问题描述
我有某种玩具语言,它使用EBNF语法定义了过程和过程调用:
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",";" ;
// other definitions omitted for brevity
已经实现了使用该语言的程序的标记器,并返回标记向量。
现在,无需程序调用就解析该程序非常简单:可以直接使用上述语法定义递归下降解析器,并简单地通过标记进行解析。其他注意事项:
-
每个过程都可以直接或间接(任何其他过程 ,并且这些过程不必按照出现的顺序进行源代码中的内容(即
B
可以在A
之后定义,A
可以调用B
,反之亦然)。 -
过程名称必须唯一,并且“保留关键字”可以用作变量/过程名称。
-
空格无关紧要,至少在不同类型的令牌中是如此:类似于C / C ++。
-
没有作用域规则:所有变量都是全局变量。
-
“行号”的概念很重要:每个语句都有一个或多个与其关联的行号:例如,
define
语句每个只有一个行号,而{{1 }}语句本身是两个语句列表的父级,具有多个行号。例如:
if
-
在整个程序中,
-
行号是连续的;没有为过程定义和关键字
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; }
分配行号。行号是由语法定义的,而不是它们在源代码中的位置:例如,考虑“行”else
和4
。 -
在给定每个语句及其行号,使用的变量,变量 set 和子容器的数据库中,需要设置一些关系。 这是一个关键考虑因素。
因此,我的问题是:我如何解析这些函数调用,保持行号的完整性以及设置关系?
我已经考虑过“ OS”的处理方式:遇到过程调用时,请寻找与所述被调用过程匹配的过程,解析被调用者,然后将调用堆栈展开回调用者。但是,这破坏了行号的排序:如果要以这种方式解析上述程序,则5
的行号为C
至6
,而不是8
10
(含)。
另一种解决方案是依次解析整个程序一次,维护过程调用的拓扑,然后按照所述拓扑对第二次进行解析。由于实现细节,这是有问题的。
有没有可能更好的方法呢?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)