在Bison Parser中解决混乱的优先级

时间:2019-05-04 06:19:35

标签: parsing compiler-construction abstract-syntax-tree bison operator-precedence

我目前正在为自己的语言构建解析器,但是我在使用优先级时遇到了麻烦(我认为这就是问题所在)。我仅在构建AST时才发现此问题。我定义了以下标记:

%token T_SEMICOLON T_COMMA T_PERIOD T_RETURN T_BOOLEAN T_EXTENDS T_TRUE T_FALSE T_IF T_DO T_NEW T_ELSE T_EQUALSSIGN T_PRINT T_INTEGER T_NONE T_WHILE T_NUMBER T_VARIABLE T_LEFTCURLY T_RIGHTCURLY T_LEFTPAREN T_RIGHTPAREN T_ARROW T_EOF

%left T_OR
%left T_AND
%left T_MINUS T_EQUALSWORD T_PLUS 
%left T_GE T_GEQ
%left T_MULTIPLY T_DIVIDE
%right T_NOT

(在这种情况下,只有优先级才重要),我有一个采用以下形式的语法

Something: T_PRINT expression T_SEMICOLON

我有几个表达作品,其中一些是

expression        : expression T_PLUS expression         {$$ = new PlusNode($1, $3);}                             
                  | expression T_MINUS expression        {$$ = new MinusNode($1, $3);} 
                  | expression T_EQUALSWORD expression   {$$ = new EqualNode($1, $3);}          
                  | expression T_MULTIPLY expression     {$$ = new TimesNode($1, $3);}           
                  | expression T_DIVIDE expression       {$$ = new DivideNode($1, $3);} 
                  | T_NOT expression                     {$$ = new NotNode($2);}                               
                  | T_MINUS expression                   {$$ = new NegationNode($2);}                
                  | T_VARIABLE                           {$$ = new VariableNode($1);} 
                  | T_NUMBER               {$$ = new IntegerLiteralNode($1);}                         
                  | T_TRUE                 {$$ = new BooleanLiteralNode(new IntegerNode(1));}                                      
                  | T_FALSE                {$$ = new BooleanLiteralNode(new IntegerNode(0));}                         
                  | T_NEW T_VARIABLE       {$$ = new NewNode($2, NULL);}

当我尝试解析类似print true equals new c0 - new c0;的内容时,我得到了一个奇怪的输出AST,看起来像Print(Minus(Equal(BooleanLiteral(1), New("c0")), New("c0")))。即使我另行定义,这里看起来T_EQUALSWORD令牌的优先级也比T_MINUS令牌高?

如果我将减号更改为加号,也会发生此问题;输入print true equals new c0 + new c0;得到Print(Equal(BooleanLiteral(1), GreaterEqual(New("c0"), New("c0"))))作为输出。表单似乎正确,但由于某种原因我正在获取T_GEQ令牌而不是T_PLUS?

有趣的是,它可以正确解析T_MULTIPLY和T_DIVIDE:

输入:print true equals new c0 * new c0;

输出:Print(Equal(BooleanLiteral(1), Times(New("c0"), New("c0"))))

输入:print true equals new c0 / new c0;

输出:Print(Equal(BooleanLiteral(1), Divide(New("c0"), New("c0"))))

因此,这似乎可以与乘法和除法一起正常使用,但不能通过加号和减号来解决。有什么想法吗?

编辑:我在T_EQUALSWORD生产中添加了%prec T_OR,这在我使用减法时解决了这个问题,但是当我使用加法时,我仍然得到了奇怪的T_GEQ令牌。

1 个答案:

答案 0 :(得分:3)

此行

%left T_MINUS T_EQUALSWORD T_PLUS 

表示这三个运算符具有相同的优先级,并且从左到右关联。您得到的第一个结果与此一致。

a - b - c     (a - b) - c     # Left associative
a - b = c     (a - b) = c     # Also left associative
a = b - c     (a = b) - c     # Once again

如果您希望等式的优先级较低,请为其指定优先级。

第二个问题是生成了错误的令牌,可能是因为您的扫描仪生成了错误的令牌。