Você está na página 1de 36

Acciones Semnticas

terminales y no terminales de la gramtica A B C D se asocian con el tipo de su valor semntico

- la accin semntica de A debe retornar un valor cuyo tipo sea el asociado a A - valor de A se puede construir de B,C,D

Parser Recursivos Descendentes: acciones semnticas son los valores retornados por las funciones, o sus efectos colaterales.

Diseo de Compiladores

Intrprete para Expr. Aritmticas usando Parsers recursivos descendentes


1. S E$ 4. T --> F T 6. F --> ( E ) | id | num 2. E --> T E

3. E--> + T E | 5. T --> * F T |
S E E T T FT T F F num T FT T F id T *FT F (E) num S E$ E TE id + S E$ E TE E +TE T FT T T * ( ) S E$ E TE E $

Diseo de Compiladores

Intrprete para Parsers recursivos descendentes


union tokenval { string id, int num; ....} tokval ; int F_follow[ ] = { MAS, POR, PARDER, EOF } ; int F(void) switch (tok) { case ID: int i = lookup( tokval.id );advance( );return i; case NUM: int i = tokval.num; advance( );return i; case PARIZQ: eat(PARIZQ); { int i = E( ) ; eatOrSkipTo(PARDER,F_follow); return i ; default: printf(se esperaba ID,NUM o par-izquierdo) ; return 0; } int T_follow[ ] = { MAS, PARDER, EOF } ; int T(void) switch (tok) { case ID: case NUM: case PARIZQ: return Tprimo( F( ) ) ; default: printf(se esperaba ID,NUM, par-izquierdo);skipto(T_follow); return 0; } int Tprimo(int a) switch (tok) { case POR: eat(POR);return Tprimo(a * F( )) ; case MAS: case PARDER case EOF: return a; default: ........ }
Diseo de Compiladores

Intrprete para Parsers recursivos descendentes


T fue agregado al eliminar la recursin izquierda. Es un smbolo artificial, y no es directa la accin semntica como sucede en: T T*F { int a, b; a = T ( ); eat ( POR ); int b = F ( ); return a * b; }

Se arregla para que se pueda interpretar ej: id1 * id2 $ E TE F T E T ( F ( ) ) E T ( a) E T ( a*F()) E ...

Diseo de Compiladores

Intrprete para Parsers Generados por YACC


Se asocian acciones semnticas a las reglas %union { int num; string id ;} % token <num> INT % token <id> ID % type <num> expr % left MAS Se definen tipos % left POR para terminales y %% no terminales expr : INT {$$ = $1;} | ID { $$ = Lookup ( $1 ); } | expr MAS expr { $$ = $1 + $3 ; } | expr POR expr { $$ = $1 * $3 ; } | ( expr ) { $$ = $1 ; } ; %%
Diseo de Compiladores

Stack semntico de Yacc


Stack INT expr expr + expr + INT expr + expr expr + expr * expr + expr * INT expr + expr * expr expr + expr expr Stack semntico 1 1 1 1 2 1 2 1 2 1 2 3 1 6 1 6 7 Input 1+2 *3$ +2 *3 $ +2 *3 2 *3 *3 *3 3 $ $ $ $ $ $ $ $ $ Accin shift reducir shift shift reducir shift shift reducir reducir reducir reducir

Diseo de Compiladores

Stack semntico de Yacc-CUP


El stack semntico contiene los valores de los atributos. Este stack corre en paralelo al stack del parser. Al reducir una produccin los k valores de ms arriba del stack corresponden a los k atributos del lado derecho de la produccin expr : expr + expr expr ::= expr : a MAS expr : b { $$ = $1 + $3 } {: RESULT=a+b :}

Diseo de Compiladores

Pasadas en un compilador
Compiladores de 1 pasada : todo el compilador se genera en las acciones semnticas. ms rpido, menos memoria en caso computador lento. pueden condicionar definicin de lenguajes, por ej: procedimientos forward de Pascal. Compiladores ms modernos, muchas pasadas (5-15) ms modular, menos limitaciones Entre las pasadas, el compilador genera representaciones intermedias, si usa k pasadas, entonces genera k-1 representaciones intermedias.

Diseo de Compiladores

Arboles sintcticos abstractos (AST)


Arbol de parser: terminales una hoja produccin aplicada nodo interior Almacenan informacin redundante. E AST: son rboles de parser sin no-terminales, contiene solo la informacin esencial. Ms apropiado como representacin intermedia. + id id * id
Diseo de Compiladores

E T F id

+ T F id

T * F id

Construyendo el AST en Yacc


Consideremos el lenguaje de las sentencias lineales y las expresiones. S S S S;S id := E print( L ) E E E E id num EBE (S,E) L L B E L,E +|-|*|/ Prod S E L id num Typedef T_sent T_exp T_listaexp string int
Diseo de Compiladores

Cada no terminal lo asociamos con una estructura que representa un nodo del rbol :

typedef struct T_sent_ *T_sent typedef struct T_exp_ *T_exp typedef struct T_listaexp_ *T_listaexp typedef struct char *string typedef enum { Kmas,Kmenos,Kdiv,Kpor } T_binop

Construyendo el AST en Yacc


Sentencias Definicin del nodo struct T_sent_ { enum {Kcompuesta, Kasignacion, Kprint } tipo; union { struct {T_sent sent1, sent2; } compuesta; struct { string id; T_exp exp; } asignacion; struct { T_exp exp; } impresion; }u; }; Funciones constructoras T_sent C_Compuesta(T_sent sent1, T_sent sent2); T_sent C_Asignacion(string id; T_exp exp); T_sent C_Print(T_exp exp);
Diseo de Compiladores

Construyendo el AST en Yacc


Expresiones Definicin del nodo struct T_exp_ { enum { Kidexp, Knumexp, Kopexp,Kseqexp } tipo; union { string id; int num; struct { T_exp izq; T_binop binop; T_exp der) op; struct { T_sent sent, T_exp exp } eseq; } u; }; Funciones constructoras T_exp C_IdExp(string id); T_exp C_ NumExp(int num); T_exp C_ OpExp(T_exp izq, T_binop oper, T_exp der); T_exp C_ SeqExp(T_sent sent; T_exp exp)
Diseo de Compiladores

Construyendo el AST en Yacc


Lista de expresiones Definicin del nodo struct T_listaexp_ { enum { Kparlistaexp, Kfinlistaexp } tipo; union { struct { T_exp head; T_listaexp tail) par ; T_exp fin ; } u; }; Funciones constructoras T_listaexp C_ ListaExp(T_exp uno,T_listaexp sig) ;
Diseo de Compiladores

Construyendo el AST en Yacc


Gramtica 1er. parte %union { int num; string id; T_sent sent; T_exp exp; } %token <num> INT %token <id> ID %token ASSIGN | PRINT | PARIZQ | PARDER|COMA %type <T_sent> sent Prog %type <T_exp> exp %start Prog %left PTOYCOMA %left MAS MENOS %left POR DIV %%
Diseo de Compiladores

Prog: sent { $$ = $1 } Gramtica 2da. parte sent : sent PTOYCOMA sent { $$ = C_Compuesta($1,$3) ;} | ID ASSIGN exp { $$ = C_Asignacion($1,$3);} | PRINT ( exps ) { $$ = C_Print($3); } ; exps : exp | exps COMA exp ; exp : ID | INT | exp DIV exp | exp POR exp | exp MAS exp | exp MENOS exp | ' ( ' exp ' ) ' | sent COMA exp ; { $$ = C_ListaExp($1,NULL); } { $$ = C_ListaExp($1); } { $$ = C_IdExp($1); } { $$ = C_NumExp($1); } { $$ = C_OpExp($1,DIV,$3); } { $$ = C_OpExp($1,POR,$3); } { $$ = C_OpExp($1,MAS,$3); } { $$ = C_OpExp($1,MENOS,$3); } { $$ = $2;} { $$ = C_SeqExp($1, $3) ; }
Diseo de Compiladores

Construyendo el AST en Yacc

Chequeo de Tipos
Funciones: - determinar el tipo de todas las expresiones - verificar valores y variables se usan correctamente - resolver ambiguedades mediante transformaciones al programa, ej: conversiones de tipos Info de declaraciones se almacena en la tabla de smbolos Al referenciar un nombre se consulta la tabla de smbolos y se valida los tipos. Chequeo esttico: tipos se chequean en tiempo de compilacin Chequeo dinmico: se genera cdigo para chequear los tipos en tiempo de ejecucin
Ejemplo: var table : array[ 0.255] i : int table [ i ] , i debe estar entre 0255
Diseo de Compiladores

Expresiones de tipo (tipos)


Tipos bsicos: boolean, integer, real, tambin void y tipo-error Tipos estructurados: aplican constructores a tipos bsicos o estructurados. Nombres de tipos: tipos son etiquetadas por nombres
ej: TYPE foo = INTEGER

Tipos implcitos ej. constantes en Pascal: CONST saludos=Hola Tipos explcitos

Diseo de Compiladores

Expresiones de tipo (tipos)


Constructores Array: Si T es un tipo entonces ARRAY(I, T) es un tipo que denota un array de elementos de tipo T e ndice I. - se usa el ndice para acceder a los elementos - se imponen restricciones a los ndices: - Pascal: tipos ordinales, array [ color ] of char se especifica el - C: enteros, typedef char A[ 3 ];
largo en vez del ndice

Punteros: Si T es un tipo, POINTER(T) es un tipo que denota un puntero a un objeto de tipo T. Funcin: Si D es un dominio de tipo D y R codominio de tipo R, f: D R es un producto que denota tipo de argumentos.
function f ( a, b : integer ) : ^real integer x integer pointer(real)
Diseo de Compiladores

Constructores Productos: Si T1...Tn son tipos, T1 x...x Tn es el producto cartesiano que representa un tipo producto. Records: - Se usan nombres para acceder a los elementos Si Ti x Ni es el tipo y el nombre del elemento i entonces (T1 x N1 ) x (T2 x N2 ) .... x(Tn x Nn ) representa un tipo record
TYPE fila = RECORD posicion: INTEGER; palabra : ARRAY 10 OF CHAR; END ( posicion x INTEGER) x ( palabra x ARRAY(0...9) of CHAR)

Expresiones de tipo (tipos)

Funciones: D

R
Diseo de Compiladores

Chequeo de tipos en declaraciones en Oberon


Tipo se pueden definir en declaraciones de tipo o de variables
Decl_Tipo Tipo Decl_Var Decl_Tipo ID = tipo ; | ID | ARRAY array | POINTER TO type | RECORD type | PROCEDURE type ID : tipo | .

Para un nivel de scope:

- construir los tipos - dar altas en tabla de smbolos - calcular direcciones, ej: offsets

Scope: procedimientos delimitan scopes, al ingresar a un procedimiento, se incrementa el nivel, al salir se decrementa
Decl_Procedure -> Cab_Proc ; Secuencia_Decl Cuerpo ID entro_scope salgo_scope
Diseo de Compiladores

Representacin Concreta de Tipos en Oberon typedef struct type * Type;


typedef struct product *Product; struct product { Product link; /*prximo producto(param.) en la lista*/ unsigned var: 1; /*si es param. por referencia o valor */ char * name; /*nombre del param: */ Type type; }; /*tipo del param */ typedef enum typeop { Void = 1, Integer, Real, Boolean, Char, Byte, Pointer,Array, Record, Procedure } TypeOp; struct type { TypeOp op; /* tipo de objeto(tipo) */ int size; /* tamao del tipo */ Type type; /* puntero a otro tipo */ union { int len; /* largo del array */ Product args; /* lista de param. en proc.*/ Product fields; /* lista de campos en record */ char *name; } u; /* nombre del tipo */ } Type type(TypeOp, int); /* crea un nodo para el tipo TypeOp y tamao int*/ Product product(char *, Type) /* crea un nodo para el producto */
Diseo de Compiladores

Ejemplo de tipos en Oberon


POINTER TO RECORD a: INTEGER; b: ARRAY 10 OF BYTE; exp: POINTER TO node; END;
Pointer 4

struct product
Record 20

exp

struct type

Integer 4

Array 10 10

Byte 1

Pointer 4

Tamao de record se alinea a palabra

node
Diseo de Compiladores

Ejemplo de tipos en Oberon


ARRAY 10,10 OF REAL
Array 800 10 Array 80 10 Real 8

POINTER TO b
Pointer 4

Punteros: slo a ARRAYS o RECORDS POINTER TO ARRAY 10 OF REAL


Pointer 4 Array 80 10 Real 8

luego que terminamos de scannear una procedure, verificamos que no queden referencias no resueltas y que el tipo sea array o record

Diseo de Compiladores

Representacin Concreta de Smbolos en Oberon


Nuevos campos a agregar en la tabla de smbolos:
typedef enum kind { KConst, KType, KVar, KProcedure, KParam } Kind; typedef struct simbolo { char * nombre; int scope; Kind kind; struct type *type; union { int offset : /* aVar, aParam: offset en stack */ int ivalor : /* aConst: valor entero */ double rvalor : /* aConst: valor real */ } u; } *Simbolo extern int nivel;
Diseo de Compiladores

Ejemplo de smbolos en Oberon


CONST pi = 3.1416; TYPE simbolo = POINTER TO RECORD . . . . . . END; VAR a: INTEGER; a simbolo pi

3 KVar offset

3 KType

3 KConst 3.1416

Integer 4

Pointer 4

Record 20

Real 4

Diseo de Compiladores

Traduciendo las declaraciones


Mantenemos informacin del scope: al inicio y fin de la declaracin de procedimiento.
DeclProcedure : CabProcedure ; SecuenciaDecl cuerpo ID CabProcedure procedure { . }

: procedure ParamsFormales { $1 ->type = $2; $$ = $1;} : PROCEDURE ID { $$ = insert($2); $$->KIND = KProcedure; entro_scope ( ) ; }

cuerpo

: BEGIN secuencia_sentencias END { dejo_scope ( ) } Verifico el nombre de procedure coincida en cabezal y fin

retorna nodo simboloprocedure

retorna nodo tipo procedure


Diseo de Compiladores

Declaraciones en Oberon
Declaracin de variables
DeclVariable : | ID : type { Simbolo p = insert($1);} p->kind = KVar; p->type = $3; $$ = $3; } ID , Declvariable { Simbolo p = insert($1);} p->kind = KVar; p->type = $3; $$ = $3; }

