野牛和lex字符串vs char

时间:2009-10-11 20:50:20

标签: yacc bison lex

我正在尝试评估和表达表格

#SomeFunc[expr][expr]expr

expr可以是由某些字符组成的字符串,也可以是上述函数。所以这可能看起来像

#SomeFunc[#SomeFunc[#SomeFunc[nm^2][nn]][nm]][n]...

问题在于,如果我以

的形式制作代币
"#"SomeFunc    {yylval.fn=F_some; return FUNC;}
m|n|ms         {return TEXT;}
"^"            {yylval.fn=F_pow;  return FUNC;}
[1-9]+         {yylval=atoi(yytext); return NUMBER;}

如果我有像

这样的东西,我就会遇到构建语法的问题
#SomeFunc[#SomeFunc[nm^2][nn]][n]

calc:
      | calc expr EOL { eval($2); }

expr: TEXT {$$= add it to ast-leaf }
      | FUNC '[' expr ']' '[' expr ']' {$$= add ast(func,$3,$6) }
      | expr expr {$$= add to ast('*',$1,$2 }

我不太确定语法是错误的还是我的AST实现。

我发现我的逻辑有缺陷,因为在nm expr的情况下将是expr expr,它将返回仍为nm的n * m的值。这会导致无限循环吗?我该如何解析这样的表达。

不要扔石头。野牛新手

稍后修改 我设法清理并测试了AST和一些链接列表背后的代码。唯一的问题仍然是语法。

%union { struct ast *a; char *strval; int ival; } 
%type <a> exp fact 
%token <strval> ISU 
%token <ival> NUMBER 
%token FUNC POW 
%token EOL OP CP 

%% 

calclist: | calclist exp EOL { printf("result >",eval($2));}; 

exp: fact | exp fact {$$ = newast('*', $1,$2);} ; 

fact: FUNC OP exp CP OP exp CP { $$ = newast('/',$3,$6);}
    | ISU POW NUMBER { $$ = newnum($1, $3);}
    | ISU { $$ = newnum($1,1);};  

这个语法对于像Frac [m ^ 2] [m ^ 4]节点/节点K m ^ 4节点K m ^ 4

这样的expr失败了

2 个答案:

答案 0 :(得分:0)

我简化了语法来表达基本形式,而不一定是它们可能被组合的方式。 (为了简化实验,我也删除了生成的词法分析器,因此在我的所有函数中都称为'f',只要它是'2',你就可以得到任何你想要的数字。)

在各种测试用例中,这似乎对我很有用:请注意除了calc之外的所有规则都是递归的,这就是你想要的yacc。

cat subcity.y && yacc subcity.y && cc -w y.tab.c -ly 
%%
calc: | calc expr '\n';
expr: | expr form
      | expr operator form;
form: mns | '[' expr ']' | digit | 'f';
mns: 'm' | 'n' | 's';
digit: '2';
operator: '^' | '+' |  '-' | '*' | '/';
%%
int yylex(void) { int c; while ((c = getchar()) == ' ') continue; return c; }
int main(int ac, char **av) { if (yyparse() != 0) printf("parse error\n"); }

似乎有效:

$ ./a.out
f[ f[ f[nm^2] [nn]] [nm]] [n]
f[f[2]] [f[f[nm^2]f]]
f[f[nm^2][nn]][n]
f[m^2][m^2] n / n 2 m^2 n 2 n^2
$ 

我无法弄清楚你对你的第一个语法不喜欢什么,但我希望这会给你一些想法。更像这样的东西当然是 I 的开头。你的语法以运算符未连接的相邻表达式为特征这一事实有点奇怪。终端符号更常见,就像字符串在某些语言中连接的方式一样。有些人会发明一个操作员来消除这种情况。

答案 1 :(得分:0)

根据你的描述,你希望“^ 2”是一个有效的expr,但是你的lex规则返回FUNC代表'^'而NUMBER代表'2',但是在你的语法中,FUNC必须后跟'['in您拥有的唯一规则,并且您没有NUMBER规则。你可能想要一个规则“expr:NUMBER”,但是你还需要一个规则“expr:FUNC expr”然后匹配“^ 2”,所以看起来你可能想要'^'返回其他一些令牌。