表达式求值,經典表達式遞歸下將法語法分析和求值

首先,給出文法定義:
經典表達式文法: Expr -> Expr + Term |Expr - Term |Term Term -> Term * Factor |Term / Factor |Factor Factor -> (Expr) |num 遞歸下降法,無法處理左遞歸文法
消除左遞歸後,用BNF表示 -> { (+|-) } -> { (*|/) } -> () | num | indent
程序:
1 /* 2 遞歸下降法構造經典表達式的語法分析 3 編寫遞歸下降子程序有一個協定: 4 每一個子程序都在全局量nextToken中放入下一個輸入的token。 5 因而,當開始一個語法分析函數時,假定nextToken具有還沒有被語法分析過程使用的輸入標記中最左面的那個標記。 6 */ 7 #include 8 #include 9 #include 10 11 enum token_type{ 12 NUMBER, OPERATOR, SEPARATOR, UNKOWN 13 }; 14 15 struct Token{ 16 int type; 17 int val; 18 }; 19 20 struct Token next_token; // 下一個未處理的token 21 // put next token into next_token 22 void lex(); 23 24 // 三個非終結符 25 double expr(); 26 double term(); 27 double factor(); 28 29 int main() 30 { 31 // input: 32 // 每個表達式, 以';'結尾 33 freopen("test.in", "r", stdin); 34 35 while (1){ 36 lex(); // 取得第一個token 37 if (next_token.type == UNKOWN && next_token.val == EOF) 38 break; 39 40 printf("%lf\n", expr()); 41 42 if (next_token.type != SEPARATOR || next_token.val != ';' ){ 43 fprintf(stderr, "未以\';\'結尾\n"); 44 break; 45 } 46 } 47 return 0; 48 } 49 50 // -> { (+ | -) } 51 double expr() 52 { 53 double val; 54 55 // parse first term 56 val = term(); 57 58 // As long as the next token is + or - , 59 // call lex() get next token, 60 // and parse the next term. 61 while(next_token.type == OPERATOR && 62 (next_token.val == '+' || next_token.val == '-')){ 63 int op = next_token.val; 64 lex(); 65 66 if(op == '+') 67 val += term(); 68 else if(op == '-') 69 val -= term(); 70 } 71 return val; 72 } 73 74 // -> { (* | /) } 75 double term() 76 { 77 double val; 78 79 // parse first factor 80 val = factor(); 81 82 // As long as the next token is * or / , 83 // call lex() get next token, 84 // and parse the next factor. 85 while(next_token.type == OPERATOR && 86 (next_token.val == '*' || next_token.val == '/')){ 87 int op = next_token.val; 88 lex(); 89 90 if(op == '*') 91 val *= factor(); 92 else if(op == '-') 93 val /= factor(); 94 } 95 return val; 96 } 97 98 // -> () | num 99 double factor(){ 100 double val; 101 if(next_token.type == SEPARATOR && next_token.val == '('){ 102 lex(); 103 val = expr(); 104 if(next_token.type == SEPARATOR && next_token.val == ')'){ 105 lex(); // 讀取下一個token 106 }else{ 107 fprintf(stderr, "括號不匹配\n"); 108 exit(1); 109 } 110 }else if(next_token.type == NUMBER){ 111 val = next_token.val; 112 lex(); 113 }else{ // 既不是數字也不是'(' 114 fprintf(stderr, "unkown factor: %c\n", next_token.val); 115 exit(1); 116 } 117 return val; 118 } 119 120 void lex(){ 121 int c; 122 while((c = getchar()) != EOF && isspace(c)) 123 ; 124 if(isdigit(c)){ 125 int val; 126 val = c - '0'; 127 while(isdigit(c = getchar())) 128 val = val * 10 + c - '0'; 129 ungetc(c, stdin); 130 next_token.type = NUMBER; 131 next_token.val = val; 132 return; 133 } 134 next_token.val = c; 135 switch(c){ 136 case '+': 137 case '-': 138 case '*': 139 case '/': 140 next_token.type = OPERATOR; 141 break; 142 case '(': 143 case ')': 144 case ';': 145 next_token.type = SEPARATOR; 146 break; 147 default: 148 next_token.type = UNKOWN; 149 } 150 }
測試數據, 以分號結尾的表達式,main()中將stdin重定向到文件test.in
12 + 2*30; (1+2)* 5; 4+5; 8+8*7;
Tags:  vc表达式求值 表达式求值的程序 后缀表达式求值 c语言表达式求值 表达式求值

延伸阅读

最新评论

发表评论