表示式求值

2021-05-09 22:18:48 字數 4741 閱讀 4666

既然是表示式求值,自然需要在記憶體中儲存計算結果以及中間值。在《用c語言寫直譯器(一)》中提過:變數要求是若型別,而 c 語言中的

view plaincopy to clipboardprint?

// in basic_io.h  

#define memery_size (26)  

typedef enum variant_type;  

typedef char string[128];  

typedef struct ;  

} variant;  

extern variant memery[memery_size];  

// in expression.h  

typedef variant operand; 

// in basic_io.h

#define memery_size (26)

typedef enum variant_type;

typedef char string[128];

typedef struct ;

} variant;

extern variant memery[memery_size];

// in expression.h

typedef variant operand;

程式自帶 a-z 26個可用變數,初始時都處於未賦值(ver_null)狀態。所有變數必須先賦值再使用,否則就會報錯!至於賦值語句的實現請參

見後面語法分析的章節。

操作符表示式中光有數值不行,還需要有操作符。在《一》中「表示式運算」一節已經給出了直譯器需要實現的所有操作符,包括「算術運算」、「

關係運算」和「邏輯運算」。下面給出程式中操作符的定義和宣告:

view plaincopy to clipboardprint?

// in expression.h  

typedef enum operator_type;  

typedef enum associativity;  

typedef struct operator;  

// in expression.c  

static const operator operators = ,     // 左括號  

,    // 右括號  

,      // 加  

,     // 減  

,  // 乘  

,    // 除  

,       // 模  

,     // 冪  

,  // 正號  

,  // 負號  

, // 階乘  

/* 關係運算 */ 

,        // 小於  

,        // 大於  

,          // 等於  

,          // 不等於  

,        // 不大於  

,        // 不小於  

/* 邏輯運算 */ 

,         // 且  

,          // 或  

,       // 非  

/* 賦值 */ 

// basic 中賦值語句不屬於表示式!  

,  // 賦值  

/* 最小優先順序 */ 

// 棧底  

}; 

// in expression.h

typedef enum operator_type;

typedef enum associativity;

typedef struct operator;

// in expression.c

static const operator operators = ,     // 左括號

,    // 右括號

,      // 加

,     // 減

,  // 乘

,    // 除

,       // 模

,     // 冪

,  // 正號

,  // 負號

, // 階乘

/* 關係運算 */

,        // 小於

,        // 大於

,          // 等於

,          // 不等於

,        // 不大於

,        // 不小於

/* 邏輯運算 */

,         // 且

,          // 或

,       // 非

/* 賦值 */

// basic 中賦值語句不屬於表示式!

,  // 賦值

/* 最小優先順序 */

// 棧底

};你也許會問為什麼需要 icp(incoming precedence)、isp(in-stack precedence) 兩個優先順序,現在不用著急,以後會詳細解釋!

字尾表示式

現在運算元(operand)和操作符(operator)都有了,乙個表示式就是由它們組合構成的,我們就統稱它們為標記(token)。在程式中定義

如下:view plaincopy to clipboardprint?

// in expression.h  

typedef enum token_type;  

typedef struct ;  

} token;  

typedef struct tlist token_list, *ptlist; 

// in expression.h

typedef enum token_type;

typedef struct ;

} token;

typedef struct tlist token_list, *ptlist;

我們平時習慣將表示式符寫作:operand operator operand(比如1+1),這是乙個遞迴的定義,表示式本身也可作為運算元。像這種將操作

符放在兩個運算元之間的表示式稱為中綴表示式,中綴表示式的好處是可讀性強,運算元之間涇渭分明(尤其是手寫體中)。但它有自身的缺

陷:操作符的位置說明不了它在運算的先後問題。例如 1+2×3 中,雖然 + 的位置在 × 之前,但這並不表示先做加運算再做乘運算。為解

決這個問題,數學中給操作符分了等級,級別高的操作符先計算(乘號的級別比加號高),並用括號提高操作符優先順序。因此上例表示式的值

是 7 而不是 (1+2)*3=9。

但對於計算機來說,優先順序是乙個多餘的概念。就像上面提到的,中綴表示式中操作符的順序沒有提供運算先後關係的資訊,這就好比用4個

位元組的空間僅儲存1個位元組資料——太浪費了!索性將操作符按照運算的先後排序:先計算的排最前面。此時操作符就不適合再放中間了,可

以將它移到被運算元的後面:operand operand operator(比如 1 1 +)。上例中 1+2×3 就變化為 1 2 3 × +;(1+2)×3 變化成 1 2 + 3

×,這種將操作符符放到運算元後面的表示式稱為字尾表示式。同理還有將操作符符按照逆序放到運算元的前面的字首表示式。

無論是字首表示式還是字尾表示式,它們的優點都是用操作符的順序來代替優先順序,這樣就可以捨棄括號等概念,化繁為簡。

字尾表示式求值

請看下面的梯等式計算,比較中綴表示式和字尾表示式的求值過程。

8 × ( 2 + 3 )        8 2 3 + ×

= 8 * 5              = 8 5 ×

= 40                 = 40字尾表示式的求值方式:從頭開始乙個標記(token)乙個標記地往後掃瞄,碰到運算元時先放到乙個臨時的空間

裡;碰到操作符就從空間裡取出最後兩個運算元,做相應的運算,然後將結果再次放回空間中。到了最後,空間中就只剩下運算元即運算結果

!這個中綴表示式求值類似,只不過中綴表示式運算元取的是前後各乙個。下面的**是程式中字尾表示式求值的節選,其中只包含加法運算

,其他運算都是類似的。

view plaincopy to clipboardprint?

// in expression.c  

variant eval ( const char expr )  

// 如果是操作符...  

switch ( p->token.ator.oper ) else else   

if ( op2->token.var.type == var_double ) else   

op1->token.type = var_string;  

strcat ( s1, s2 );  

strcpy ( op1->token.var.s, s1 );  

}  

free ( op2 );  

break;  

// ...  

// 其他操作符方法類似  

default:  

// 無效操作符處理  

break;  

}  

free ( p );  

}  

value = stack->token.var;  

free ( stack );  

// 最後乙個元素即表示式的值  

return value;  

表示式求值

程式的說明見清華大學出版社 資料結構 c語言版 include include define stack init size 40 define stackincrement 20 define ok 1 define false 0 typedef structs stack typedef st...

表示式求值

寫了乙個下午,各種糾結,各種問,終於搞明白了。但是自己還是想出來的一點東西的。很爽歪歪的,哈哈。先貼第一次的 include include include include include includeusing namespace std char data 7 7 int sign char ...

表示式求值

description 輸入中綴算術表示式s,s 中的運算元為非負整數,只含 和 運算,也可能含有括號 運算子的計算順序和實際四則運算的計算順序相同 輸出 表示式s 的值.注意除法運算只取整數部分,例如 1 2 0.input 輸入有多組資料.每組資料是乙個算術表示式s,s的長度不超過100.輸入的...