The YACC Parser Generator/Exercise 5: Difference between revisions

From Wiki**3

< The YACC Parser Generator
 
Line 1: Line 1:
{{TOCright}}
#REDIRECT [[ist:The YACC Parser Generator/Exercise 5]]
== Problema ==
 
O problema a resolver consiste na localização na pilha dos argumentos actuais de uma função C++. Considere que os argumentos apenas podem ser dos tipos '''char''', '''short''', '''int''', ponteiro, '''float''' e '''double''' (ocupando, respectivamente, 1, 2, 4, 4, 4 e 8 bytes). Considere ainda que o argumento mais à esquerda está na posição 8.
 
Construa um ficheiro YACC (.y) que receba uma assinatura de uma função e que imprima a posição de cada argumento.  Considere que a especificação Flex (não é necessário implementá-la) detecta os seguintes tokens: '''tVOID''', '''tID''', '''tCHAR''', '''tSHORT''', '''tINT''', '''tFLOAT''', '''tDOUBLE''', '''(''', ''')''', ''',''', '''*''' e ''';'''.
 
Por exemplo, na seguinte assinatura, os argumentos estarão (respectivamente), nas posições 8, 12, 16 e 17:
<cpp>
void f(int a, char *b, char c, double d);
</cpp>
== The Lexical Analyzer (Flex) Specification ==
 
The lexical analyzer ('''funcoffs.l''') is very simple and limited to recognizing the indispensable tokens.
<text>
%option 8bit noyywrap yylineno
%{
#include <string>
#include "y.tab.h"
%}
%%
 
"void"                  return tVOID;
"char"                  return tCHAR;
"short"                return tSHORT;
"int"                  return tINT;
"float"                return tFLOAT;
"double"                return tDOUBLE;
 
[_A-Za-z][_A-Za-z0-9]*  yylval.s = new std::string(yytext); return tID;
[,()*;]                return *yytext;
 
.|\n                    ; // ignore the rest
 
%%
</text>
 
== The Syntactic Analyzer (YACC) Specification ==
 
The syntactic analyzer ('''funcoffs.y''') will be built to immediately compute the expressions in a syntax-directed fashion as they occur. It is, thus, important to use trees that build nodes as the expressions occur (left-recursive grammars).
<text>
%{
#include <string>
#include <iostream>
inline void yyerror(const char *msg) { std::cerr << msg << std::endl; }
%}
%union {
  int i;
  std::string *s;
  std::pair<int, std::string> *p;
}
 
%token <s> tID
%token tVOID tCHAR tSHORT tINT tFLOAT tDOUBLE
 
%type <i> args atype
%type <p> arg
 
%%
 
funcs: func
    | funcs func
    ;
 
func : rtype tID '('      ')' ';'
    | rtype tID '(' args ')' ';'
    ;
 
args : arg              { std::cout << $1->second << "@" << ($$ =  8) << std::endl; $$ += $1->first; delete $1; }
    | args ',' arg    { std::cout << $3->second << "@" << ($$ = $1) << std::endl; $$ += $3->first; delete $3; }
    ;
 
arg  : atype tID        { $$ = new std::pair<int,std::string>($1,*$2); delete $2; }
    ;
 
rtype : tVOID | tCHAR | tSHORT | tINT | tFLOAT | tDOUBLE | rtype '*' ;
 
atype : tCHAR          { $$ = 1; }
      | tSHORT          { $$ = 2; }
      | tINT            { $$ = 4; }
      | tFLOAT          { $$ = 4; }
      | tDOUBLE        { $$ = 8; }
      | tVOID '*'      { $$ = 4; }
      | atype '*'      { $$ = 4; }
      ;
 
%%
extern int yylex();
extern int yyparse();
int main() {
  return yyparse();
}
</text>
 
== How to Compile? ==
 
The Flex specification is processed as follows (the file '''lex.yy.c''' is produced):
 
  flex funcoffs.l
 
The YACC specification is processed as follows (files '''y.tab.h''', needed by the Flex-generated code, and '''y.tab.c'''):
 
  byacc -dtv funcoffs.y
 
Compiling the C/C++ code (it is C++ simply because we programmed the extra code in that language):
 
  g++ -c lex.yy.c
  g++ -c y.tab.c
  g++ -o funcoffs y.tab.o lex.yy.o
 
[[category:Compiladores]]
[[category:Ensino]]

Latest revision as of 23:42, 5 December 2018