0

I am writing a program for calculating the expression value using LR parser (2 stack-track). The code is working fine for single digits. It adds or multiplies two integers from 0-9 but for double digits like 12+5*10 it fails. The code is below. I have added the logic for concatenating double numbers in comments where I check if the token is a digit.

#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();
}
Ammar Ul Hassan
  • 826
  • 1
  • 18
  • 48

2 Answers2

2

You have a more severe error than a number that is inproperly parsed (see may other answer).

You have a problem understanding how yylex and yyparse work together.

The parser calls lex to get the next input token and processes that. Then it asks lex for the next token, until the parser reaches the ACCEPT state and returns to the caller (your main).

You first call yylex and then yyparse. Fine. Lex gets the first token and should put that on your stack. But it doesn't. So the input token is lost. Neither do I see you call yylex in yyparse to get the next token.

I leave to you to fix your error. it requires quite some rework and debugging that I am unwilling to do. It is your homework. But I hope this hint heps you.

And start learning to use a debugger. It shows you the path the program takes and the value of variables and so you can check if you make any logic errors or have bugs. Debugging is an integral part of learning the C language.

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
0

In else if (isdigit(ch)) you must continue reading input while it is a digit, and process it into x, e.g.

ch = input[test++];
...
else if (isdigit(ch))
{
    lk.type = NUMBER;
    x= ch - '0';
    while (isdigit(ch=input[test++]))
        x = x*10 + ch - '0';
}
...
// test++; // remove it here.
Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
  • I tried this but it didn't work. Actually, I already tried this kind of logic as u can see in my comments in the same part of the code but its failing. – Ammar Ul Hassan Sep 29 '18 at 15:04
  • In your code you did not advance the input. The above code does. Try the code exactly as given. See my update. – Paul Ogilvie Sep 29 '18 at 15:09
  • Thanks for the update. I have modified my code as shown above the way u asked me still am having the same error. Have u run this code after the edit u mentioned? – Ammar Ul Hassan Sep 29 '18 at 15:20
  • Yes, I ran it and it works. So something else must be wrong in your code. Take a debugger and step thru it to see what happens. Or use printf statements at key points. – Paul Ogilvie Sep 29 '18 at 15:54
  • I see that in `main` you call `yylex` and then `yyparse`. But normally, `yyparse` _calls_ `yylex` to get the next token! So main should only call `yyparse`! – Paul Ogilvie Sep 29 '18 at 15:56