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.