0
votes

I created a small interpreter using flex/bison.

This just can print a number, but I want to know how can add a string print?


lexer :

%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "y.tab.h"
%}
%%

<INITIAL>[s|S][h|H][o|O][w|W]               {return show;}
<INITIAL>[0-9a-zA-z]+                       {yylval.num=atoi(yytext);return string;}
<INITIAL>[\-\+\=\;\*\/]                     {return yytext[0];}
%%
int yywrap (void) {return 1;}

yacc :

%{
void yyerror(char *s);
#include <stdio.h>
#include <stdlib.h>
%}
%union {int num;}
%start line
%token show
%token <num> number
%type <num> line exp term

%%
line    : show exp ';'          {printf("showing : %d\n",$2);}
        | line show exp ';'     {printf("showing : %d\n",$3);}  
        ;
exp     : term                  {$$ = $1;}
        | exp '+' term          {$$ = $1 + $3;}
        | exp '-' term          {$$ = $1 - $3;}
        | exp '*' term          {$$ = $1 * $3;}
        | exp '/' term          {$$ = $1 / $3;}
        ;
term    : number                {$$ = $1;}
%%
int main (void)
{
    return yyparse();
}
void yyerror (char *s)
{
    printf("-%s at %s !\n",s );
}

test data :

show 5;
show 5+5;
show 5*2-5+1;

I want add string code to the lexer :

<INITIAL>\"                                 {BEGIN(STRING);}
<STRING>\"                                  {BEGIN(INITIAL);}

Now how to use from content of in <STRING>?

Can you help me to complete my interpreter?

I need to add this examples to my interpreter :

show "hello erfan";//hello erfan
show "hello ".5;//hello 5

Please help me.

1

1 Answers

1
votes

At the moment your interpreter doesn't work on numbers either! (Its an interpreter because it generates the results directly and does not generate code like a compiler would).

To make it work for numbers (again) you'd have to return a number token from the lexer and not a string. This line is wrong:

<INITIAL>[0-9a-zA-z]+                       {yylval.num=atoi(yytext);return string;}

It should return a number token:

<INITIAL>[0-9]+                       {yylval.num=atoi(yytext);return number;}

Now lets add a string. I see you made a start:

<INITIAL>\"                                 {BEGIN(STRING);}
<STRING>\"                                  {BEGIN(INITIAL);}

We need to add the state for a string to the lexer:

%x STRING

We should also match the contents of the string. I'll cheat a little here:

<STRING>[^"]*\"                                  {BEGIN(INITIAL); return(string);}

We also need to return the string value in the lval. Cheating again I can store a char pointer in the integer

<STRING>[^"]*\"             {BEGIN(INITIAL); yylval.num=strdup(yytext); return(string); }

Now we have to add strings to the yacc grammar. I'm cheating again by not allowing integers and strings to be mixed. You can expand that later if you wish:

line    : show exp ';'          {printf("showing : %d\n",$2);}
        | line show exp ';'     {printf("showing : %d\n",$3);}  
        | show string ';'       {printf("showing : %s\n",$2);}  
        | line show string ';'  {printf("showing : %s\n",$3);}
        ;

We need to remember to declare the string token:

%token <num> number string

Now we can put that all together:

The lexer file:

%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "y.tab.h"
%}
%x STRING
%%

<INITIAL>[s|S][h|H][o|O][w|W]   {return show;}
<INITIAL>[0-9]+                 {yylval.num=atoi(yytext);return number;}
<INITIAL>[\-\+\=\;\*\/]         {return yytext[0];}
<INITIAL>\"                     {BEGIN(STRING);}
<STRING>[^"]*\"                    {BEGIN(INITIAL);yylval.num=strdup(yytext);return(string);}
%%
int yywrap (void) {return 1;}

The parser file:

%{
void yyerror(char *s);
#include <stdio.h>
#include <stdlib.h>
%}
%union {int num;}
%start line
%token show
%token <num> number string
%type <num> line exp term

%%
line    : show exp ';'          {printf("showing : %d\n",$2);}
        | line show exp ';'     {printf("showing : %d\n",$3);}  
        | show string ';'       {printf("showing : %s\n",$2);}  
        | line show string ';'  {printf("showing : %s\n",$3);}
        ;
exp     : term                  {$$ = $1;}
        | exp '+' term          {$$ = $1 + $3;}
        | exp '-' term          {$$ = $1 - $3;}
        | exp '*' term          {$$ = $1 * $3;}
        | exp '/' term          {$$ = $1 / $3;}
        ;
term    : number                {$$ = $1;}
%%
int main (void)
{ 
    return yyparse();
}
void yyerror (char *s)
{
    printf("-%s at %s !\n",s );
}
#include "lex.yy.c"

Its basic and it works (I tested it). I've left plenty of things to be polished. You can remove the quote character from the string text; you can make the string token ave a string value rather than an integer to avoid the horrible type mismatch and you can make the show statements a bit more complex, but at least I've got you started.