Реализация языка Wolfram в flex, bison, Stack Overflow

После просмотра таких проектов, как mathics а также symja, Я пытаюсь реализовать синтаксический анализатор с открытым исходным кодом для языка Wolfram, используя flex и bison в C ++. Вызов bison -d и flex ++ не вызывает никаких проблем, но когда я использую g ++, я получаю следующее сообщение об ошибке:

parser.tab.cpp:1242:16: error: use of undeclared identifier 'yylex'
yychar = YYLEX;
^
parser.tab.cpp:598:16: note: expanded from macro 'YYLEX'
# define YYLEX yylex ()
^
1 error generated.

Вот мои файлы .lpp и .ypp для справки

lexer.lpp

%{
#include <iostream>
#include "parser.tab.hpp"using namespace std;

extern "C"{
int yylex(void);
}

%}

%option c++
%option noyywrap

%%
[1-9][0-9]*(.[0-9]*)?     { return NUM; }
"\["        { return LBRACE; }
"\]"        cout << "rBrace" << endl;
"\("        cout << "lParen" << endl;
"\)"        cout << "rParen" << endl;
"\{"        cout << "lBracket" << endl;
"\}"        cout << "rBracket" << endl;
","         cout << "comma" << endl;

"@@"        cout << "apply" << endl;
"Apply\["   cout << "apply" << endl;
"/@"        cout << "map" << endl;
"Map\["     cout << "map" << endl;
"/."        cout << "rule" << endl;

"==="       cout << "sameQ" << endl;
"SameQ\["   cout << "sameQ" << endl;

"+"         cout << "plus" << endl;
"-"         cout << "minus" << endl;
"*"         cout << "times" << endl;
"/"         cout << "divide" << endl;
"^"         cout << "power" << endl;
"Power\["   cout << "power" << endl;

--Abbreviated--

.           ECHO;
%%

int main()
{
FlexLexer* lexer = new yyFlexLexer;
while(lexer->yylex() != 0)
;

return 0;
}

parser.ypp

%{
#include <iostream>
#include <string>

using namespace std;

extern "C"{
int yyparse(void);
}
void yyerror(const char *s);
%}

%union {
double dval;
char *str;
}

%token <dval> NUM;
%token <str> RBRACE;
%token <str> LBRACE;
%%

expr:
NUM     { cout << $1 << endl;}
| NUM "+" NUM { cout << $1 + $3}
| NUM "-" NUM { cout << $1 - $3}
| NUM "*" NUM { cout << $1 * $3}
| NUM "/" NUM { cout << $1 / $3}
;
%%

int main(int argc, char **argv)
{
yyparse();
}

void yyerror(const char *s)
{
cout << s << endl;
}

Любая помощь будет оценена. Спасибо!

1

Решение

yylex определяется в сгенерированном сканере и используется (автоматически) в сгенерированном парсере. Так как результаты — просто C (++), волшебства нет; если вы используете yylex в файле, вы должны объявить его в этом файле.

Вы могли бы ожидать, что зубр включит объявление автоматически, но это не так. Во-первых, он не будет знать, что вы хотите (излишне и, возможно, бесполезно) обернуть объявление в extern "C" {...},


Кроме того, вы столкнетесь с проблемами с интерфейсами C ++. yylex является функцией-членом в API flex C ++, поэтому вы не можете объявить ее как extern "C"и вы также не можете просто назвать это как yylex во внешнем файле.

YMMV, но лично я предпочитаю использовать обычный (стабильный и хорошо документированный) C API, который будет прекрасно компилироваться как C ++, избегая необходимости каких-либо extern "C" деклараций.

Если вы хотите избежать глобальных переменных, используйте интерфейсы reentrant scanner / pure parser.

В заключение, flex поставляется с совершенно хорошим вариантом отладки, который доступен практически с нулевой стоимостью, просто указав -d в командной строке. Сканер, созданный с этим флагом, будет автоматически выводить информативные сообщения о каждом сканированном токене, и намного проще удалить флаг командной строки, чем редактировать полное описание flex.

bison имеет похожий механизм, но он не такой автоматический: вам нужно включить его при генерации парсера, а затем включить его, установив флаг времени выполнения. Оба хорошо документированы в соответствующих руководствах.

1

Другие решения


По вопросам рекламы [email protected]