2014-07-25 56 views
1

我正在日K & R第5K&R遞歸下降解析器錯誤

該書剛剛推出了一個遞歸下降解析器來說明一些C.發現然而,該方案始終把「複雜的聲明」的報告語法錯誤。

例如,如果我運行該程序,如下所示和類型int a;然後回車我收到以下輸出:

$ ./dcl 
int a; 
syntax error 
a: int 

我也嘗試重定向文件與單個int和空主要功能,但收到相同的錯誤,所以不要認爲這是'\ n'問題。

下一個練習5-18要求讀者「讓dc1從輸入錯誤中恢復」,但我不相信我的工作正常。我隨後複製並粘貼了本書PDF的代碼,因此認爲它反映了打印的內容。

對診斷和解決方案的建議非常感謝。

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

#define MAXTOKEN 100 
#define BUFSIZE 100 

enum { NAME, PARENS, BRACKETS }; 

void dcl(void); 
void dirdcl(void); 

int bufp = 0; /* next free position in buf */ 
int gettoken(void); 
int tokentype;   /* type of last token */ 
char token[MAXTOKEN]; /* last token string */ 
char name[MAXTOKEN];  /* identifier name */ 
char datatype[MAXTOKEN]; /* data type = char, int, etc. */ 
char out[1000]; 
char buf[BUFSIZE]; /* buffer for ungetch */ 


int main() /* convert declaration to words */ 
{ 
    while (gettoken() != EOF) { /* 1st token on line */ 
     strcpy(datatype, token); /* is the datatype */ 
     out[0] = '\0'; 
     dcl(); /* parse rest of line */ 
     if (tokentype != '\n') 
      printf("syntax error\n"); 
     printf("%s: %s %s\n", name, out, datatype); 
    } 
    return 0; 
} 

/* dcl: parse a declarator */ 
void dcl(void) 
{ 
    int ns; 
    for (ns = 0; gettoken() == '*';) /* count *'s */ 
     ns++; 
    dirdcl(); 
    while (ns-- > 0) 
     strcat(out, " pointer to"); 
} 

/* dirdcl: parse a direct declarator */ 
void dirdcl(void) 
{ 
    int type; 
    if (tokentype == '(') { 
     dcl(); /* (dcl) */ 
     if (tokentype != ')') 
      printf("error: missing)\n"); 
    } else if (tokentype == NAME) /* variable name */ 
     strcpy(name, token); 
    else 
     printf("error: expected name or (dcl)\n"); 
    while ((type=gettoken()) == PARENS || type == BRACKETS) 
     if (type == PARENS) 
      strcat(out, " function returning"); 
     else { 
      strcat(out, " array"); 
      strcat(out, token); 
      strcat(out, " of"); 
     } 
} 

/* return next token */ 
int gettoken(void) 
{ 
    int c, getch(void); 
    void ungetch(int); 
    char *p = token; 
    while ((c = getch()) == ' ' || c == '\t') 
     ; 
    if (c == '(') { 
     if ((c = getch()) == ')') { 
      strcpy(token, "()"); 
      return tokentype = PARENS; 
     } else { 
      ungetch(c); 
      return tokentype = '('; 
     } 
    } else if (c == '[') { 
     for (*p++ = c; (*p++ = getch()) != ']';) 
      ; 
     *p = '\0'; 
     return tokentype = BRACKETS; 
    } else if (isalpha(c)) { 
     for (*p++ = c; isalnum(c = getch());) 
      *p++ = c; 
     *p = '\0'; 
     ungetch(c); 
     return tokentype = NAME; 
    } else 
     return tokentype = c; 
} 


/* get a (possibly pushed-back) character */ 
int getch(void) 
{ 
    return (bufp > 0) ? buf[--bufp] : getchar(); 
} 

/* push character back on input */ 
void ungetch(int c) 
{ 
    if (bufp >= BUFSIZE) 
     printf("ungetch: too many characters\n"); 
    else 
     buf[bufp++] = c; 
} 
+2

請勿在輸入中輸入分號。或者修改程序以接受分號作爲聲明的結尾,如換行符。請注意,它不接受一行中的多個聲明,所以'int a,b'將不被接受。 –

+0

我想你不應該在一個已經過時的資源上工作,因爲K&R(最新版本甚至早於C89,更不用說C99和C11),除非它是爲了獲得關於C語言的歷史回顧。 –

+0

你會推薦什麼作爲現代替代品? – retrodev

回答

1

喬納森·萊弗勒是正確的,代碼只是作爲解析本書中的代碼之前立即列出的聲明語法,而不是語法正確的聲明,你會發現在代碼。