通常,编写解析器的目的是最终得到表示输入的数据结构。然后,您可以以某种方式转换结构,或者,在您的情况下,只需将其打印出来。
在每个表达式生成中,您希望在该结构中构造一个节点来表示您到目前为止所识别的内容。
我有点生疏了,但它会是这样的:
query: /* empty */
| query expression { printNode($2); /* printf()s are in here */ }
;
expression: term { $$ = makeTermNode($1); }
| expression OR term { $$ = makeOrNode($1, $3); }
| expression AND term { $$ = makeAndNode($1, $3); }
;
保存节点的数据结构:
struct Node {
int nodeType; /* WORD or operator token like AND, OR */
node* leftOperand;
node* rightOperand; /* will be null if the node is a term */
}
%union
{
int number;
char *string;
Node *node;
}
Update:
我已经有一段时间没有用 C 编写代码了,所以我不得不求助于伪代码。这里没有代码可以在我们使用完内存后回收内存。对任何其他错误表示歉意。
struct Node *makeTermNode(int word) {
Node *node = malloc(sizeof struct Node);
node->nodeType = word;
node->rightOperand = null;
node->leftOperand = null;
return node;
}
请注意,您的 WORD 标记仅表示扫描了某种类型的字母串;特定的字母顺序将被丢弃。 (如果您想知道序列,请让您的词法分析器返回 yytext 的副本而不是 WORD 标记。)
struct Node *makeAndNode(struct Node* leftOperand, struct Node *rightOperand) {
Node *node = malloc(sizeof struct Node);
node->nodeType = AND;
node->leftOperand = leftOperand;
node->rightOperand = rightOperand;
return node;
}
makeOrNode() 也是如此。或者,您可以只编写 makeNodeWithOperator(int operator, struct Node* leftOperand, struct Node *rightOperand) 来处理“and”和“or”情况。
我将 printAllNodes() 更改为 printNode()。它从我们构建的表达式树结构的根部开始,首先递归访问每个子表达式的左侧,然后是右侧。事情是这样的:
void printNode (struct Node* node) {
switch (node->nodeType) {
case WORD:
printf("%i", node->nodeType);
return;
case AND:
case OR:
printf("(");
printNode(node->leftOperand);
printf("%i", node->nodeType);
printfNode(node->rightOperand);
printf(")");
return;
}
}