【发布时间】:2021-05-29 17:58:36
【问题描述】:
我尝试从 PackCC 的计算器示例中打印 AST 表示。
我添加了一个“节点”对象和函数来编写一个点文件。
这似乎适用于 '+' 和 '-' 表达式,但当我混合使用 '+' 和 '*' 时,结果出乎意料。
请注意这两个操作有不同的优先级,如果它可以帮助你的话。
这是语法文件。
%prefix "calc"
%value "Node*" # The type of "$$" values.
###############################################################################
%header{
typedef struct Node {
const char* data;
struct Node* l_child;
struct Node* r_child;
}Node;
Node* node(const char* text, Node* left, Node* right);
void dot_graph(char* name, Node* root);
}
###############################################################################
%source {
#include <stdio.h>
#include <stdlib.h>
Node* node(const char* text, Node* left, Node* right)
{
Node* res = malloc(sizeof (Node));
res->data = text;
res->l_child = left;
res->r_child = right;
return res;
}
void fill_dot(FILE* f, Node* n, Node* parent, int parentNum)
{
static int currentNum; // This number will be printed to make unique names.
// Lines that represents nodes.
if (parent == NULL) {
fprintf(f, " node%d [label=\"%s\"]\n", currentNum, n->data);
}
else {
fprintf(f, " node%d [label=\"%s\"]\n", currentNum, n->data);
fprintf(f, " node%d -- node%d\n", parentNum, currentNum);
parentNum += 1;
}
currentNum += 1;
if (n->l_child != NULL) {
fill_dot(f, n->l_child, n, parentNum);
}
if (n->r_child != NULL) {
fill_dot(f, n->r_child, n, parentNum);
}
parentNum -= 1;
if( parentNum == -1) // Hopefully the end of the recursion.
currentNum = 0;
}
void dot_graph(char* name, Node* root)
{
FILE* res = fopen(name, "w");
if (res == NULL) {
printf("File problem: %s\n", name);
exit(1);
}
fprintf(res, "graph {\n"); // Opens the dot file
fill_dot(res, root, NULL, 0); // fills with the nodes.
fprintf(res, "}\n"); // Close the dot file.
fclose(res);
}
}
###############################################################################
statement <- _ e:expression _ EOL { $$ = e; puts("Expression parsed");}
/ ( !EOL . )* EOL { printf("error\n"); }
expression <- e:term { $$ = e; }
term <- l:term _ < '+' > _ r:factor { $$ = node(strdup($1), l, r); }
/ l:term _ < '-' > _ r:factor { $$ = node(strdup($2), l, r); }
/ e:factor { $$ = e; }
factor <- l:factor _ < '*' > _ r:unary { $$ = node(strdup($1), l, r); }
/ l:factor _ < '/' > _ r:unary { $$ = node(strdup($2), l, r); }
/ e:unary { $$ = e; }
unary <- < '+' > _ e:unary { $$ = node(strdup($1), e, NULL ); }
/ < '-' > _ e:unary { $$ = node(strdup($2), e, NULL ); }
/ e:primary { $$ = e; }
primary <- < [0-9]+ > { $$ = node(strdup($1), NULL, NULL); }
/ '(' _ e:expression _ ')' { $$ = e; }
_ <- [ \t]*
EOL <- '\n' / '\r\n' / '\r' / ';'
%%
int main() {
Node* root = node("", NULL, NULL);
calc_context_t *ctx = calc_create(NULL);
while (calc_parse(ctx, &root)) { // The root node will be "extended" by childs during parsing.
}
dot_graph("calc.dot", root);
calc_destroy(ctx);
// No "free" for the nodes to shorten this file.
return 0;
}
运行 packcc、编译和运行解析器的命令。
./packcc calc.peg && gcc calc.c && ./a.out
如果你在 linux 上查看图表的命令。
dot -Tx11 calc.dot
我想知道问题出在解析器操作上还是出在我设计得很痛苦的点式打印机上。
【问题讨论】: