【问题标题】:Parsing data into structures using bison使用 bison 将数据解析为结构
【发布时间】:2020-06-11 05:07:01
【问题描述】:

暑假我在学校学习了 flex 和 bison,现在我想更深入地了解一下。我无法理解 Bison 3.0.2 的文档。也许你们中的一些人可以帮助我。我想解析一个表示方程的字符串,同时填写一个数据结构,其中包含有关已解析内容的信息。例如,假设我有 (ax+b)^2。我希望解析器生成一个包含字符串和整数常量的结构,如下所示。

(  BEGINGROUP
a  VARIABLE
x  VARIABLE
+  ADDITION
b  VARIABLE
)  ENDGROUP

我已经使用 flex 创建了一个语言规范,并且我已经使用 bison 创建了一个语法。所需要的只是让两者将信息放入结构中。我有一些代码以我想要的方式工作,但我不禁认为我错过了一些东西。在 Bison 文档示例中,我看到他们使用 $$ 或 $1 来检查语义值?当我打印语义值时,我总是得到零。不管怎样,我的代码贴在下面。

数学.l

%{
 #include "equation.h"

Equation* equ;
void setEquation(Equation* equation) {
    equ = equation;
}
%}

/* Definitions */
space     [ \t]
digit     [0-9]
letter    [a-zA-Z]
number    ({digit}+|{digit}+"."{digit}+|"."{digit}+|{digit}+".")
variable  {letter}

/* actions */
%%
{space}      ;
{number}     equ->addElement(yytext, Equation::number); return(1);
{variable}   equ->addElement(yytext, Equation::variable); return(2);  
"+"          equ->addElement(yytext, Equation::addition); return(10); /* Basic operators */
"-"          return(11);
"*"          return(12);
"/"          return(13);
"^"          return(14);
"log"        return(15); 
"sin"        return(20); /* Trigonometric Functions */
"cos"        return(21);
"tan"        return(22);
"csc"        return(23);              
"sec"        return(24);
"cot"        return(25);
"arcsin"     return(26);
"arccos"     return(27);
"arctan"     return(28); 
"("          equ->addElement(yytext, Equation::begGroup); return(30); /* Grouping Operators */
")"          equ->addElement(yytext, Equation::endGroup); return(31);
"["          return(32);
"]"          return(33);
","          return(34);
.            fprintf(stderr, "Error on character %s\n", yytext);

数学.y

/*
* Implement grammer for equations
*/
%{
#include "lex.yy.c"
#include "equation.h"
#include <iostream>

int yylex(void);
int yyerror(const char *msg);

void output(const char* where) {
    std::cout << where << ": " << yytext << std::endl;
}
%}

%token e_num       1
%token e_var       2
%token e_plus     10
%token e_minus    11
%token e_mult     12
%token e_div      13
%token e_pow      14
%token e_log      15 
%token e_sin      20
%token e_cos      21
%token e_tan      22
%token e_csc      23              
%token e_sec      24
%token e_cot      25
%token e_asin     26
%token e_acos     27
%token e_atan     28 
%token lparen     30
%token rparen     31
%token slparen    32
%token srparen    33
%token comma      34
%start Expression
%%

Expression : Term  MoreTerms 
           | e_minus Term MoreTerms
           ;
MoreTerms  : /* add a term */
             e_plus Term MoreTerms
           | /* subtract a term */
             e_minus Term MoreTerms
           | /* add a negetive term */
             e_plus e_minus Term MoreTerms /* Add a negetive term */
           | /* minus a negetive term */
             e_minus e_minus Term MoreTerms /* Subtract a negetive term */
           | /* no extra terms */
           ;
Term       : Factor MoreFactors {equ->addElement("*", Equation::multiplication)};
           ;
MoreFactors: e_mult Factor MoreFactors
           | e_div  Factor MoreFactors
           | Factor MoreFactors
           |
           ;
Factor     : e_num { std::cout << $1 << std::endl; } //returns zero no matter where I put this
           | e_var
           | Group 
           | Function 
           ;
BeginGroup : lparen | slparen; 
EndGroup   : rparen | srparen;
Group      : BeginGroup Expression EndGroup 
              ;

Function   : TrigFuncs
           | PowerFunc
           ;
TrigFuncs  : e_sin lparen Expression rparen
           | e_cos lparen Expression rparen
           | e_tan lparen Expression rparen
           | e_csc lparen Expression rparen
           | e_sec lparen Expression rparen
           | e_cot lparen Expression rparen
           | e_asin lparen Expression rparen
           | e_acos lparen Expression rparen
           | e_atan lparen Expression rparen
           ;
