Difference between revisions of "The YACC Parser Generator/Exercise 5"

From Wiki**3

< The YACC Parser Generator
(The Syntactic Analyzer (YACC) Specification)
Line 81: Line 81:
 
       | tFLOAT          { $$ = 4; }
 
       | tFLOAT          { $$ = 4; }
 
       | tDOUBLE        { $$ = 8; }
 
       | tDOUBLE        { $$ = 8; }
 +
      | tVOID '*'      { $$ = 4; }
 
       | atype '*'      { $$ = 4; }
 
       | atype '*'      { $$ = 4; }
 
       ;
 
       ;

Revision as of 12:47, 7 April 2017

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 %{

  1. include <string>
  2. 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> %{

  1. include <string>
  2. 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 tID %token tVOID tCHAR tSHORT tINT tFLOAT tDOUBLE

%type args atype

%type

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