小白說編譯原理-5-變數支援計算機

來源:互聯網
上載者:User

標籤:

簡介

本章依然專註於使用yacc實現計算機,主要的特點是給算術運算增加變數支援。

模組拆分

它主要分為3個模組
1. lex詞法分析器
2. yacc文法分析器
3. 符號表

功能描述1. lex詞法分析器

正規式的定義如下:

    delim [ \t]    ws    {delim}+    letter [a-zA-Z]    digit [0-9]    id    {letter}({letter}|{digit})*    /* can support 12.34 */    number {digit}+(\.{digit}+)?

相當於是給一些經常使用的Regex起一個別名,然後利用別名即可以構造更複雜的Regex。例如id標示符是由letter以及digit的組合形成的,表示必須以字母開頭,後面可以字母和數位任意組合。

詞法分析器的動作定義(轉換規則)

    {ws} {/* do nothing */}    "int"  {print_token(INT, yytext); return INT;}    "double"  {print_token(DOUBLE, yytext);}    "char"  {print_token(CHAR, yytext);}    "+"         {print_token(PLUS, yytext); return PLUS;}    "-"         {print_token(MINUS, yytext); return MINUS;}    "*"         {print_token(TIMES, yytext); return TIMES;}    "/"         {print_token(OVER, yytext); return OVER;}    "("         {return LP;}    ")"         {return RP;}    "\n"        {return EOL;}    "="         {return ASSIGN;}    {id}        {                    int p = sym_table.lookup(yytext);                    if(p == -1){//not find                        p = sym_table.insert(yytext);//insert the default value 0.0                    }                    yylval = p;//return the position                    return ID;                }    {number}    {yylval = atof(yytext);return NUMBER;}//yylval儲存數位值,NUMBER只是token標記    "//".*      {return COMMENT;}    "."         {printf("Mystery character %s\n", yytext); }

上述每一組代表一個轉換規則,對於一個規則,它的左邊代表要匹配的模式串,右邊表示要執行的詞法動作。例如對於規則 “+” {print_token(PLUS, yytext); return PLUS;}, 它表示在解析出”+”後,它將執行print_token,並返回PLUS標記(PLUS在yacc中定義)。

運算子識別:
從上面定義的規則可以看出,此詞法分析支援+,-,*,/,(,)這些基本的算術運算。

number的識別:
{number} {yylval = atof(yytext);return NUMBER;} //yylval儲存數位值,NUMBER只是token標記
不再像(小白說編譯原理-3)那樣,將number的識別放在yacc中,利用cin的方式得到數字,而是利用詞法分析的正規式的表達,將得到的結果賦值給yylval**(yylval = atof(yytext))**,然後返回NUMBER標記。

標示符的識別:
這個規則的執行動作比較複雜,它利用了一個符號表的模組(後面講述),當識別到標示符後,它向符號表中尋找(沒找到,就插入一條)並返回它的位置資訊。

        {id}        {                        int p = sym_table.lookup(yytext);                        if(p == -1){//not find                            p = sym_table.insert(yytext);//insert the default value 0.0                        }                        yylval = p;//return the position                        return ID;                    }

yytext是標示符的字串,p儲存它在符號表的位置,當找到後將位置資訊賦值給yylval,同時返回標示符類型ID。 yylval和ID資訊都會在yacc實現中用到。

2. yacc文法分析器

token定義如下:

    %token NUMBER ID    %token PLUS MINUS TIMES OVER    %token LP RP EOL COMMENT    %TOKEN INT DOUBLE CHAR    %token ASSIGN    %left PLUS MINUS    %left TIMES OVER    %right UMINUS

上述定義的token在lex詞法分析器中使用。

yacc文法轉換規則定義如下:

    lines   :   lines expr EOL  { printf("%g\n", $2); }            |   lines EOL            |   lines COMMENT            |               ;    expr    :   expr PLUS expr  { $$ = $1 + $3; }|expr MINUS expr{ $$ = $1 - $3; }|expr TIMES expr{ $$ = $1 * $3; }|expr OVER expr{ $$ = $1 / $3; }|LP expr RP{ $$ = $2; }|‘-‘ expr %prec UMINUS{ $$ = -$2; }|NUMBER {$$=$1;} //$$=$1 can be ignored            |   ID {$$ = sym_table.getValue($1);}//get value from sym_table|   ID ASSIGN expr {sym_table.setValue($1, $3); $$=$3; }//modify the value

與詞法分析器類似的是依然是根據規則是否匹配,然後執行相應的文法動作,具體請參見小白說編譯原理-3(http://blog.csdn.net/lpstudy/article/details/51225953)中的yacc的描述。

數位動作:
NUMBER {$$=$1;} //$$=$1 can be ignored
它在識別出數字之後,將此數位值(詞法分析器得到的yylval)賦值給$$,$$表示當前結果。
注意$1表示是第一個對應的文法規則中第一個token的value,同理,對於$2,$3也是如此,表示第2個,第3個token的value。 而對於本規則,$1就是NUMBER的value。這個value是在詞法分析中賦值的yylval(yylval=atof(yytext))。

標示符的動作:
標示符的動作分為兩類,一種是賦值動作,一種是取值動作。 例如a=2,這表示給變數a賦值為2, 然後a+4表示將a變數加上4,因此結果為6. 簡單起見,本程式不考慮變數的定義操作(例如c語言中的int a;),所有的變數預設值為0.0,可直接使用,可使用賦值運算修改它的值。

賦值動作
ID ASSIGN expr {sym_table.setValue($1, $3); $$\=\$3; }//modify the value
上述規則表明如果遇到a=2這樣的輸入後,會執行符號表的setValue方法,\$1表示詞法分析器返回ID時候設定的yylval值(標示符的位置), \$3表示文法分析中expr的結果,這樣setValue就會將\$1位置上的標示符設定為\$3.
取值動作
ID {\$\$ = sym_table.getValue(\$1);}//get value from sym_table
上述規則說明:首先詞法分析器返回的ID標示符,同時\$1中儲存標示符的位置,根據位置取出相應的value並賦值給\$\$當前值。

lex和yacc協同策略
lex傳遞到yacc兩個重要的資訊,類型和值, 類型由return實現,值由yylval儲存。
yacc中的文法規則碰到的token標記是由lex的return得到的,而通過$number取值實際上取出的是lex中的yylval值。
$1和$3這種是根據前面規則中標記的位置來確定1和3的,它們的值或者由詞法分析器通過yylval給出,或者由賦值$$得到。例如 ID ASSIGN expr中expr的值為$3,它不是由詞法分析器給出的,而是使用了expr進行分析時候得到的$$值。

3. 符號表

符號表是支撐詞法和文法分析的資料儲存區。 詞法分析過程中遇到id標示符,需要將其插入到符號表中,並設定預設值為0.0, 文法分析過程中遇到取值id標示符,使用符號表提供的存取子得到符號的值,當遇到賦值id,則更新符號表中對應符號的值。範例程式碼,使用數組進行了簡單實現。

    #include <iostream>    #include <map>    #include <vector>    #include "yacc.h"    #include "lex.h"    using namespace std;    struct Node    {        string name;        double value;    };    class SymTable    {    public:        SymTable(){        }    public:        int lookup(const string& name){            for (int i = 0; i < idValueTable.size(); ++i)            {                if(idValueTable[i].name.compare(name) == 0){                    return i;                }            }            return -1;//not find        }        int insert(const string& name){//when parser x=2 (current we get x)            Node node;            node.name = name;            node.value = 0.0;            idValueTable.push_back(node);            return idValueTable.size()-1;        }        void setValue(int pos, double value){//when parser x=2 (current we get x)            idValueTable[pos].value = value;        }        double getValue(int pos){            return idValueTable[pos].value;        }    private:        vector<Node> idValueTable;    };    extern SymTable sym_table;
運行效果

本人lpstudy,轉載請註明出處: http://blog.csdn.net/lpstudy/article/details/51328851

小白說編譯原理-5-變數支援計算機

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.