Lua新手求教:如何为Hello-World函数构建抽象语法树(AST)
Hey there! I totally get how ASTs can feel overwhelming when you're starting out—let's break this down step by step so you can see exactly how your code maps to a tree structure. First, let's recap your code for reference:
function foo() value = 10 num = "to the" if value > 2 then print("Hello World") end return value end print(foo())
Core Idea of ASTs
Think of an AST as a structured "blueprint" of your code, where every piece of syntax (like a function definition, assignment, or if statement) becomes a node in the tree. Each node has a type (e.g., FunctionDefinition, Assignment) and may have child nodes that represent its parts.
Step-by-Step AST Breakdown
Let's start from the top level and drill down into each part:
1. Top-Level Program Node
This is the root of your AST, and it contains two child nodes:
- A
FunctionDefinitionnode forfoo() - A
CallExpressionnode forprint(foo())
2. FunctionDefinition Node (for foo)
This node represents your entire function. It has three key parts:
- Name:
foo(aIdentifiernode) - Parameters: An empty list (since
footakes no arguments) - Body: A
Blocknode containing all the statements insidefoo()
The Block node has these child nodes (in order):
- Assignment node 1:
value = 10 - Assignment node 2:
num = "to the" - IfStatement node: The conditional check and its body
- ReturnStatement node:
return value
3. Assignment Nodes
Each assignment is a node with two children:
- Left-hand side: An
Identifiernode (the variable name:valueornum) - Right-hand side: A
Literalnode (the value being assigned:10is aNumericLiteral,"to the"is aStringLiteral)
Example for value = 10:
Assignment ├─ Identifier: "value" └─ NumericLiteral: 10
4. IfStatement Node
This node has two main parts:
- Condition: A
BinaryExpressionnode representingvalue > 2- Operator:
> - Left operand:
Identifiernode (value) - Right operand:
NumericLiteralnode (2)
- Operator:
- Body: A
Blocknode containing oneCallExpressionnode (print("Hello World"))
The CallExpression for print("Hello World") has:
- Callee:
Identifiernode (print) - Arguments: A list with one
StringLiteralnode ("Hello World")
5. ReturnStatement Node
This node has one child: an Identifier node (value), representing the value being returned.
6. Top-Level CallExpression Node (print(foo()))
This is the final line of your code. It's a CallExpression with:
- Callee:
Identifiernode (print) - Arguments: A list containing another
CallExpressionnode (callingfoo()):- Callee:
Identifiernode (foo) - Arguments: Empty list
- Callee:
Visualizing the Tree Structure
If you were to draw this out, it would look something like this (simplified):
Program ├─ FunctionDefinition │ ├─ Identifier: "foo" │ ├─ Parameters: [] │ └─ Block │ ├─ Assignment │ │ ├─ Identifier: "value" │ │ └─ NumericLiteral: 10 │ ├─ Assignment │ │ ├─ Identifier: "num" │ │ └─ StringLiteral: "to the" │ ├─ IfStatement │ │ ├─ BinaryExpression (>) │ │ │ ├─ Identifier: "value" │ │ │ └─ NumericLiteral: 2 │ │ └─ Block │ │ └─ CallExpression │ │ ├─ Identifier: "print" │ │ └─ Arguments: [StringLiteral: "Hello World"] │ └─ ReturnStatement │ └─ Identifier: "value" └─ CallExpression ├─ Identifier: "print" └─ Arguments: └─ CallExpression ├─ Identifier: "foo" └─ Arguments: []
Key Takeaway
Every line (and even parts of lines) of your code maps to a specific node type. Once you start matching syntax to node types, building ASTs becomes much more intuitive. Try picking apart smaller pieces of code first, then combine them into a full tree—you've got this!
内容的提问来源于stack exchange,提问作者verrrilog

