这使得“参数传递”(属性流动)的讨论更加丰富。我们现在有两种清晰的“参数”流:
-
综合属性 (Synthesized Attribute) [自底向上]
- 是什么: 这就是您函数返回的
node对象。 - 目的: 构建AST。子节点(如
translateASTFactor)构建一个小树,并通过return语句将其“传递”给父节点(如translateASTTerm),父节点再将其组合成一个更大的树。 - 方向: Bottom-Up (自底向上)。
- 是什么: 这就是您函数返回的
-
继承属性 (Inherited Attribute) [自顶向下]
- 是什么: 这就是您通过函数参数(如
const std::string& type)传递的信息。 - 目的: 提供上下文。父节点(如
translateASTDeclareStatement)将上下文信息(“我们正在声明的变量是int类型”)传递下去,子节点(如translateASTVarList)使用这个信息来执行语义动作(如更新符号表idenTable)。 - 方向: Top-Down (自顶向下)。
- 是什么: 这就是您通过函数参数(如
下面,我们使用您 C++ 代码中的文法,重新详细讲解这五种语句的属性流动。
1. 声明语句 (Declaration Statement)
-
C++ 代码:
translateASTDeclareStatement,translateASTVarList(type),translateASTB(type) -
文法:
<变量说明语句> -> 变量说明 <标识符列表> -
AST 目标:
(declare [Type] (varList [ID1] (linkVarList [ID2] ...))) -
属性流 (最完整的例子):
这是一个同时展现了继承和综合属性的完美例子。
-
Top-Down (继承属性):
translateASTDeclareStatement首先读取 “变量说明” (例如int),并将其存储在std::string type中。- 它向下调用
translateASTVarList(type),将type字符串作为继承属性传递下去。 translateASTVarList接着向下调用translateASTB(type),继续将这个type属性传递下去。
-
语义动作 (使用继承属性):
- 在
translateASTVarList和translateASTB内部,当它们match("标识符")(例如a) 时,它们会立即使用这个继承来的type属性来更新符号表 (Context):idenTable.Add(name)idenTable.UpdateTypeByName(name, type)
- 在
-
Bottom-Up (综合属性):
translateASTB构建并返回(linkVarList ...)节点 (作为B.ast)。translateASTVarList接收这个B.ast,将它和idNode.ast组合成(varList ...)节点,并返回这个节点 (作为varList.ast)。translateASTDeclareStatement接收这个varList.ast(存入node varList),将它和typeNode.ast组合成(declare ...)节点,并返回这个最终的AST子树 (作为<变量说明语句>.ast)。
-
-
代码中的“综合”与“继承”:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// P.S. 这是对您代码的简化伪代码,以突出属性流
node translateASTDeclareStatement()
{
node root = new node("declare");
string type = currentToken.value; // 1. 获取上下文
node typeNode(type);
// 2. 将 'type' 作为继承属性(inh)向下传递
node c2 = translateASTVarList(type);
// c2 是 translateASTVarList 返回的综合属性(ast)
// 3. 组合 (Synthesize)
root.addChild(typeNode); // c1.ast
root.addChild(c2); // c2.ast
// 4. 将组合后的新树作为自己的综合属性(ast)返回
return root;
}
2. 赋值语句 (Assignment Statement)
-
C++ 代码:
translateASTAssignmentStatement() -
文法:
<赋值语句> -> 标识符 赋值号 <表达式> -
AST 目标:
(assign [ID] [Expression]) -
属性流 (自底向上 + 语义检查):
-
Bottom-Up (综合属性):
- 这是 “结构化映射” 的经典例子。
translateASTAssignmentStatement被调用。- 它创建
idNode(例如a)。 - 它向下调用
translateASTExpression()。 translateASTExpression经过一系列复杂的递归,最终返回一个完整的表达式子树(例如(add b c))。这就是<表达式>.ast综合属性。translateASTAssignmentStatement接收这个子树 (存入node expression)。- 综合: 它将
idNode和expression挂在一个新根root(“assign”) 下。 - 返回:
root(即<赋值语句>.ast) 被返回。
-
语义动作 (使用Context):
- 在组合 AST 之前,它会检查上下文(
idenTable)以验证语义: if (!idenTable.identifierExists(name))- 这是一个在AST构建时发生的即时语义检查,它利用
idenTable(符号表)作为上下文,而不是通过参数传递。
- 在组合 AST 之前,它会检查上下文(
-
3. 条件语句 (Conditional Statement)
-
C++ 代码:
translateASTConditionalStatement() -
文法:
... if (<表达式>) <嵌套语句> else <嵌套语句> -
AST 目标:
(ifThenElse [Condition] [Then-Branch] [Else-Branch]) -
属性流 (纯自底向上):
- Bottom-Up (综合属性):
- 这是最纯粹的“填空”式综合。
- 它创建
condStmtNode("ifThenElse")。 - 调用 1:
translateASTExpression()被调用,它返回<表达式>.ast(存入node expression)。 - 调用 2:
translateASTNestedStatement()被调用,它返回<嵌套语句>_1.ast(存入nestedStmt1)。 - 调用 3:
translateASTNestedStatement()被调用,它返回<嵌套语句>_2.ast(存入nestedStmt2)。 - 综合: 它将这三个已完成的子树作为
ifThenElse节点的子节点。 - 返回:
condStmtNode(即<条件语句>.ast) 被返回。
- Bottom-Up (综合属性):
-
特点: 结构固定,没有歧义,只是简单地收集子节点返回的
.ast属性并组装。
4. 循环语句 (Loop Statement)
-
C++ 代码:
translateASTLoopStatement() -
文法:
while (<表达式>) : <嵌套语句> -
AST 目标:
(while [Condition] [Body]) -
属性流 (纯自底向上):
- 与
if语句完全相同,只是子节点从三个变成了两个。 - 调用 1:
translateASTExpression()被调用,返回<表达式>.ast(存入node expression)。 - 调用 2:
translateASTNestedStatement()被调用,返回<嵌套语句>.ast(存入nestedStmt)。 - 综合: 将
expression和nestedStmt挂在新根root(“while”) 下。 - 返回:
root(即<循环语句>.ast) 被返回。
- 与
5. 表达式 (Expression)
-
C++ 代码:
translateASTExpression(),translateASTH(),translateASTI(),translateASTD(),translateASTG(),translateASTE(), … -
文法: (一套处理
or,and,not,rel,+,-,*,/的复杂文法) -
AST 目标:
(add (mul a b) c)(对于a * b + c,需要正确的优先级和左结合) -
属性流 (自底向上 + 重构):
您的 C++ 代码在处理表达式时,完美地结合了我们之前讨论的两个算法:
-
算法1:用函数调用栈处理“优先级” (综合流)
translateASTExpression(处理or)- ->
translateASTConjunction(处理and) - ->
translateASTInversion(处理not) - ->
translateASTRelationExpression(处理rel) - ->
translateASTMathExpression(处理+,-) - ->
translateASTTerm(处理*,/) - ->
translateASTFactor(处理ID,整数,( )) - 这个调用链本身就编码了运算符的优先级。
Factor(优先级最高)在栈的最深处被解析。它返回 (综合) 它的node.ast,然后Term处理它,再返回,依此类推。
-
算法2:用树重构处理“左结合性” (综合流)
- 这仍然是代码中最精妙的部分,它处理
a + b + c这样的左结合链。 translateASTH(处理+,-),translateASTI(处理*,/),translateASTD(处理or),translateASTG(处理and) 全都使用了这个算法。- 追踪
a + b + c(在translateASTMathExpression中):- 它调用
translateASTTerm()得到a(返回c1 = (term a ...))。 - 它调用
translateASTH()来处理+ b + c(返回c2)。 - 深入
translateASTH()(+ b + c):op = "add",c1_H = (term b ...)(通过调用translateASTTerm获得)。- 递归调用
translateASTH()(+ c):op = "add",c1_H_inner = (term c ...)。- 递归调用
translateASTH()(空) -> 返回 (综合)(empty)。 c2是empty。它创建并返回 (综合)(add (term c ...))。
c2_H现在是(add (term c ...))。c2_H.root != "empty"。newFirstChild = (add (term b ...))。c2_H.getFirstLeftNonLeafChild(insertPoint)返回false(因为c是叶子)。c2_H.addNodeAsFirstChild(newFirstChild)。c2_H变为(add (add (term b ...)) (term c ...))。translateASTH返回 (综合) 这个(add (add ...))树。
- 回到
translateASTMathExpression:c1 = (term a ...)。c2 = (add (add (term b ...)) (term c ...))。c2.root != "empty"。c2.getFirstLeftNonLeafChild(insertPoint)返回true,insertPoint现在指向(add (term b ...))节点。insertPoint.addNodeAsFirstChild(c1)。c2(完整的树) 变为(add (add (term a ...)) (term b ...)) (term c ...))(这里假设add可以有多个孩子,或者getFirstLeft...找到了正确的add节点)。- 等等,让我重读您的
getFirstLeftNonLeafChildC# 逻辑… - (
pointer = children[0];
while(pointer.children.Count != 0) { lastPointer = pointer; pointer = pointer.children[0]; }
return lastPointer;
) - OK,C# 逻辑追踪:
c2 = (add (add (term b)) (term c))(简化版)insertPoint = c2.getFirstLeft...():pointer = (add (term b))while:lastPointer = (add (term b)),pointer = (term b)while:pointer.children.Count == 0-> 循环终止- 返回
lastPointer,即(add (term b))节点。
insertPoint.addNodeAsFirstChild(c1)(即(term a))insertPoint变为(add (term a) (term b))c2(完整的树) 变为(add (add (term a) (term b)) (term c))。
- 结论: 您的 C++ 代码完美地复现了 C# 中的左结合树重构算法。它仍然是一个纯粹的综合属性 (Bottom-Up) 流,但父节点不是简单地组合子节点,而是重构子节点返回的树,以确保正确的结合性。
- 它调用
- 这仍然是代码中最精妙的部分,它处理
-
总结对比
| 语句类型 | C++ 代码 | 属性流 (参数传递) |
|---|---|---|
| 声明语句 | translateASTDeclareStatement |
(1) 继承 (Top-Down): const string& type 被传递下去。(2) 综合 (Bottom-Up): node 对象被 return 回来。 |
| 赋值语句 | translateASTAssignmentStatement |
综合 (Bottom-Up): node 对象被 return 回来。 |
| 条件语句 | translateASTConditionalStatement |
综合 (Bottom-Up): 纯粹的结构化组合。if 节点收集三个 return 回来的 node。 |
| 循环语句 | translateASTLoopStatement |
综合 (Bottom-Up): 纯粹的结构化组合。while 节点收集两个 return 回来的 node。 |
| 表达式 | translateASTH, translateASTI, … |
综合 (Bottom-Up) + 重构: node 对象被 return,但父节点会修改子树的结构 (使用 getFirst...) 来保证左结合性。 |