Declaracin de tipos
type : ID

| | | ;

{ Simbolo p = lookup($1);} if ( p && p->kind == kType ) $$=p->type; else . } ArrayType PointerType RecordType
Diseo de Compiladores

Declaraciones de Records
Construyo una lista de productos (T1 x N1 ) x (T2 x N2 ) .... x(Tn x Nn ) Calculo el largo del registro luego de construir el producto
RecordType : RECORD Lista_Sec_Campos END { Product p; $$ = type(Record,0); $$ ->u.fields = $2 ; for ( p = $2; p; p = p->link ) $$->size += p->type->size; $$->size=roundup($$->size,align($$)); }

Lista_Sec_Campos : Lista_Sec_Campos ; Campos {$$=fields($1,$3);} | Campos { $$ = $1; } Campos : ID : type { $$ = product($1, $3); } | ID , Campos { $$ = product($1, $3->type); $$->link = $3; }

Verificar nombre y tipo de campos sean nicos


Diseo de Compiladores

Declaraciones de Arrays
Arrays multi-dimensional:
ArrayType : ARRAY Array ; Array

arrays n, m of type

{ $$ = $2 }

: expr OF type { $$ = type(Array, $1->u.ivalor*$3->size); $$->u.len = $1->u.ivalor;$$->type=$3; } | expr , Array { $$ = type(Array, $1->u.ivalor*$3->size); $$->u.len = $1->u.ivalue ;$$->type=$3; } ;

