2013-04-21 82 views
4

我想了解解析表達式。我發現遞歸下降解析似乎很容易做到這一點。從維基百科,我在C中找到了一個例子。所以,我開始閱讀和編輯這段代碼,以瞭解它是如何工作的。我根據維基百科頁面上的描述編寫了遺漏的例程,但它不能像我預期的那樣使用任何表達式。例如:1+2*3+1;返回C遞歸下降解析器示例C

error: statement: syntax error

有人可以解釋我錯過了什麼嗎?

當前的C代碼:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

typedef enum {ident, number, lparen, rparen, 
      times, // symbol * 
      slash, // symbol \ not added yet 
      plus, // symbol + 
      minus, //symbol - 
      eql, //symbol == 
      neq, // != 
      lss, // < 
      leq,// <= 
      gtr, // > 
      geq, // >= 
      callsym, // not added yet 
      beginsym, // not added yet 
      semicolon, // ; 
      endsym, 
      ifsym, whilesym, becomes, thensym, dosym, constsym, 
      comma, //: 
      varsym, procsym, period, oddsym, 
      not, // ! 
      eq // = 
} Symbol; 

Symbol sym; 
int peek; 
void getsym(void); 
void error(const char*); 
void expression(void); 
void program(void); 
void nexttok(void); 

#define is_num(c) ((c) >= '0' && (c) <= '9') 
#define is_letter(c) ((c) <= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') 

int main(void) 
{ 
    program(); 
    return 0; 
} 

void nexttok(void) 
{ 
    peek = getchar(); 
} 

void getsym(void) 
{ 
    for(;;) { 
    nexttok(); 
    if(peek == ' ' || peek == '\t') continue; 
    else if(peek == EOF) break; 
    else break; 
    } 
    //static char buf[256]; 
    switch(peek) { 
    case '+': sym = plus; return; 
    case '-': sym = minus; return; 
    case '*': sym = times; return; 
    case ';': sym = semicolon; return; 
    case ':': sym = comma; return; 
    case '=': 
    nexttok(); 
    if(peek == '=') 
     sym = eql; 
    else 
     sym = eq; 
    return; 
    case '!': 
    nexttok(); 
    if(peek == '=') 
     sym = neq; 
    else 
     sym = not; 
    return; 
    case '<': 
    nexttok(); 
    if(peek == '=') 
     sym = leq; 
    else 
     sym = lss; 
    return; 
    case '>': 
    nexttok(); 
    if(peek == '=') 
     sym = geq; 
    else 
     sym = gtr; 
    return; 
    } 
    if(is_num(peek)) { 
    sym = number; 
    return; 
    } 
} 

int accept(Symbol s) { 
    if (sym == s) { 
     getsym(); 
     return 1; 
    } 
    return 0; 
} 

int expect(Symbol s) { 
    if (accept(s)) 
     return 1; 
    error("expect: unexpected symbol"); 
    return 0; 
} 

void factor(void) { 
    if (accept(ident)) { 
     ; 
    } else if (accept(number)) { 
     ; 
    } else if (accept(lparen)) { 
     expression(); 
     expect(rparen); 
    } else { 
     error("factor: syntax error"); 
     getsym(); 
    } 
} 

void term(void) { 
    factor(); 
    while (sym == times || sym == slash) { 
     getsym(); 
     factor(); 
    } 
} 

void expression(void) { 
    if (sym == plus || sym == minus) 
     getsym(); 
    term(); 
    while (sym == plus || sym == minus) { 
     getsym(); 
     term(); 
    } 
} 

void condition(void) { 
    if (accept(oddsym)) { 
     expression(); 
    } else { 
     expression(); 
     if (sym == eql || sym == neq || sym == lss || sym == leq || sym == gtr || sym == geq) { 
      getsym(); 
      expression(); 
     } else { 
      error("condition: invalid operator"); 
      getsym(); 
     } 
    } 
} 

void statement(void) { 
    if (accept(ident)) { 
     expect(becomes); 
     expression(); 
    } else if (accept(callsym)) { 
     expect(ident); 
    } else if (accept(beginsym)) { 
     do { 
      statement(); 
     } while (accept(semicolon)); 
     expect(endsym); 
    } else if (accept(ifsym)) { 
     condition(); 
     expect(thensym); 
     statement(); 
    } else if (accept(whilesym)) { 
     condition(); 
     expect(dosym); 
     statement(); 
    } else { 
     error("statement: syntax error"); 
     getsym(); 
    } 
} 

void block(void) { 
    if (accept(constsym)) { 
     do { 
      expect(ident); 
      expect(eql); 
      expect(number); 
     } while (accept(comma)); 
     expect(semicolon); 
    } 
    if (accept(varsym)) { 
     do { 
      expect(ident); 
     } while (accept(comma)); 
     expect(semicolon); 
    } 
    while (accept(procsym)) { 
     expect(ident); 
     expect(semicolon); 
     block(); 
     expect(semicolon); 
    } 
    statement(); 
} 

void program(void) { 
    getsym(); 
    block(); 
    expect(period); 
} 

void error(const char *msg) 
{ 
    fprintf(stderr,"error: %s\n",msg); 
    exit(1); 
} 
+0

[小型C編譯器中的遞歸下降解析器的另一個示例](https://github.com/alexfru/SmallerC)。 – 2013-04-21 03:53:42

+0

@AlexeyFrunze:我來看看這個!非常感謝! – Jack 2013-04-21 03:58:54

+0

@AlexeyFrunze:基於堆棧的模型是否用於解析此編譯器中的表達式? – Jack 2013-04-21 04:32:18

回答

7

statement從來不打電話expression,因此所有的表情都將是語法錯誤。要解決此問題,您需要更改statement,因此如果sym是啓動表達式的有效符號,它將調用expression。 (accept將是不可接受的,因爲它會消耗符號,並且expression不會看到它。)

+8

沒有雙關意圖。 – icktoofay 2013-04-21 02:38:27