Как перевести 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 шт):
Вам надо получить исполнимый модуль?
Давным-давно я учился на аналогичном примере. Я взял два исходных файла:
- calcparse.l для Lex
- calcparse.y для Yacc
Я хотел получить исполняемый файл
calc
для чего написал Makefile, который создавал промежуточные файлы:
- calcparse.tab.c - выходной файл Yacc
- calcparse.tab.h - выходной файл Yacc
- 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.*
Я думаю, здесь всё достаточно понятно.