c - 如何在 C 中使用 LR 解析器计算表达式结果

标签 c parsing lr

我正在编写一个程序,使用 LR 解析器(2 个堆栈轨道)计算表达式值。该代码适用于个位数。它将 0-9 中的两个整数相加或相乘,但对于像 12+5*10 这样的两位数,它会失败。代码如下。我在评论中添加了连接双数的逻辑,我在其中检查标记是否为数字。

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

void push(int);
void shift(int);
void reduce(int);
void yyerror();
void lex_error();

#define NUMBER 256
#define PLUS 257
#define STAR 258
#define LPAREN 259
#define RPAREN 260
#define END 261
#define EXPRESSION 0
#define TERM 1
#define FACTOR 2
#define ACC 999


int action[12][6]={
{5, 0, 0, 4, 0, 0}, {0, 6, 0, 0, 0, ACC},{0,-2, 7, 0,-2,-2},
{0,-4,-4, 0,-4,-4}, {5, 0, 0, 4, 0, 0}, {0,-6,-6, 0,-6,-6},
{5, 0, 0, 4, 0, 0}, {5, 0, 0, 4, 0, 0}, {0, 6, 0, 0,11, 0},
{0,-1, 7, 0,-1,-1}, {0,-3, -3, 0,-3,-3}, {0,-5,-5, 0,-5,-5} };

int go_to[12][3]={
{1,2,3},{0,0,0}, {0,0,0},{0,0,0},{8,2,3},{0,0,0},
{0,9,3},{0,0,10},{0,0,0},{0,0,0},{0,0,0},{0,0,0} };

int prod_left[7]={0,EXPRESSION,EXPRESSION,TERM,TERM,FACTOR,FACTOR};
int prod_length[7]={0,3,1,3,1,3,1};
int stack[1000];
int value[1000];
int top=-1;
int sym;

typedef struct _token {
  int   type,   /* type of token (AND_TOK, etc.) */
   varno;   /* number of a VAR_TOK token */
} token;

token lk;
char *input;

token yylex() {
static int init = 1;    /* set to true first time through */
static char ch;     /* lookahead character */
char    s[100];
int i,x;
int num=0;
static int test = 0;

/* put nonsense value in for debugging */

lk.type = -1;
lk.varno = 0;

/* if at end of file, return an EOF token */

if (feof (stdin)) {
lk.type = END;
return lk;
}

/* if uninitialized, initialize the lookahead character */

if (init) {
init = 0;
}

ch = input[test++];

printf("character value in check token is %c\n", ch);
if(ch=='+')
    lk.type = PLUS;
else if(ch=='*')
    lk.type = STAR;
else if(ch=='(')
    lk.type = LPAREN;
else if(ch==')')
    lk.type = RPAREN;
else if (isdigit(ch))
{
    lk.type = NUMBER;
    x= ch - '0';
    while (isdigit(ch=input[test++]))
        x = x*10 + ch - '0';
    lk.varno = x;
}
/*while (lk.type==256)
 {
 num = num * 10;
 num = num + x - '0';
 }*/
else if (ch=='$')
    lk.type = END;
else{
    printf("character value befora saying illegal token %c\n", ch);
    lex_error();
}

 //test++;

 return lk;
}
int yyparse() {
int i;
int num = 0;
stack[++top]=0; // initial state
printf("token type is %d\n", lk.type);
printf("token type is %d\n", lk.type);
printf("token number value is %d\n", lk.varno);

do {
    i=action[stack[top]][lk.type-256]; // get relation
    printf("I value is %d\n", i);
    if (i==ACC){
        printf("success !\n");
        printf("value is ! %d \n", value[1]);
    }
    else if (i>0){ // shift
        printf("i is greater than 0 so calling shift\n");
        shift(i);
    }
    else if (i<0){ // reduce
        printf("i is less than 0 so calling reduce with - value %d \n", -i);
        reduce(-i);
    }
    else
        yyerror(); }
while (i!=ACC);
}

void push(int I) {
top++;
//printf("stack top after push is %d \n", stack[top]);
stack[top]=I;
//printf("stack top after assigning i is %d \n", stack[top]);
}

void shift(int I) {
//printf("pushing I value in stack is %d\n", I);
push(I);
value[top]=lk.varno;
yylex();
//printf("next token in shift is %d\n", sym);
}

void reduce(int I) {
int old_top;
/*printf("Top in reduce is %d\n", top);
printf("I in reduce is %d\n", I);
printf("Top in reduce is %d\n", top);
printf("prod prod_length in reduce is %d\n", prod_length[I]);*/
top-=prod_length[I];
//printf("top after minus in reduce is %d\n", top);
old_top=top;
//printf("oldtop in reduce is %d\n", old_top);
push(go_to[stack[old_top]][prod_left[I]]);

switch (I) {
    case 1: value[top]=value[old_top+1]+value[old_top+3];
    break;
    case 2: value[top]=value[old_top+1];
    break;
    case 3: value[top]=value[old_top+1]*value[old_top+3];
    break;
    case 4: value[top]=value[old_top+1];
    break;
    case 5: value[top]=value[old_top+2];
    break;
    case 6: value[top]=value[old_top+1];
    break;
    default: yyerror("parsing table error");
    break;
    }
}

void yyerror() {
printf("syntax error\n");
exit(1);
}

void lex_error() {
printf("illegal token\n");
exit(1);
}

void main () {
printf("Enter the expression: ");
input = malloc(sizeof(char) * 1024);
scanf("%s",input); 
yylex();
yyparse();
}

最佳答案

您遇到的错误比未正确解析的数字更严重(请参阅其他答案)。

您在理解 yylexyyparse 如何协同工作时遇到问题。

解析器调用 lex 来获取下一个输入标记并对其进行处理。然后它向 lex 询问下一个标记,直到解析器到达 ACCEPT 状态并返回给调用者(您的 main)。

您首先调用 yylex,然后调用 yyparse。美好的。 Lex 获得第一个标记,应该将其放入您的堆栈。但事实并非如此。所以输入 token 丢失了。我也没有看到您在 yyparse 中调用 yylex 来获取下一个标记。

我留给你来修正你的错误。它需要我不愿意做的大量返工和调试。这是你的功课。但我希望这个提示对您有所帮助。

并开始学习使用调试器。它向您显示程序采用的路径和变量的值,因此您可以检查您是否犯了任何逻辑错误或有错误。调试是学习 C 语言不可或缺的一部分。

关于c - 如何在 C 中使用 LR 解析器计算表达式结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52569459/

相关文章:

c - 给定一组点,我如何找到彼此最远的两个点?

c - 是否可以使用指针和一条语句来分配整个结构

c# - 如何将字符串解析为时间跨度

javascript - 构建 ES6 解析器和字符串生成器

parsing - 从 Lemon Parser Generator 生成 LR 解析表

parsing - 真实世界的 LR(k > 1) 文法?

c++ - 了解 SystemC 中的类型

c - 在函数签名中使用 void 指针

php - 每 24 小时执行一个 php 页面

parsing - LL 解析器比 LR 解析器有什么优势?