Witam.
Mam taki problem - piszę program, którego zadaniem jest parsowanie dość prostego języka. Podstawowa budowa dokumentu ma postać:
procedure NAZWA
{
instrukcje;
....
};
program
{
instrukcje;
...
}
z tym założeniem ze procedur użytkownika może być dowolna ilość w tym 0. I tu pojawia się problem gdyż jeśli program wygląda np:
program
{
while(!north)
{
left;
};
go;
left;
}
jest poprawnie rozpoznawany i wykonywany. Jeśli natomiast pojawi się procedura lub więcej to procedury są poprawnie rozpoznawane i dodawane do pamięci robota, który ma je wykonywać ale w momencie gdy parser dochodzi do słowa kluczowego "program" daje znać że nie był w stanie rozpoznać takiej reguły i zaprzestaje parsowania reszty. Jako, że to jest moje pierwsze zetknięcie się zarówno z Flex'em jak i Bison'em wzorowałem się na paru przykładach niestety bardzo odmiennych od tego co mam uzyskać i w tym momencie nie wiem, w którym momencie jest błąd w zapisie gramatyki Bison'a. Przy próbie uzyskania dodatkowych informacji od Bison'a przy kompilacji jego pliku widzę, że w state 0 tworzone są dziwne przejścia, które nie wiem skąd pochodzą.
Plik gramatyki Flex'a:
%option noyywrap nodefault yylineno
%{
# include "bison.tab.h"
# include "extra.h"
%}
%%
"idz" |
"go" { return GO; }
"lewo" |
"left" { return LEFT; }
"wez" |
"get" { return GET; }
"poloz" |
"put" { return PUT; }
"jesli" |
"if" { return IF; }
"w przeciwnym razie" |
"else" { return ELSE; }
"dopoki" |
"while" { return WHILE; }
"i" |
"and" { return AND; }
"prawda" |
"true" { return TRUE; }
"sciana" |
"wall" { return WALL; }
"polnoc" |
"north" { return NORTH; }
"lisc" |
"leaf" { return LEAF ;}
"kwiatek" |
"flower" { return FLOWER; }
"pelny" |
"full" { return FULL; }
"biedronka" |
"ladybug" { return LADYBUG; }
"!prawda" |
"!true" { return NTRUE; }
"!sciana" |
"!wall" { return NWALL; }
"!polnoc" |
"!north" { return NNORTH; }
"!lisc" |
"!leaf" { return NLEAF ;}
"!kwiatek" |
"!flower" { return NFLOWER; }
"!pelny" |
"!full" { return NFULL; }
"!biedronka" |
"!ladybug" { return NLADYBUG; }
"{" { return LB; }
"}" { return RB; }
"(" { return LN; }
")" { return RN; }
"program" { return PROG; }
"procedura" |
"procedure" { return PROC; }
[a-zA-Z][a-zA-Z0-9]* { yylval.s = lookup(yytext); return NAME; }
";" {printf("EOL \n"); return EOL; }
\n
"//".*
[ \t] /* ignorowanie bialych znakow */
\\\n /* ignorowanie powtarzanych nowych linii */
. { yyerror("Nieznany znak %c", *yytext); }
%%
Plik gramatyki Bison'a:
%{
# include <stdio.h>
# include <string>
# include <iostream>
# include <stdlib.h>
# include "extra.h"
using namespace std;
int yylex(void);
extern string id;
void yyerror(const char *c, ...) {printf(c);
}
%}
%union {
struct ast *a;
char *d;
struct symbol *s;
struct symlist *sl;
}
%token PROG PROC
%token <s> GO LEFT GET PUT
%token <s> NAME
%token EOL
%token IF ELSE WHILE
%token LB RB LN RN
%token AND
%token NTRUE NWALL NNORTH NLEAF NFLOWER NFULL NLADYBUG TRUE WALL NORTH LEAF FLOWER FULL LADYBUG
%type <a> exp stmt list cond condition prc proc prog program
%start program
%%
stmt: WHILE cond LB list RB { $$ = newflow('W', $2, $4, NULL); }
| IF cond LB list RB { $$ = newflow('I', $2, $4, NULL); }
| IF cond LB list RB ELSE LB list RB { $$ = newflow('I', $2, $4, $8); }
| list
| exp
;
list: /* nic */ { $$ = NULL; }
| stmt EOL list { if ($3 == NULL)
$$ = $1;
else
$$ = newast('L', $1, $3);
}
;
cond: LN condition RN { $$ = newcomcon($2, NULL); }
| LN cond AND cond RN { $$ = newcomcon($2, $4); }
;
condition: NTRUE { $$ = newnegexp('A'); }
| NWALL { $$ = newnegexp('W'); }
| NNORTH { $$ = newnegexp('N'); }
| NLEAF { $$ = newnegexp('L'); }
| NFLOWER { $$ = newnegexp('F'); }
| NFULL { $$ = newnegexp('U'); }
| NLADYBUG { $$ = newnegexp('B'); }
| TRUE { $$ = newexp('A'); }
| WALL { $$ = newexp('W'); }
| NORTH { $$ = newexp('N'); }
| LEAF { $$ = newexp('L'); }
| FLOWER { $$ = newexp('F'); }
| FULL { $$ = newexp('U'); }
| LADYBUG { $$ = newexp('B'); }
;
exp: GO { $$ = newexp('M'); }
| LEFT { $$ = newexp('T'); }
| GET { $$ = newexp('G'); }
| PUT { $$ = newexp('P'); }
| NAME { $$ = newcall(yylval.s->name, NULL); }
;
prc: /* nothing */ { $$ = NULL; }
| proc
| proc EOL prc
;
proc: { $$ = NULL; }
| PROC NAME LB stmt RB { addProcedure(yylval.s->name, $4); }
;
prog: PROG LB stmt RB { createprogram(id, $3); }
| PROG error EOL { yyerrok; printf("> "); }
;
program: /* nothing */ { $$ = NULL; }
| prc EOL prog
| prog
;
%%
Plik extra.h
#ifndef EXTRA_H__
#define EXTRA_H__
/*
* Symbole:
* M - idz
* G - wez
* P - poloz
* T - lewo
*
* S - czy sciana
* F - czy kwiatek
* L - czy lisc
* N - czy polnoc
* B - czy biedronka
* U - czy pelny pojemnik
* A - prawda
*
* C - funkcja uzytkownika
* W - while
* I - if
*
* K - wyrazenie
* E - warunek
* M - negacja
*/
#include <string>
#include <stdlib.h>
using namespace std;
extern int yylineno;
extern string id;
void yyerror(const char *s, ...);
struct symbol
{
char *name;
char *value;
struct ast *func;
struct symlist *syms;
};
#define NHASH 9997
struct symbol *lookup(char*);
struct symlist
{
struct symbol *sym;
struct symlist *next;
};
struct symlist *newsymlist(struct symbol *sym, struct symlist *next);
void symlistfree(struct symlist *sl);
struct ast
{
char nodetype;
struct ast *l;
struct ast *r;
};
struct ufncall /* funkcje uzytkownika */
{
char nodetype; /* typ C */
struct ast *l; /* lista argumentow */
char *name;
};
struct expval
{
char nodetype; /* typ K */
char instruction;
};
struct flow
{
char nodetype; /* typ I(f) lub W(hile) */
struct ast *cond; /* warunki */
struct ast *tl; /* elementy do wykonania przez instrukcje */
struct ast *el; /* opcjonalny else */
};
struct ast *newast(char nodetype, struct ast *l, struct ast *r);
struct ast *newcall(char *s, struct ast *l);
struct ast *newref(struct symbol *s);
struct ast *newexp(char d);
struct ast *newnegexp(char d);
struct ast *newcomcon(struct ast *l, struct ast *r);
struct ast *newflow(char nodetype, struct ast *cond, struct ast *tl, struct ast *tr);
bool addprogram(string id, struct ast *a);
bool addProcedure(const char *name, struct ast *a);
bool createprogram(string id, struct ast *a);
/* definiowanie funkcji */
void dodef(struct symbol *name, struct symlist *syms, struct ast *stmts);
/* niszczenie i zwalnianie drzewa AST */
void treefree(struct ast *);
extern int yylineno; /* z lexera */
#endif
Wycinek bison.output
state 0
PROG shift, and go to state 1
PROC shift, and go to state 2
$ reduce using rule 36 (program)
EOL reduce using rule 29 (prc)
EOL [reduce using rule 32 (proc)]
LADYBUG reduce using rule 36 (program)
$default reduce using rule 29 (prc)
prc go to state 3
proc go to state 4
prog go to state 5
program go to state 64
Nie wiem skąd bierze się LADYBUG w stanie skoro jest to jeden z ostatnich tokenów jaki może wystąpić i to na pewno nie tym etapie
Jeśli ktoś byłby w stanie pomóc rozwiązać mi ten problem byłbym niezmiernie wdzięczny.