(Created page with "== 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 '''...") |
(→How to Compile?) |
||
(6 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
+ | {{TOCright}} | ||
== Problema == | == Problema == | ||
Line 6: | Line 7: | ||
Por exemplo, na seguinte assinatura, os argumentos estarão (respectivamente), nas posições 8, 12, 16 e 17: | Por exemplo, na seguinte assinatura, os argumentos estarão (respectivamente), nas posições 8, 12, 16 e 17: | ||
− | < | + | <source lang="c++"> |
void f(int a, char *b, char c, double d); | void f(int a, char *b, char c, double d); | ||
− | </ | + | </source> |
== The Lexical Analyzer (Flex) Specification == | == The Lexical Analyzer (Flex) Specification == | ||
The lexical analyzer ('''funcoffs.l''') is very simple and limited to recognizing the indispensable tokens. | The lexical analyzer ('''funcoffs.l''') is very simple and limited to recognizing the indispensable tokens. | ||
− | <text> | + | <source lang="text"> |
%option 8bit noyywrap yylineno | %option 8bit noyywrap yylineno | ||
%{ | %{ | ||
Line 33: | Line 34: | ||
%% | %% | ||
− | </ | + | </source> |
== The Syntactic Analyzer (YACC) Specification == | == 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). | 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> | + | <source lang="text"> |
%{ | %{ | ||
#include <string> | #include <string> | ||
#include <iostream> | #include <iostream> | ||
+ | extern int yylex(); | ||
inline void yyerror(const char *msg) { std::cerr << msg << std::endl; } | inline void yyerror(const char *msg) { std::cerr << msg << std::endl; } | ||
%} | %} | ||
Line 80: | Line 82: | ||
| tFLOAT { $$ = 4; } | | tFLOAT { $$ = 4; } | ||
| tDOUBLE { $$ = 8; } | | tDOUBLE { $$ = 8; } | ||
+ | | tVOID '*' { $$ = 4; } | ||
| atype '*' { $$ = 4; } | | atype '*' { $$ = 4; } | ||
; | ; | ||
%% | %% | ||
− | |||
extern int yyparse(); | extern int yyparse(); | ||
int main() { | int main() { | ||
return yyparse(); | return yyparse(); | ||
} | } | ||
− | </ | + | </source> |
== How to Compile? == | == How to Compile? == | ||
Line 99: | Line 101: | ||
The YACC specification is processed as follows (files '''y.tab.h''', needed by the Flex-generated code, and '''y.tab.c'''): | The YACC specification is processed as follows (files '''y.tab.h''', needed by the Flex-generated code, and '''y.tab.c'''): | ||
− | + | bison -dtv funcoffs.y | |
Compiling the C/C++ code (it is C++ simply because we programmed the extra code in that language): | Compiling the C/C++ code (it is C++ simply because we programmed the extra code in that language): |
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:
void f(int a, char *b, char c, double d);
The lexical analyzer (funcoffs.l) is very simple and limited to recognizing the indispensable tokens.
%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
%%
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).
%{
#include <string>
#include <iostream>
extern int yylex();
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 yyparse();
int main() {
return yyparse();
}
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):
bison -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