PowerFunc  : e_num e_pow Factor
           | e_var e_pow Factor
           | Group e_pow Factor
           | TrigFuncs e_pow Factor
           ;

我认为我在做什么很清楚。如您所见,扫描器将 yytext 与其代码一起存储到方程类中,但有时解析器必须将信息添加到方程类中,这就是事情变得忙碌的地方。一方面,试图在语句之前或中间添加代码会导致大量的移位/减少冲突。其次,将代码放在语句末尾的效果是乱序记录。查看术语的规则。如果我输入“ax”,这隐含的意思是“a”乘以“x”或“a*x”。我希望解析器将乘法添加到我的结构中,但是解析器不按顺序执行此操作。那么有没有更好的方法来实现我的目标?

【问题讨论】:

    标签: c++ bison


    【解决方案1】:

    您可能想知道为什么在四个月内没有人回答您的问题;当计算器看起来如此简单的问题时。这是因为这不是一个简单的问题要回答。它是一个问题的组合,有很多隐藏的角落和缝隙供粗心的人使用。现在有不少野牛专家为 Stack Overflow 上的答案做出了贡献,他们真正了解他们的东西,而且他们都像瘟疫一样避免了这种情况。如果您简化了问题并一次只询问一件事,您可能会得到一些答案,但您只是粘贴了整个代码并丢弃了一些“哦,顺便说一句,在您解决其他所有问题时”重来!”。但是,如果有人想调试您的代码,他们就无法调试,因为您错过了一大堆关键的东西,比如 Equation 对象。 StackOverflow 不是你知道的一堆免费编码器!阅读一些guidance

    让我们从简单的开始;这 $$$1 你开始的东西。您称它们为“语义值”。并不真地。它们是一种通过解析树将值传回的机制,也是词法分析器关联一个令牌值以提供给解析器的机制。你总是得到一个零的原因是你从来没有在词法分析器中分配任何值。该值是通过引用内置变量yylval 来分配的。那是在文档中。让我们使用您的号码词位,它返回一个e_num 令牌。我可以写这个(math.l):

    {number}     {yylval = atoi(yytext);return(e_num);}
    

    这允许我们现在打印数字的值:

    Factor     : e_num { std::cout << $1 << std::endl; }
    

    如果您使用枚举常量的名称而不是那些绝对值,它看起来会更好。像这样硬连线这些数字的编码非常糟糕。

    我还看到您已经创建了堆栈并在词法分析器中将内容推送到它上面。可能不是一个好计划,但现在让我们开始吧。如果需要,您可以将令牌与这样的对象值相关联。 %union 构造(在野牛中)用于:

    %union {
    Equation* TokenValue;
    }
    

    现在您必须开始输入语法的终结符和非终结符:

    %token <TokenValue> e_enum;
    

    但现在我们可以根据需要使用这些结构来获取值:

    {number}    {equ->addElement(yytext, Equation::number); 
                yylval.TokenValue = equ;
                return(e_num);
                }
    

    在野牛中:

    Factor     : e_num { std::cout << $1->ElementText << std::endl; }
    

    在野牛语法中,您可能希望将多个值从规则的右侧传回左侧。这就是 $$ = $2 形式的构造将被使用的地方,但我会让你继续阅读。

    接下来要提到的是您描述算术表达式语法的方式。有两个问题,主要是否定句的处理和语法形式。

    这里需要bit of computer science。您(主要)将表达式表示为运算符和操作数的列表,这被视为 Regular LanguageChomsky Type 3 形式。问题在于算术表达式主要嵌套在结构中。嵌套需要上下文无关语法Chomsky Type 2。这就是所有计算器语法示例都使用以下形式的原因:

    exp : exp OP exp

    而不是您使用的列表形式。

    现在您已经使用规则层次结构来获取语法中运算符的一些优先级,但不幸的是,一元减法(或否定)运算符的优先级高于二元减法运算符,因此应该出现在 @987654337 @ 规则。这就是为什么你会遇到如此多的 shift/reduce 冲突的原因。这不是正确的方法。所有教科书都以与您的示例不同的方式使用计算器和表达式是有原因的。你需要回到教科书。

    这就是人们在大学学习这些东西的原因。希望对以后遇到类似问题的读者有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-25
      • 1970-01-01
      • 2021-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多