Linguagens e Programação BISON
BISON Gerador de analisadores sintáticos. Converte uma gramática independente de contexto LARL(1) 1 num programa C capaz de processar frases da linguagem. Gramática LARL(1) independente de contexto. Especificação do processo de análise apenas com um token de avanço. 1 LARL : Look-Ahead Left to right Rightmost derivation
BISON & FLEX O BISON integra-se com o FLEX para o reconhecimento dos tokens da linguagem Excerto de programa int square ( int x ) { return x * x ; } Análise léxica (FLEX) TIPO_INT '{' RETURN ID '*' ID ';' '}' ID '(' TIPO_INT ID ')' Gramática BISON para a Análise sintática funcao: tipo ID '(' listaparametros ')' blocoinstrucoes; blocoinstrucoes: '{' instrucoes '}'; instrucoes: /*vazio*/ instrucoes instrucao; tipo: TIPO_INT TIPO_FLOAT TIPO_CHAR ; ( )
Ciclo de vida do programa BISON Erros de BISON ficheiro fonte bison.y BISON ficheiro fonte C.tab.c Ficheiro texto 1 Ficheiro texto Ficheiro 3 texto 2 opção -d ficheiro de cabeçalho C.tab.h Compilador (gcc) programa executável Erros de FLEX Resultado 3 Resultado 2 Resultado 1 ficheiro fonte flex.flex FLEX include yylex() ficheiro fonte C.c
Passos para a compilação >> bison d ficheiro.y >> flex ficheiro.flex Produz: ficheiro.tab.c A opção " d" implica a criação do ficheiro.tab.h >> gcc ficheiro.tab.c lex.yy.c -lfl Produz: lex.yy.c Produz: a.out
Declarações Ficheiro BISON Formato de um ficheiro BISON %{ #include <stdio.h> int numargs=0, numerros=0; %} %token ID INT REAL %start inicio ( ) Instruções C Instruções que serão incluídas no ficheiro C gerado pelo BISON. Os exemplos mais comuns são: - inclusão ficheiros.h - declaração de variáveis e constantes Declarações BISON Definições BISON que incluem: - declaração de tokens e dos seus tipos - precedência de operadores - axioma da gramática
Gramática Ficheiro BISON Formato de um ficheiro BISON ( ) %% inicio: /*vazio*/ lista_args ; lista_args: arg lista_args ',' arg ; arg: ID {numargs++;} INT {numargs++;} REAL {numargs++;} ; %% Regra inicial - Definida com %start Alternativa vazia - Definida sem conteúdo - Por questão de legibilidade utilizase o comentário /*vazio*/ Gramática - Notação BNF Regras definidas em minúsculas O símbolo definido como é : Tokens com mais de um caracter definidos em maiúsculas e com um só caracter especificados entre plicas ( ) Final da regra - As regras terminam com ;
Rotinas em C Ficheiro BISON Formato de um ficheiro BISON ( ) Evoca o analisador sintático int main() { yyparse(); if (numerros == 0) printf("frase válida\n"); else printf("frase inválida\nnº de erros: %d\n", numerros); printf("nº de argumentos: %d\n",numargs); return 0; } int yyerror(char *s) { numerros++; printf("erro sintático ou semântico: %s\n", s); }
Propostas de Exercícios 1. Crie o programa Hello World com BISON e FLEX. Os tokens existentes são HELLO e WORLD. Sempre que o texto a analisar tiver os dois tokens pela ordem certa, deve imprimir a frase Hello World!!!.
1. pl5ex1.flex Propostas de Exercícios %{ #include "pl5ex1.tab.h" /* header file criado pelo BISON */ extern int nerr; /* variável declarada no BISON */ %} %% [ \t] return ' '; Hello return HELLO; World return WORLD;. {printf("erro léxico: simbolo desconhecido %s\n", yytext);nerr++;} \n return 0; <<EOF>> return 0; %%
1. pl5ex1.y Propostas de Exercícios %{ #include <stdio.h> int existe=0; int nerr=0; %} %token HELLO WORLD %start inicio %% inicio: %% HELLO ' ' WORLD {existe=1;} ; ( )
1. pl5ex1.y ( ) Propostas de Exercícios int main() { yyparse(); if(existe) printf("\nhello World!!!\n"); else printf("frase inválida\nnumero de erros: %d\n",nerr); return 0; } int yyerror(char *s) { nerr++; printf("erro semantico: %s\n",s); }
Valores semânticos A variável yylval permite guardar os valores semânticos (lexemas) identificados pelo analisador léxico. Por omissão yylval é definida como um inteiro Armazenamento do lexema no FLEX [0-9]+ { yylval=atoi(yytext); return INT; } É possível redefinir o tipo de yylval Redefinição do tipo de yylval #define YYSTYPE double
Valores semânticos Para definição de tipos mais complexos utiliza-se a diretiva BISON %union. Diretiva %union no ficheiro BISON %union { char int float } *palavra; numinteiro; numreal; Armazenamento do lexema no FLEX [0-9]+ { yylval.numinteiro=atoi(yytext); return INT; } [a-za-z]+ { yylval.palavra=strdup(yytext); return STRING; }
Ações Semânticas O BISON pode ter ações semânticas ao longo das regras; Cada ação semântica ocupa um $ da regra dependendo da posição ocupada; O lado esquerdo (regra) é referenciado sempre por $$. expressao: INT { printf("inteiro = %d\n",$1); } '+' { printf("operador = %d\n",$2); } INT { printf("inteiro = %d\n",$3); $$=$1+$3; } ;
Propostas de Exercícios 2. Crie um analisador usando o FLEX e o BISON, que reconheça frases constituídas por dois inteiros separados por um operador relacional (=, <, >, <=, >=, <>). O analisador deve indicar se a frase esta de acordo com a sintaxe, e se a comparação é verdadeira ou falsa. 10 <= 20 '\n' - verdadeiro 5 = 10 '\n' -falso 120 <> 130 '\n' - verdadeiro > 10 '\n' - erro de sintaxe
2. Propostas de Exercícios pl5ex2.flex %{ #include "pl5ex2.tab.h" extern int nerr; %} %% [ \t] return 0; [0-9]+ {yylval=atoi(yytext);return INT;} = return IGUAL; \<= return MENOR_IGUAL; \>= return MAIOR_IGUAL; \<\> return DIFERENTE; \< return MENOR; \> return MAIOR;. {printf("erro léxico: %s\n", yytext);nerr++;} \n return 0; <<EOF>> return 0; %%
2. Pl5ex2.y %{ %} Propostas de Exercícios #include <stdio.h> int vlogico; int nerr=0; %token INT IGUAL MAIOR MENOR MAIOR_IGUAL MENOR_IGUAL DIFERENTE %start inicio ( )
2. Pl5ex2.y Propostas de Exercícios ( ) %% inicio: expigual expmaior expmenor expmaiorigual expmenorigual diferente; expigual: expmaior: expmenor: ( ) INT IGUAL INT {vlogico=($1==$3);} ; INT MAIOR INT {vlogico=($1>$3);} ; INT MENOR INT {vlogico=($1<$3);} ;
2. Pl5ex2.y Propostas de Exercícios ( ) expmaiorigual: INT MAIOR_IGUAL INT {vlogico=($1>=$3);} ; expmenorigual: INT MENOR_IGUAL INT {vlogico=($1<=$3);} ; diferente: %% ( ) INT DIFERENTE INT {vlogico=($1!=$3);} ;
Propostas de Exercícios 2. Pl5ex2.y ( ) int main() { yyparse(); printf("%s\n",(vlogico==0)?"falso":"verdadeiro"); return 0; } int yyerror(char *s) { nerr++; printf("erro semantico: %s\n",s); }
Propostas de Exercícios 3. Reescreva a gramática do exercício 2, de modo a: i. aceitar inteiros e letras (a-z e A-Z); ii. iii. iv. aceitar várias comparações na mesma linha; testar a incompatibilidade de tipos entre inteiros e letras; fazer a recuperação dos erros ocorridos. 10 <= 20 = 20 '\n' verdadeiro verdadeiro 5 < 10 >= 5 < 2 '\n' verdadeiro verdadeiro falso 120 <> A'\n' incompatível z <> A'\n' verdadeiro > 10 '\n' - erro de sintaxe
3. Propostas de Exercícios pl5ex3.flex %{ #include <stdlib.h> #include "PL5Ex3Defs.h" #include "PL5Ex3.tab.h" %} %% [ \t] return 0; [0-9]+ {yylval.valor.numero=atoi(yytext); [a-za-z]+ yylval.valor.tipo=integer;return INT;} {yylval.valor.palavra=strdup(yytext); yylval.valor.tipo=string;return PALAVRA;} = return IGUAL; \<= return MENOR_IGUAL; \>= return MAIOR_IGUAL; \<\> return DIFERENTE; \< return MENOR; \> return MAIOR;. /*ignorado*/ \n return yytext[0]; <<EOF>> return 0; %%
3. Propostas de Exercícios pl5ex3defs.h typedef enum {INTEGER, STRING} ETipo; typedef struct{ int numero; char *palavra; ETipo tipo; }SValor;
3. pl5ex3.y %{ Propostas de Exercícios #include <stdio.h> #include "PL5Ex3Defs.h" int vlogico; int nerr=0; %} void compara(svalor, int, SValor); %union{ SValor valor; } %token <valor> INT PALAVRA IGUAL MAIOR MENOR MAIOR_IGUAL MENOR_IGUAL DIFERENTE %type <valor> exprs %start exprs_linha %% (...)
3. pl5ex3.y Propostas de Exercícios (...) %% exprs_linha: /*vazio*/ exprs_linha exprs '\n' ; exprs: %% (...) INT {$$.numero = $1.numero; $$.tipo = $1.tipo;} PALAVRA {$$.palavra = $1.palavra; $$.tipo = $1.tipo;} exprs IGUAL INT { compara($1, IGUAL, $3); $$ = $3; } exprs IGUAL PALAVRA { compara($1, IGUAL, $3); $$ = $3; } exprs MAIOR INT { compara($1, MAIOR, $3); $$ = $3; } exprs MAIOR PALAVRA { compara($1, MAIOR, $3); $$ = $3; } exprs MENOR INT { compara($1, MENOR, $3); $$ = $3; } exprs MENOR PALAVRA { compara($1, MENOR, $3); $$ = $3; } exprs MAIOR_IGUAL INT { compara($1, MAIOR_IGUAL, $3); $$ = $3; } exprs MAIOR_IGUAL PALAVRA { compara($1, MAIOR_IGUAL, $3); $$ = $3; } exprs MENOR_IGUAL INT { compara($1, MENOR_IGUAL, $3); $$ = $3; } exprs MENOR_IGUAL PALAVRA { compara($1, MENOR_IGUAL, $3); $$ = $3; } exprs DIFERENTE INT { compara($1, DIFERENTE, $3); $$ = $3; } exprs DIFERENTE PALAVRA { compara($1, DIFERENTE, $3); $$ = $3; } error { yyerror("erro de sintaxe");} ;
3. pl5ex3.y Propostas de Exercícios (...) void compara (SValor v1, int op, SValor v2) { if(v1.tipo!= v2.tipo){ puts("incompativel"); return; } switch(op){ case IGUAL: vlogico=(v1.tipo==integer)? (v1.numero==v2.numero):(strcmp(v1.palavra,v2.palavra)==0); break; case MAIOR: vlogico=(v1.tipo==integer)? (v1.numero>v2.numero):(strcmp(v1.palavra,v2.palavra)>0); break; case MENOR: vlogico=(v1.tipo==integer)? (v1.numero<v2.numero):(strcmp(v1.palavra,v2.palavra)<0); break; case MAIOR_IGUAL: vlogico=(v1.tipo==integer)? (v1.numero>=v2.numero):(strcmp(v1.palavra,v2.palavra)>=0); break; case MENOR_IGUAL: vlogico=(v1.tipo==integer)? (v1.numero<=v2.numero):(strcmp(v1.palavra,v2.palavra)<=0); break; case DIFERENTE: vlogico=(v1.tipo==integer)? (v1.numero!=v2.numero):(strcmp(v1.palavra,v2.palavra)!=0); } puts((vlogico==1)?"verdadeiro":"falso"); }(...)
3. pl5ex3.y (...) Propostas de Exercícios int main() { yyparse(); return 0; } int yyerror(char *s) { nerr++; printf("erro sintatico/semantico: %s\n",s); }
Precedência de operadores A precedência de operadores no BISON permite estabelecer a ordem pela qual as regras alternativas são processadas. Diretivas BISON %left - Declara um operador binário com associação à esquerda, isto é, o agrupamento é realizado primeiro à esquerda. Assim a frase x OPL y OPL z seria realizada primeiro a operação x OPL y e depois o resultado desta operação com OPL z ; %right - Declara um operador binário com associação a direita, isto e, o agrupamento e realizado primeiro a direita. Assim na frase x OPR y OPR z seria realizada primeiro a operação y OPR z e depois realizada o operação x OPR com o resultado obtido anteriormente; %nonassoc - Declara um operador não associativo, ou seja, um operador que não pode aparecer mais que uma vez de seguida. Assim, a frase x OPNA y OPNA z gera um erro.
Precedência de operadores A precedência relativa de diferentes operadores é controlada pela ordem das suas declarações. %left OP1 precedência mais baixa %left OP2 %right OP3 %left OP4 precedência mais alta Operadores definidos na mesma declaração têm igual nível de precedência. %left OP5 OP6 OP7
Precedência de operadores Exemplo ficheiro BISON ( ) %left '<' '>' '=' DIF MEN_IG MAI_IG %left '+' '-' %left '*' '/' %left '^' %nonassoc MENOS_UNARIO %% expressao: expressao '+' expressao expressao '-' expressao expressao '*' expressao expressao '/' expressao '-' expressao %prec MENOS_UNARIO operando ; operando: INTEIRO REAL ID; %% ( )
Propostas de Exercícios 5. Implemente, utilizando o BISON e o FLEX, um analisador sintático para reconhecimento duma expressão aritmética. A gramática é a seguinte: S ID '=' E E E E '+' E E '-' E E '*' E E '/' E '-'E '(' E ')' ID INT REAL Em que ID é um identificador (letra de 'a' a 'z'), INT um numero inteiro e REAL um numero real. O parser deve analisar múltiplas expressões e apresentar os resultados. Sempre que haja uma atribuição esse valor deve ser guardado, para ser utilizado com o identificador respectivo em outras expressões. Como tabela de símbolos, utilize um vector com uma posição para cada letra. i. Implemente este analisador sem usar precedências de operadores; ii. Implemente este analisador usando precedências de operadores.
5. Propostas de Exercícios pl5ex5.flex %{ #include "PL5Ex5Defs.h" #include "PL5Ex5.tab.h" extern int nerr; %} %% [ \t] return 0; [a-z] {yylval.valor.id=yytext[0]; yylval.valor.tipo=variavel; return ID;} [0-9]+\.[0-9]+ {yylval.valor.val=atof(yytext); yylval.valor.tipo=nreal; return REAL;} [0-9]+ {yylval.valor.val=atof(yytext);yylval.valor.tipo=nint; return INT;} \+ return ADD; - return SUB; \* return PROD; \/ return DIV; \( return OPENBR; \) return CLOSEBR; = return IGUAL;. {printf("erro léxico! simbolo não permitido: %s\n",yytext);nerr++;} \n return 0; <<EOF>> return 0; %%
5. Propostas de Exercícios pl5ex5defs.h typedef enum {NINT, NREAL, VARIAVEL} ETipo; typedef struct{ char id; float val; ETipo tipo; }SValor;
5. ii. Pl5Ex5.y %{ %} Propostas de Exercícios #include <stdio.h> #include "PL5Ex5Defs.h" int nerr; float resultado; float memoria[26]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; float calcula(svalor, int, SValor); void setvalor(svalor, SValor); float getvalor(svalor); %union{ SValor valor; }; %token <valor> INT REAL ADD SUB PROD DIV ID OPENBR CLOSEBR IGUAL %type <valor> e %left ADD SUB %left PROD DIV %start s (...)
5. ii. Pl5Ex5.y (...) %% Propostas de Exercícios s: ID IGUAL e { setvalor($1,$3); } e ; e: e ADD e { $$.val=calcula($1, ADD, $3); } e SUB e { $$.val=calcula($1, SUB, $3); } e PROD e { $$.val=calcula($1, PROD, $3); } e DIV e { $$.val=calcula($1, DIV, $3); } SUB e { $$.val=-$2.val; } OPENBR e CLOSEBR { $$.val=$2.val; } ID { $$.val=getvalor($1); } INT REAL ; %% (...)
5. ii. Pl5Ex5.y (...) Propostas de Exercícios int main() { while(1){ int nerr=0; printf(" %-8f :: ",resultado); yyparse(); } return 0; } int yyerror(char *s) { nerr++; printf("erro SEMANTICO: %s\n",s); } (...)
5. ii. Pl5ex5.y (...) Propostas de Exercícios void setvalor(svalor x, SValor y) { int indice=x.id - 'a'; memoria[indice]=y.val; } float getvalor(svalor x) { int indice=x.id - 'a'; resultado=memoria[indice]; return(resultado); } (...)
5. ii. Pl5Ex5.y (...) Propostas de Exercícios float calcula (SValor v1, int op, SValor v2) { switch(op){ case ADD: resultado=v1.val+v2.val; break; case SUB: resultado=v1.val-v2.val; break; case PROD: resultado=v1.val*v2.val; break; case DIV: resultado=v1.val/v2.val; } } return resultado;
Exercício de aula Desenvolver um analisador sintático, recorrendo ao flex e ao bison, que permita validar informação de datas segundo a seguinte gramática: data: NUM '-' NUM '-' YEAR NUM '.' MONTH '.' NUM NUM '/' NUM '/' NUM ; Onde NUM é um numero de dois dígitos, YEAR num número de quatro dígitos e MONTH é uma palavra. O analisador sintático deverá verificar a validade da data também no sentido da existência real da mesma.
Algoritmo de análise do BISON O funcionamento do BISON baseia-se numa pilha, onde são inseridos os tokens e os lexemas. Sempre que uma sequencia de tokens faz match com a regra atual, estes tokens são substituídos pela regra. A inserção de tokens na pilha é chamada de shift e a substituição dos tokens por regras é chamada de reduce.
Algoritmo de análise do BISON Gramática (recursiva à ESQUERDA): lista: INT Frase: 12,20,30 lista ',' INT PILHA
Algoritmo de análise do BISON Gramática (recursiva à esquerda): lista: INT Frase: 12,20,30 lista ',' INT PILHA PILHA shift INT reduce lista
Algoritmo de análise do BISON Gramática (recursiva à esquerda): lista: INT Frase: 12,20,30 lista ',' INT PILHA shift, lista
Algoritmo de análise do BISON Gramática (recursiva à esquerda): lista: INT Frase: 12,20,30 lista ',' INT PILHA PILHA shift INT, lista reduce lista
Algoritmo de análise do BISON Gramática (recursiva à esquerda): lista: INT Frase: 12,20,30 lista ',' INT PILHA shift, lista
Algoritmo de análise do BISON Gramática (recursiva à esquerda): lista: INT Frase: 12,20,30 lista ',' INT PILHA PILHA shift INT, lista reduce lista
Algoritmo de análise do BISON Gramática (recursiva à DIREITA): lista: INT Frase: 12,20,30 INT ',' lista PILHA
Algoritmo de análise do BISON Gramática (recursiva à direita): lista: INT Frase: 12,20,30 INT ',' lista PILHA shift INT
Algoritmo de análise do BISON Gramática (recursiva à direita): lista: INT Frase: 12,20,30 INT ',' lista PILHA shift, INT
Algoritmo de análise do BISON Gramática (recursiva à direita): lista: INT Frase: 12,20,30 INT ',' lista PILHA shift INT, INT
Algoritmo de análise do BISON Gramática (recursiva à direita): lista: INT Frase: 12,20,30 INT ',' lista PILHA shift, INT, INT
Algoritmo de análise do BISON Gramática (recursiva à direita): lista: INT Frase: 12,20,30 INT ',' lista PILHA PILHA shift INT reduce lista,, INT INT,, INT INT
Algoritmo de análise do BISON Gramática (recursiva à direita): lista: INT Frase: 12,20,30 INT ',' lista PILHA PILHA lista, INT, INT reduce lista, INT
Algoritmo de análise do BISON Gramática (recursiva à direita): lista: INT Frase: 12,20,30 INT ',' lista PILHA PILHA lista, INT reduce lista
Algoritmo de análise do BISON O funcionamento do analisador sintático pode ser acompanhado com detalhe utilizando a opção v (--verbose) no comado bison ou incluindo a diretiva %verbose no ficheiro ".y" Estes mecanismos produzem a criação de um ficheiro de extensão ".output", contendo informação sobre o funcionamento do analisador sintático (gramática, conflitos, símbolos terminais e não terminais e os estados do autómato gerado pelo BISON)
Algoritmo de análise do BISON calc.y %token NUM STR %left '+' '-' %left '*' %start exp %% exp: exp '+' exp exp '-' exp exp '*' exp exp '/' exp NUM ; useless: STR; %%
calc.output 1ª secção refere os símbolos e as regras que não são utilizadas na gramática as regras (e os símbolos não terminais) inúteis são removidas para produzir um parser mais reduzido os tokens não utilizados na gramática são preservados uma vez que podem ser reconhecidos pelo analisador léxico Nonterminals useless in grammar useless Terminals unused in grammar STR Rules useless in grammar 6 useless: STR
calc.output 2ª secção são listados os estados que têm conflitos State 8 conflicts: 1 shift/reduce State 9 conflicts: 1 shift/reduce State 10 conflicts: 1 shift/reduce State 11 conflicts: 4 shift/reduce
calc.output 3ª secção o BISON apresenta a gramática que é de facto utilizada Grammar 0 $accept: exp $end 1 exp: exp '+' exp 2 exp '-' exp 3 exp '*' exp 4 exp '/' exp 5 NUM e descreve a utilização dos símbolos Terminals, with rules where they appear ( ) Nonterminals, with rules where they appear ( )
calc.output 4ª secção especificação do autómato, com a descrição de cada estado e das respetivas transições (pointed rules) cada transição é uma regra de produção onde o. representa a localização atual do cursor de entrada State 0 0 $accept:. exp $end NUM shift, and go to state 1 exp go to state 2 State 1 5 exp: NUM. $default reduce using rule 5 (exp)
Algoritmo de análise do BISON O BISON pode produzir outras visualizações desta informação: Ficheiro DOT - opção g (--graph) Formato Graphviz Visualizador online em: http://graphviz-dev.appspot.com/ Ficheiro XML - opção -x (--xml ) [=FILE] Este ficheiro pode ser transformado para HTML recorrendo a uma transformação XSLT
Conflitos BISON reduce/reduce Ocorre quando o BISON pode realizar reduce a duas regras simultaneamente Este erro deve-se normalmente a questões de ambiguidade da gramática DEVE SER SEMPRE CORRIGIDO
reduce/reduce Conflitos BISON Ocorre quando o BISON pode realizar reduce a duas regras simultaneamente sequencia: /* vazio */ talvez sequencia palavra ; talvez: /* vazio */ palavra ; palavra: TOKEN ; <sequencia> <sequencia><palavra> /*vazio*/<palavra> TOKEN <sequencia> <talvez> <palavra> TOKEN
Conflitos BISON - reduce/reduce Frase: TOKEN sequencia: /* vazio */ talvez sequencia palavra ; talvez: /* vazio */ palavra ; palavra: TOKEN ; shift TOKEN reduce palavra reduce talvez /*vazio*/ reduce sequencia palavra palavra
Conflitos BISON shift/reduce Ocorre quando o BISON pode realizar shift de um token ou reduce a uma regra simultaneamente Este erro deve-se normalmente a questões de ambiguidade da gramática O BISON resolve sempre este conflito usando o shift
shift/reduce Conflitos BISON Ocorre quando o BISON pode realizar shift de um token ou reduce a uma regra simultaneamente if_stmt: stmt: expr: IF expr THEN stmt IF expr THEN stmt ELSE stmt ; TOKEN if_stmt ; TRUE FALSE ; <if_stmt> IF <expr> THEN <stmt> IF <expr> THEN IF <expr> THEN <stmt> ELSE <stmt> <if_stmt> IF <expr> THEN <stmt> ELSE <stmt> IF <expr> THEN IF <expr> THEN <stmt> ELSE <stmt>
Conflitos BISON - shift/reduce Frase: IF <expr> THEN IF <expr> THEN <stmt> ELSE <stmt> if_stmt: IF expr THEN stmt IF expr THEN stmt ELSE stmt ; stmt: TOKEN if_stmt ; expr: TRUE FALSE ; shift ELSE stmt stmt THEN THEN expr expr IF THEN IF THEN reduce if_stmt THEN expr expr expr IF IF IF
Propostas de Exercícios 6. Considere um simulador de uma máquina de venda automática que dispõe de um conjunto de produtos e aceita moedas em euros ( 0.01, 0.02, 0.05, 0.10, 0.20, 0.50, 1.00, 2.00). O objetivo é selecionar um produto, introduzir o respetivo valor, receber o troco (se existir) e receber o produto. Considere os seguintes produtos: café ( 0.35), pingo ( 0.35), chá ( 0.35), chocolate ( 0.40), copo ( 0.05) e leite ( 0.30). O formato de entrada de dados deve obedecer à seguinte regra: <produto>,<moeda_1>,...<moeda_n> O formato de saída deve obedecer à seguinte regra: <produto>, <moeda_1>,...<moeda_n> "dinheiro insuficiente" Defina a gramática para que a máquina funcione sem interrupções e implemente-a utilizando o FLEX e o BISON.
Linguagens e Programação BISON