Неопределенные символы для архитектуры x86_64 flex / bison

Я пытаюсь сделать простую игрушку (LET) язык как практика использования flex/bison, Тем не менее, я продолжаю получать следующую ошибку при запуске команды g++ -Wall -std=c++11 repl.cpp -v -o LET:

Undefined symbols for architecture x86_64:
"yy_scan_string(char const*)", referenced from:
_main in repl-030403.o
"yy_delete_buffer(yy_buffer_state*)", referenced from:
_main in repl-030403.o
"yyparse()", referenced from:
_main in repl-030403.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

У меня определены следующие файлы,

LET.y:

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

#include "AST.hpp"#include "GENERATED_CODE/LET_parser.hpp"#include "GENERATED_CODE/LET_lexer.hpp"
using namespace std;

extern int yylex();
extern char* yytext;
extern int yyparse();
extern Pgm* prog;
void yyerror (char const *s) {
fprintf (stderr, "%s\n", s);
}
%}

%output "./PARSER/GENERATED_CODE/LET_parser.cpp"%defines "./PARSER/GENERATED_CODE/LET_parser.hpp"
%union {
Pgm* prog;
int value;
char* var;
char cval;
Exp* exp;
string* str;
}

%token TTRUE
%token TFALSE
%token TLET
%token TIN
%token TIF
%token TTHEN
%token TELSE
%token TISZERO
%token TASSIGN
%token TLPAREN
%token TRPAREN
%token TPLUS
%token TMINU
%token TMULT
%token TDIVI
%token TREMI
%token TCOMMA
%token <value> TNUM
%token <var> TVAR

%type <prog> Prog
%type <exp> Exp
%type <str> Vari
/* Causes Bison to give more detailed error messages when parsing */
%error-verbose

%%

/* Bison Grammar Declarations */
Prog: Exp                 { prog = new Pgm($1); }

Vari: TVAR        { $$ = new string(yytext);}

Exp: TNUM                                 { $$ = new ConstExp(atoi(yytext)); }
| TVAR                                 { $$ = new VarExp(yytext); }
| TTRUE                                { $$ = new TrueExp; }
| TFALSE                               { $$ = new FalseExp; }
| TISZERO TLPAREN Exp TRPAREN          { $$ = new IsZeroExp($3); }
| TMINU TLPAREN Exp TCOMMA Exp TRPAREN { $$ = new DiffExp($3, $5); }
| TPLUS TLPAREN Exp TCOMMA Exp TRPAREN { $$ = new SumExp($3, $5); }
| TMULT TLPAREN Exp TCOMMA Exp TRPAREN { $$ = new MultExp($3, $5); }
| TDIVI TLPAREN Exp TCOMMA Exp TRPAREN { $$ = new QuotExp($3, $5); }
| TREMI TLPAREN Exp TCOMMA Exp TRPAREN { $$ = new RemiExp($3, $5); }
| TIF Exp TTHEN Exp TELSE Exp          { $$ = new IfExp($2, $4, $6); }
| TLET Vari TASSIGN Exp TIN Exp        { $$ = new LetExp(*$2, $4, $6); }

LET.l:

%{
#include <iostream>
#include <cstdio>

#include "AST.hpp"#include "GENERATED_CODE/LET_parser.hpp"
using namespace std;

int yylex();
void yyerror (char const *s) {
fprintf (stderr, "%s\n", s);
}
%}

%option c++
%option header-file = "./PARSER/GENERATED_CODE/LET_lexer.hpp"%option outfile     = "./PARSER/GENERATED_CODE/LET_lexer.cpp"%option noyywrap

digit [0-9]
alpha [a-zA-Z]
ws [ \t\n]+

%%
"#".*[\n]                      { /* No Action Taken */ }
{ws}                           { /* No Action Taken */ }
"true"                         { return TTRUE; }
"false"                        { return TFALSE; }
"let"                          { return TLET; }
"in"                           { return TIN; }
"if"                           { return TIF; }
"then"                         { return TTHEN; }
"else"                         { return TELSE; }
"zero?"                        { return TISZERO; }
"="                            { return TASSIGN; }
"("                            { return TLPAREN; }
")"                            { return TRPAREN; }
"+"                            { return TPLUS; }
"-"                            { return TMINU; }
"*"                            { return TMULT; }
"/"                            { return TDIVI; }
"%"                            { return TREMI; }
","                            { return TCOMMA; }
"-"?{digit}+                   { return TNUM; }
[a-zA-Z][a-z|0-9|\_|\'|\-|\?]* { return TVAR; }

Makefile:

generate-parser: clean flex bison

clean:
rm -rf PARSER/GENERATED_CODE
mkdir -p PARSER/GENERATED_CODE

flex:
flex PARSER/LET.l

bison:
bison -d PARSER/LET.y

repl.cpp:

#include <cstdio>

#include "./PARSER/AST.hpp"#include "./PARSER/GENERATED_CODE/LET_parser.hpp"#include "./PARSER/GENERATED_CODE/LET_lexer.hpp"
using namespace std;

extern YY_BUFFER_STATE yy_scan_string(const char * str);
extern void yy_delete_buffer(YY_BUFFER_STATE buffer);

int main() {
char input[] = "RAINBOW UNICORN 1234 UNICORN";

YY_BUFFER_STATE state = yy_scan_string(input);
yyparse();
yy_delete_buffer(state);

return 0;
}

0

Решение

Основная проблема заключается в том, что вы, похоже, не компилируете сгенерированный сканер и анализатор, а также не связываете скомпилированный сканер и анализатор в свой исполняемый файл. Поэтому, когда вы пытаетесь создать исполняемый файл, ни один из символов, определенных в сканере (yy_scan_string а также yy_delete_buffer) ни в парсере (yyparse) существовать.

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

В этом случае синтаксический анализатор не может зависеть от сканера, поэтому неправильно #include файл заголовка сканера в прологе зубров. Также неверно #include файл заголовка парсера в прологе зубров, потому что парсер, созданный зубрами, уже содержит необходимые прототипы и определения.

Наконец, вы просите flex сгенерировать лексер C ++, но ваш код использует интерфейс C (который включает в себя функции yy_scan_string а также yy_delete_buffer). Лично я бы просто удалил %option c++ с вашего пролога сканера. Если вы действительно хотите использовать C ++ API, вам необходимо внимательно прочитать глава руководства по сканерам C ++, и затем внесите соответствующие изменения в определение вашего бизона, чтобы он знал, как вызвать лексер.

Хотя это не связано с вашим вопросом, использование yytext в парсере почти никогда не корректно, так как содержимое yytext будет обычно соответствовать следующий токен на входе. (Парсеры LR (1) всегда смотрят вперед на один токен.) Вы должны выполнить необходимые семантические преобразования в действиях вашего сканера.

2

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

Других решений пока нет …

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