簡體   English   中英

使用 bison 將數據解析為結構

[英]Parsing data into structures using bison

暑假期間,我在學校學習了 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”。 我希望解析器將乘法添加到我的結構中,但解析器不按順序執行此操作。 那么有沒有更好的方法來實現我的目標?

您可能想知道為什么四個月內沒有人回答您的問題; 當計算器似乎是一個如此簡單的問題時。 這是因為這不是一個簡單的問題。 它是一個問題的綜合體,對於粗心的人來說,有許多隱藏的角落和縫隙。 現在有不少野牛專家在 Stack Overflow 上提供答案,他們真正了解他們的東西,他們都像瘟疫一樣避免了這種情況。 如果你簡化了問題,一次只問一件事,你可能會得到一些答案,但你只是粘貼了整個代碼,然后加上了一些“哦,順便說一句,在你的時候修復其他一切”重新開始!”。 但是,如果有人想調試您的代碼,他們無法調試,因為您錯過了一大堆關鍵內容,例如Equation對象。 StackOverflow 不是一堆你知道的免費編碼器! 閱讀一些指南

讓我們從簡單的事情開始; 你開始使用的這個$$$1東西。 你稱它們為“語義值”。 並不真地。 它們是一種通過解析樹將值傳回的機制,也是詞法分析器將標記值關聯起來以提供給解析器的機制。 你總是得到零的原因是你從來沒有在詞法分析器中為它分配任何值。 該值是通過引用內置變量yylval來分配的。 那是在文檔中。 讓我們拿你的數字e_num返回一個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形式的構造的地方,但我會讓你閱讀它。

接下來要提到的是您描述算術表達式語法的方式。 有兩個問題,主要是否定句的處理和語法形式。

這里我們需要一些計算機科學 您已(主要)將表達式表示為運算符和操作數列表,這被視為正則語言Chomsky Type 3形式。 問題是算術表達式主要是嵌套在結構中。 嵌套需要Context Free GrammarChomsky Type 2 這就是為什么所有計算器語法示例都使用以下形式的原因:

exp : exp OP exp

而不是您使用的列表表格。

現在您已經使用規則層次結構來獲得語法中運算符的一些優先級,但不幸的是,一元減(或否定)運算符的優先級高於二元減法運算符,因此應該出現在Factor規則中。 這就是為什么您會遇到如此多的 shift/reduce 沖突的原因。 這不是正確的方法。 所有教科書都以與您的示例不同的方式進行計算器和表達式,這是有原因的。 你需要回到課本上。

這就是人們在大學學習這些東西的原因。 我希望對未來正在研究類似問題的一些讀者有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM