C 编译器中的抽象语法树:如何准确地表示函数?

C 编译器中的抽象语法树:如何准确地表示函数?,c,regex,bison,abstract-syntax-tree,C,Regex,Bison,Abstract Syntax Tree,我们正在创建一种非常简单的编程语言,使用Flex和Bison进行解析和语法分析,并使用C构建编译器。 在直接进入汇编之前,我们将根据语言规则创建一个抽象语法树。但是我们很难从语言中表达一个特定的函数。 该功能描述如下: FILTERC:它接受一个条件和一个表达式列表作为输入,并返回这些表达式中有多少与条件匹配。它可以是单个条件或计算条件。 它用于以下形式:FILTERC(条件,[expression list]) 条件必须在每个元素之前有一个下划线,表示表达式应放置在何处进行比较。示例:FILT

我们正在创建一种非常简单的编程语言,使用Flex和Bison进行解析和语法分析,并使用C构建编译器。 在直接进入汇编之前,我们将根据语言规则创建一个抽象语法树。但是我们很难从语言中表达一个特定的函数。 该功能描述如下:

FILTERC:它接受一个条件和一个表达式列表作为输入,并返回这些表达式中有多少与条件匹配。它可以是单个条件或计算条件。 它用于以下形式:FILTERC(条件,[expression list])
条件必须在每个元素之前有一个下划线,表示表达式应放置在何处进行比较。示例:FILTERC(>4和p>当解析器读取表达式的一部分(例如“>”)时,它没有足够的资源为表达式构建树。这同样适用于您语言中的任何概念(“非终结符”)。从这个角度看,您可能会感到困惑

显然你不明白像Bison这样的LR解析器是如何工作的。假设我们有规则R1,R2,…规则有右手边,例如Rn=T1 T2 T3;每个规则的右手边长度为L(Rn)

您需要的关键思想是,LR解析器从左到右从输入流收集(“堆栈”,是的,它确实使用了一堆令牌)令牌。这些步骤称为“移位”。解析器反复移位,不断寻找指示已读取足够令牌的情况(例如,T1、T2、然后T3)满足某些语法规则Rn的右侧。解析器生成器的魔力和它生成的LR表允许解析器一次有效地跟踪所有“活动”规则,我们在这里不再进一步讨论

在该点识别出的右侧,LR解析器执行“reduce”操作,并用非终端标记Rn替换与规则体匹配的堆叠标记(“然后弹出堆栈L(Rn)次并按下Rn”)。在返回到从输入流收集终端令牌之前,它会尽可能多地进行缩减。在非常小的语法上手动模拟此过程是值得的。[一个微妙的细节:某些规则的右侧为空,例如,L(Rn)==0);在这种情况下,当减少发生时,零POP发生,是的,这听起来很有趣,但它是致命的权利]

在解析器执行reduce操作的每一点上,它都为解析器程序员提供了一个做一些额外工作的机会。这些额外的工作几乎总是“树的建设”。显然,组成规则Rn的令牌都已被看到,因此如果令牌都是终端,则可以构建表示Rn的树。事实上,如果已经看到了Rn的所有标记,并且Rn包含一些非终结符,那么必须有reduce操作来生成每个非终结符。如果它们中的每一个都生成了一个表示它们自己的树,那么当包含非终结符的规则减少时,已经为其他非终结符生成了树,并且可以将这些树组合起来为当前规则生成树

LR解析器生成器工具(如Bison)通常通过提供可在reduce操作中调用的树构建操作符来帮助您。它还帮助您使reduce操作可以使用已处理的非终结符的树,这样它就可以组合它们来生成reduce操作的树。(它通过在与令牌堆栈平行的堆栈中跟踪生成的树来实现这一点。)在没有需要所有子树的情况下,它从未尝试减少或尝试生成树


我认为您需要手动仔细阅读Bison,当您尝试实现解析器和缩减时,所有这些都将变得清晰;这本手册有很好的例子。很明显,你没有这样做(害怕不知道如何处理树木?),因为a)你所表达的规则被打破了;无法生成术语,并且b)您没有任何嵌入式reduce操作

为什么您关心(子)AST树的构建顺序?使用ASTs解析的问题是捕获已解析的内容。AST的目的是表示捕获的结果;以后可以按照您喜欢的任何顺序处理它(不同于从左到右的解析)。所以为过滤条件构建AST节点(通过将操作附加到规则,您清楚地知道如何做到这一点),并为表达式构建AST节点(通过将操作附加到规则),然后运行生成的解析器。这将生成一个完整的AST,包含过滤条件和表达式。谢谢,Ira。但我仍然不明白:当解析器读取规则
filter::=FILTERC(条件过滤器[expression\u list])
时,它将按顺序执行,以便尝试确定什么是条件过滤器。它将看到一个条件过滤器可以是一个比较过滤器,这可以是,例如:
comparison\u filter::=\u>expression
。因此,它需要使用操作符(在本例中为>符号)创建一个节点,并使用要比较的表达式创建左、右子节点。问题是,它还没有左边的表达式,因为它还没有读过。你应该把你的问题的标题改成更像:“……如何用野牛建造一棵树?”
filter ::= FILTERC ( condition_filter , [ expression_list ] )
;
condition_filter ::= comparison_filter | comparison_filter AND comparison_filter | comparison_filter OR comparison_filter
;
comparison_filter ::= _ > expression | _ < expression | _ == expression | _ >= expression | _ <= expression | _ != expression
;
expression_list ::= expression | expression , expression_list
;
expression: term | expression + term | expression - term
;
term: factor | term * factor | term / factor 
;
factor: ID | INT_LITERAL | REAL_LITERAL | STRING_LITERAL | ( expression ) | filter
;
IF condition THEN block {thenPtr = blockPtr;} ENDIF {createNode("if", conditionPtr, thenPtr);}