简体   繁体   中英

lex and yacc analyzer

Now here is my lex code

%{
#include <stdio.h>
#include "y.tab.h"
extern int yylval;
int yywrap();
%}

%%
[a-zA-Z]    {yylval = *yytext; return ALPHABET;}
[0-9]+      {yylval = atoi(yytext); return NUMBER;}
[0-9]+"."[0-9]* {yylval = atof(yytext); return NUMBER;}
"=="        return EQ;
"<="        return LE;
">="        return GE;
"!="        return NE;
[\t]    ;
\n  return 0;
.   return  yytext[0];
%%

int yywrap()
{
    return 1;
}

and here is my yacc code

%{
#include<stdio.h>
extern int yylex();
extern int yyparse();
extern FILE* yyin;
int flag = 0;
%}

%token NUMBER
%token ALPHABET
%left '+''-' 
%left '*''/''%'
%left '&''|''^''~'
%right EQ LE GE NE'<''>'
%left '('')'
%left UMINUS
%left UPLUS
%start check

%%
check   : E { }
  E:E '+' E {$$ = $1 + $3;}
  |E '-' E  {$$ = $1 - $3;}
  |E '&' E  {$$ = $1 & $3;}
  |E '|' E  {$$ = $1 | $3;}
  |E '^' E  {$$ = $1 ^ $3;}
  |'~' E    {$$ = ~$2;}
  |E EQ E   {$$ = (EQ, $1, $3);}
  |E LE E   {$$ = (LE, $1, $3);}
  |E GE E   {$$ = (GE, $1, $3);}
  |E NE E   {$$ = (NE, $1, $3);}
  |E '<' E  {$$ = ('<', $1, $3);}
  |E '>' E  {$$ = ('>', $1, $3);}
  |'(' E ')'    {$$ = $2;}
  |'-' E %prec  UMINUS
            {$$ = - $2;}
  |'+' E %prec  UPLUS
    {$$ = + $2;} 
  |NUMBER   {$$ = $1;}
  |ALPHABET {$$ = $1;}
  ;
%%

int main(int argc, char** argv)
{
    char filename[30];
    char line[300];
    printf("\nEnter filename\n");
    scanf("%s",filename);
    yyin = fopen(filename, "r");
    if(NULL == yyin)
    {
        fprintf(stderr,"Can't read file %s\n",filename);
        return 1;
    }
    else
    {
        while(fgets(line, sizeof line, yyin) != NULL)
        {
            printf("%s\n", line);

        }
        yyparse();  
        fclose(yyin);
        printf("\nValue of yyparse : %d\n",yyparse());
    }
    if(flag == 0)
        printf("\nBoolean Arithmetic Expression is valid\n");

    return 0;
}

void yyerror()
{
    printf("\nBoolean Arithmetic expression is invalid\n\n");
    flag = 1;
}

This is my main part for reading text file and do some operations, so anyone can tell me this how to read multiple line in text file using Yacc. Now I put my fully Yacc code and I try to check Boolean expression is correct or not my text file expressions are : -