Verificar expr sea constante entera.

Diseo de Compiladores

Declaracin de Punteros
PointerType : POINTER TO ArrayType { $$ = type(Pointer,4); $$ ->type = $3 ;} | POINTER TO RecordType { $$ = type(Pointer,4); $$ ->type = $3 ;} | POINTER TO ID { simbolo p= lookup($3) if (p && (p->type->op == ARRAY || p->type->op==RECORD) { $$ = type(Pointer,4) $$->type = p->type else error } ;

Verifico puntero sea a tipo array o record (restriccin del lenguaje )

Diseo de Compiladores

Chequeo de Tipos en Oberon


Union de Yacc incluir tipos: - type, product, simbolo, ....interger
S S S S id : = E { if id.type = E.type then S.type : = void else S.type : = type_error }

if E then S { if E.type = boolean then S.type : = S1.type else S.type : = type_error } while E do S { if E.type = boolean then S.type : = S1.type else S.type : = type_error } S;S { if 1.type = void and S2.type = void then S.type = void else S.type : = type_error }

Diseo de Compiladores

Chequeo de Tipos de Expresiones


Las traducciones para expresiones sintetizan el atributo type y chequean por operadores compatibles
E --> literal E --> num E --> id E --> E mod E { E.type : = char } { E.type := integer } { E.type : = lookup ( id.entry ) }
integer x integer --> integer

{ if E1.type = integer and E2.type = integer then E.type = integer else E.type = type_error } array(I,T) x integer --> T { if E1.type = array( I, T ) and E2.type = integer then E.type = T pointer(T) --> T else E.type = type_error } { if E1.type = pointer( T ) then E.type = T else E.type : = type_error }
Diseo de Compiladores

E --> E [ E ]

E --> E ^

Chequeo de Tipos de Expresiones


E --> E = E < { if E1.type = integer and E2.type = integer or E1.type = boolean and E2.type = boolean then E.type = boolean else E.type = type_error } { if E1.type = boolean and E2.type = boolean then E.type = boolean else E.type = type_error } { if E1.type = D --> R and L.type = D then E.type : = R else E.type : = type_error } { L.type : = E.type } { L.type : = L1.type x E.type }
Diseo de Compiladores

E --> E & E or E --> E ( L ) L --> E L --> L , E

Equivalencia estructural entre expresiones T1 y T2 son equivalentes sii estn compuestas por los mismos constructores en el mismo momento Equivalencia por nombre entre expresiones T1 y T2 son equivalentes sii T1 y T2 tiene los mismos nombres de tipos Ej : type link = * celda por nombre var next : link ; estructural last: * celda ;
variable next last nombre del tipo link T tipo de la expr pointer(celda) pointer(celda)
Diseo de Compiladores

Equivalencia de tipos en las expresiones

Equivalencia de tipos en las expresiones


Pascal : si una declaracin contiene un tipo que no es un nombre , un nombre implcito es creado Ej: type link = * celda type link = * celda var next: link np = * celda var last: link nqr = * celda p: * celda var next : link q,r: *celda last: link p : np q : nqr r : nqr
Diseo de Compiladores

Conversin de Tipos
Conversiones implcitas: ocurren como resultado de aplicar reglas semnticas al lenguaje ej : x + i x es real, i es entero, se produce una conversin implcita del valor entero al real durante la adicin. Conversiones explcitas: el programador debe especificar la conversin ej: casts en C, ord y chr en Pascal y Oberon - Conversiones complican el chequeo de tipos al traducir
E --> E + E { case (E1.type, E2.type) in (integer,integer): E.type = integer (integer,real) , (real,integer), (real,real): E.type = real else E.type = type_error }
Diseo de Compiladores

Você também pode gostar