Как перевести LEX на Си,чтобы работало с грамматикой YACC'a?

У меня имеется следующий лексический анализатор калькулятора на LEX:

%option noyywrap

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


NEWLINE  \n
WSPACE   [ \t\r]*
WORDCHAR [A-Za-z_]
NUMBER   [0-9]*\.?[0-9]*

%%

{NEWLINE}  {   
               return NEWLINE;
           }

{WSPACE}    {
                //no return
            }

"exit" {
         return EXIT;//if enter exit so get end programm
       }

{WORDCHAR} {
                /* ignore letters that user writes */
        return WORD;
           }

{NUMBER}  {
              yylval.double_val = atof(yytext);
              return NUMBER;
          }

"+" {
      return ADD;
    }

"-" {
      return SUB;
    }



%%

Работает он на регулярках. Это грамматика калькулятора на yacc:

%{
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int yydebug=0;
void yyerror(const char *s);
int yylex();
void prompt();

%}



%token <double_val> NUMBER
%type <double_val> expr_L1 expr_L2 



%token WORD EXIT ADD SUB  NEWLINE



%union {
        double double_val;
    }

%%

goal:
    complete_expressions 
    ;

complete_expressions: 
    complete_expression /* a single complete expression OR */
    | complete_expressions complete_expression /* Multiple complete
                                                  expressions. */
    ;

complete_expression:

    expr_L1 NEWLINE { 
            printf(" = %f\n", $1);
            prompt();
         }
     | WORD 
     {
     yyerror("WRONG!!");
     }
    | NEWLINE { 
            prompt();
        }

    | EXIT NEWLINE { /* Exit if the user tells us to */
            printf("Goodbye!\n");
            exit(0);
        }
    ;

expr_L1:



    expr_L2
    | expr_L1 ADD expr_L2 { $$ = $1 + $3; }
    | expr_L1 SUB expr_L2 { $$ = $1 - $3; }
    ;
expr_L2:
    | NUMBER;



%%



void yyerror(const char *err)
{
    fprintf(stderr, "Error: %s\n", err);
    exit(-1);
}



void prompt()
{
    printf("calc> ");
}



/*int main(const char **argc, int argv)
{
    prompt();
    yyparse();
    return 0;
}*/

Я хочу заменить LEX на Си и мочь хотя бы складывать несколько чисел:

//#define YYSTYPE char* 
#include "y.tab.h"
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
//extern char* yytext;
//extern int yyparse();



int yylex(char* yy)
{

    if(atof(yy))
        {
            yylval.double_val = atof(yy);
                     return NUMBER;
        }   
    if(*yy='-')
    {
        return SUB; 
    }
    if(*yy='+')
    {
     return ADD;
    }

}
/*void yyerror()
{
    printf("Error!");
}*/
void scan()
{
    unsigned int ch=0;
    char buf[100];
    int i=0;
    while ((ch = getchar()) != '\n')
    {
    //*yytext++=ch;
        if(isdigit(ch))
        {
         buf[i]=ch;
            i++;
        }
        if(ch=='-' || ch =='+')
        {
            yylex(buf);
            yylex(&ch);
            memset(buf,0,sizeof(char)*100);
        }
    }


}


int main(const char **argc, int argv) {

    scan();
    prompt();
    yyparse();
    return 0;
}

Анализатора на Си работает примерно так: считываю выражение 2+3+4 с консоли, затем определяю, что из символов число, а что знак и отправляю в yylex. По-моему, в yylex у меня как раз и проблемы, так как я ,видимо , неправильно передаю в yacc значения.У меня при вводе 2+2 возникает Segmentation fault.

Грамматику на yacc для этого Си-анализатора сохраняю той же. Добавление к прототипу функции char* в .y файле int yylex(char*); создало больше проблем:

y.tab.c:1145:16: error: too few arguments to function ‘yylex’
       yychar = yylex ();
                ^~~~~

Запускаю так: yacc myyacc_calc.y и cc source.c y.tab.c -o example4. Можете помочь перевести анализатор c LEX на Си?


Ответы (1 шт):

Автор решения: Sergey

Вам надо получить исполнимый модуль?

Давным-давно я учился на аналогичном примере. Я взял два исходных файла:

  1. calcparse.l для Lex
  2. calcparse.y для Yacc

Я хотел получить исполняемый файл

calc

для чего написал Makefile, который создавал промежуточные файлы:

  1. calcparse.tab.c - выходной файл Yacc
  2. calcparse.tab.h - выходной файл Yacc
  3. lex.yy.c - выходной файл Lex

Сам Makefile выглядит следующим образом

YFLAGS = -d
PROGRAM = calc
OBJS = calcparse.tab.o lex.yy.o
SRCS = calcparse.tab.c lex.yy.c
CC = gcc

all: $(PROGRAM)
.c.o: $(SRCS)
    $(CC) -c $*.c -o $@ -O
calcparse.tab.c: calcparse.y
    bison $(YFLAGS) calcparse.y
lex.yy.c: calcparse.l
    flex calcparse.l
calc: $(OBJS)
    $(CC) $(OBJS) -o $@ -lfl -lm
clean:;
    rm -f $(OBJS) core *~ \#* *.o $(PROGRAM) \
y.* lex.yy.* calcparse.tab.*

Я думаю, здесь всё достаточно понятно.

→ Ссылка