Я хочу получить все условия оператора if в C ++. Если я поставлю (foo&&bar&&(one&&two))
тогда я хочу распечатать foo - bar - one - two
,
Я скомпилировал файлы scanner.l и parser.y и проверил индивидуально: my yy.lex.c
работает: если я поставлю (a&&b)
тогда я получаю 5 жетонов: (
, a
, &&
, b
а также )
как я хочу. Но когда я использую файл .y, если я помещаю тот же самый ввод, тогда я получаю a&&b
а также b)
, Обратите внимание, что в этом случае я получаю 2 токена, потому что токен a&&b
следует разделить на 3 токена a
, &&
а также b
, Я попытался ввести более простое условие: (a)
тогда я получаю: (
а также a)
но я хочу получить (
, a
, )
,
Я не знаю, делаю ли я что-то не так или это ошибка; Я надеюсь, что это моя вина.
parser.y
%{
#include <iostream>
#include <list>
#include <stdio.h>
#include <sstream>
#include <string>
using namespace std;
int yylex(void);
void yyerror(char *);
list<string> tokenList;
#define YYSTYPE char *
%}
%token PAR_IZQ
PAR_DER
SIMBOLO
FIN
NADA
AND
OR
%start input
%%
input:
| input terminos
;
terminos:
PAR_IZQ terminos PAR_DER { }
| PAR_IZQ condicion PAR_DER { }
;
condicion:
terminos AND terminos { }
| SIMBOLO AND terminos { cout << " 1) CONDITION FOUND: " << $1 << endl; }
| terminos AND SIMBOLO { cout << " 2) CONDITION FOUND: " << $3 << endl; }
| SIMBOLO AND SIMBOLO { cout << " 3) CONDITION FOUND: " << $3 << " AND " << $1 << endl; }
| SIMBOLO { cout << " 4) CONDITION FOUND: " << $1 << endl; }
;
%%
void yyerror(char *s) {
fprintf(stderr, "%s\n", s);
}
int main(void) {
yyparse();
return 0;
}
scanner.l
%option noyywrap
%{
#include <iostream>
#include "parser.tab.c"using namespace std;
%}
%%
[a-zA-Z0-9]+ {
yylval = yytext;
return SIMBOLO;
}
"&&" {
return AND;
}
"||" {
return OR;
}
[ \0\0] {
return FIN;
}
"(" {
yylval = yytext;
return PAR_IZQ;
}
")" {
yylval = yytext;
return PAR_DER;
}
. {
cout << "Entrada no permitida.";
cout << endl << yytext << endl;
exit(1);
}
%%
main.cpp
#include "mainwindow.h"#include <QApplication>
#include "lex.yy.c"#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef yy_buffer_state *YY_BUFFER_STATE;
extern int yyparse();
extern YY_BUFFER_STATE yy_scan_buffer(char *, size_t);
int main(int argc, char** argv) {
char condition[] = "(a) \0\0";
// note yy_scan_buffer is looking for a double null string
yy_scan_buffer(condition, sizeof(condition));
yyparse();
return 0;
}
Обратите внимание, что ввод синтаксического анализатора является строкой, поэтому я должен передать его в качестве параметра yy_scan_buffer
функция. \0\0
необходимо, потому что в противном случае программа никогда не закончит свое выполнение. Консоль говорит красным «ошибка синтаксиса», но я не знаю почему!
Знаешь ли ты, как я могу это исправить и получить нужные мне токены?
Спасибо!
PS: Я использую Windows 8.1, Qt Creator 2.8.1, win_bison 2.7 и win_flex 2.5.37.
Проблема в том, что ваш лексер возвращается yytext
парсеру как yylval
ассоциируется с символами, но yytext
является указателем на внутренний буфер токенов лексера, который будет действителен только до чтения следующего токена. Поэтому, когда вы позже приступите к распечатке токенов в своем состоянии, вы получите полуслучайный мусор (так как вскоре после этого вы в основном получаете тот же необработанный буфер токенов без завершающих нулевых символов).
Вам нужно сделать копию строки, на которую указывает yytext
перед возвратом парсеру:
[a-zA-Z0-9]+ {
yylval = strdup(yytext);
return SIMBOLO;
}
конечно, вам также нужно отслеживать, когда строка больше не нужна, и free
Это.
Альтернативно, так как вы не используете %union
поменяй #define
за YYSTYPE
в
#define YYSTYPE std::string