a-b
a+b&c
(P!=F+E-O+F-(U>Y+I<N))
(((a+B)-7+4-(c-d))+((P^q)-(L|z))+(m&n)+(O-g)
((A-2)&(B+2)|(C-4)^(D+4)+(~E))==F+(G!=)-(i<j)-(K>M)
((((a+b)-(c+d))-((E-F)+(G-H)))+((a&B)+(c|d))-((e^f)+(~g)+(i==2)-(j!=2)+(k<=8)-(l>=17.98)+(M<N)-(O>p)-((-2+4)+(6-(-5)))))

So my code check only first expression. So my problem is that how to check all expressions line by line.

Now please check where is the problem for reading text line by line and give message expression is valid or not please help. Some expressions are valid and some are invalid so please check and tell me the problem and how to correct it.

You grammar only handles a single ArithmeticExpression , and once that is done the parser returns.

One way to solve your problem is to modify the parser grammar just a little, so it handles multiple "lines" (or rather multiple expressions in your case) itself:

    ArithmeticExpression_list
      : ArithmeticExpression
      | ArithmeticExpression_list ArithmeticExpression
      ;

Then you simply use the return value of the yyparse() function to see if parsing was successful or not. If yyparse() return 0 then all expressions were syntactically okay.

If you want to print for each and every expression, just add a semantic action for the ArithmeticExpression , if there's a syntax error it will not be invoked.

The structure of main() is wrong. It reads the whole of the input file using fgets() , and then seems to expect yyparse() to read some more information from it.

What you probably need to do is:

while (yyparse() == 0)
    printf("OK\n");

Well, something along those lines. You might need to analyze flag , and/or set flag to 0 (or 1) after each iteration. If you want to read lines and have the grammar read the string, you have more work to do — setting up appropriate input functions, etc.

To get the code to compile cleanly, I used the following code. I added #define YY_NO_INPUT and full prototypes and various other changes — and cleaned up the triple comma expressions in the grammar for the comparison operations. They probably aren't what you'll use in the long term, but they satisfy the stringent compiler options I use.

testlex.l

%{
#include <stdio.h>
#include "y.tab.h"
#define YY_NO_INPUT
extern int yylval;
int yywrap(void);
extern void use_yyunput(char c);
%}

%%
[a-zA-Z]    {yylval = *yytext; return ALPHABET;}
[0-9]+      {yylval = atoi(yytext); return NUMBER;}
[0-9]+"."[0-9]* {yylval = atof(yytext); return NUMBER;}
"=="        return EQ;
"<="        return LE;
">="        return GE;
"!="        return NE;
[\t]    ;
\n  return 0;
.   return  yytext[0];
%%

int yywrap(void)
{
    return 1;
}
void use_yyunput(char c)
{
    unput(c);
}

testyacc.y

%{
#include <stdio.h>
#include <assert.h>
extern int yylex(void);
extern int yyparse(void);
extern void yyerror(char *str);
extern FILE* yyin;
int flag = 0;
%}

%token NUMBER
%token ALPHABET
%left '+''-' 
%left '*''/''%'
%left '&''|''^''~'
%right EQ LE GE NE'<''>'
%left '('')'
%left UMINUS
%left UPLUS
%start check

%%
check   : E { }
  E:E '+' E {$$ = $1 + $3;}
  |E '-' E  {$$ = $1 - $3;}
  |E '&' E  {$$ = $1 & $3;}
  |E '|' E  {$$ = $1 | $3;}
  |E '^' E  {$$ = $1 ^ $3;}
  |'~' E    {$$ = ~$2;}
  |E EQ E   {$$ = ($1 == $3);}
  |E LE E   {$$ = ($1 <= $3);}
  |E GE E   {$$ = ($1 >= $3);}
  |E NE E   {$$ = ($1 != $3);}
  |E '<' E  {$$ = ($1 <  $3);}
  |E '>' E  {$$ = ($1 >  $3);}
  |'(' E ')'    {$$ = $2;}
  |'-' E %prec  UMINUS
            {$$ = - $2;}
  |'+' E %prec  UPLUS
    {$$ = + $2;} 
  |NUMBER   {$$ = $1;}
  |ALPHABET {$$ = $1;}
  ;
%%

int main(void)
{
    char filename[30];
    printf("\nEnter filename\n");
    scanf("%s",filename);
    yyin = fopen(filename, "r");
    if(NULL == yyin)
    {
        fprintf(stderr,"Can't read file %s\n",filename);
        return 1;
    }
    else
    {
        while (yyparse() == 0)
        {
            printf("OK\n");
        }
        fclose(yyin);
    }

    if(flag == 0)
        printf("\nBoolean Arithmetic Expression is valid\n");

    return 0;
}

void yyerror(char *str)
{
    assert(str != 0);
    printf("\nBoolean Arithmetic expression is invalid\n\n");
    flag = 1;
}

Compilation and run

The file data contained the data from the question. rmk is a variation on the theme of make .

$ rmk testyacc.o testlex.o
    yacc  testyacc.y
    gcc -O3   -g   -I/Users/jleffler/inc   -std=c11   -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror    -c y.tab.c
    mv y.tab.o testyacc.o
    rm -f y.tab.c
    lex  testlex.l
    gcc -O3   -g   -I/Users/jleffler/inc   -std=c11   -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror    -c lex.yy.c
    mv lex.yy.o testlex.o
    rm -f lex.yy.c
$ gcc -o testit testyacc.o testlex.o
$ ./testit

Enter filename
data
OK
OK
OK

Boolean Arithmetic expression is invalid

$

Your stack uses integers, I believe. The use of atof() isn't going to help very much. That mainly means you've still got a lot of work to do.

Testing on Mac OS X 10.11.2 with GCC 5.3.0 (with flex 2.5.35 Apple(flex-31) and bison (GNU Bison) 2.3 masquerading as lex and yacc ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM