UNIVERSIDAD GERARDO BARRIOS
Facultad de ciencias y tecnologias
e-Portafolio de evidencias
Catedra: Compiladores e interpretes
Tutor: Ing. Marvin Osmaro Parada
Alumno: Herson Enrique Chorro Ventura
Producción
|
Reglas
semántica
|
S à id := E
|
S. Código
:= E. código || gen (id. lugar ':=' E. lugar)
|
E à E1 +E2
|
E. lugar
:= tempnuevo;
E. código
:= E1. código || E2. código || gen(E. lugar ':=' E1. lugar '+' E2.lugar)
|
E à E1 * E2
|
E. lugar
:= tempnuevo;
E. código
:= E1. código || E2. código || gen(E. lugar ':=' E1. lugar '*' E2.lugar)
|
E à -E1
|
E. lugar
:= tempnuevo;
E. código
:= E1. código || gen('E. lugar ':=' 'menosu' E1. lugar)
|
E à (E1)
|
E.
lugar := E1. lugar;
E. código
:= E1. código
|
E à id
|
E. lugar
:= id. lugar;
E.
código := ' '
|
Regla
Gramatical
|
Reglas
Semánticas
|
exp à id = exp2
|
exp1.pcode ="lda" ||id.strval++
exp2.pcode++"stn"
|
exp à aexp
|
exp. pcode
=aexp.pcode
|
aexp1à aexp2 + factor
|
aexp1.
pcode = aexp2.pcode ++ factor. pcode ++ "adi"
|
aexp à factor
|
aexp.
pcode =factor. pcode
|
factor à (exp)
|
factor.
pcode =exp. pcode
|
factor à num
|
factor.
pcode = "idc"||num.stval
|
factor à id
|
factor.
pcode = "lod"||id.strval
|
int a,b,c;
a/(b+c^2)
El árbol sintáctico es: /
---------
| |
a +
---------
| |
b ^
---------
| |
c 2
De la instrucción declarativa, la tabla de símbolos y el analizador morfológico obtenemos los atributos de los operandos: /
---------
| |
a +
int ---------
| |
b ^
int ---------
| |
c 2
int int
Propagando los atributos obtenemos: / int
---------
| |
a + int
int ---------
| |
b ^ int
int ---------
| |
c 2
int int
Si la expresión hubiera sidoa/(b+c^-2)El árbol sintáctico sería el mismo, sustituyendo 2 por -2. Sin embargo, la propagación de atributos sería diferente:
/ real
---------
| |
a + real
int ---------
| |
b ^ real
int ---------
| |
c -2
int int
En algún caso podría llegar a producirse error (p.e. si / representara sólo la división entera). int a,b,c,d;
a/(b+c^d)
El árbol sintáctico sería el mismo, sustituyendo 2 por d. Sin embargo, la propagación de atributos sería incompleta: / {int,real}
---------
| |
a + {int,real}
int ---------
| |
b ^ {int,real}
int ---------
| |
c d
int int
El analizador semántico podría reducir los tipos inseguros al tipo máximo (real) o utilizar un tipo interno nuevo (ej. arit={int,real}, una unión). real a;
int b,c;
a:=b+c
El árbol sintáctico es: :=
---------
| |
a +
real ---------
| |
b c
int int
Existen dos conversiones posibles: := real := real
--------- ---------
| | | |
a + real a + int
real --------- real ---------
| | | |
b c b c
int int int int
El problema es que no tenemos garantía de que los dos procedimientos sean equivalentes. El segundo puede dar overflow, el primero pérdida de precisión. La definición del lenguaje debe especificar estos casos.<AsSt> ::= id #PId := <Exp> #RAs <Exp> ::= <Exp> + <T> #RS | <T> <T> ::= id #PId | Ct #PCtSe observará que hemos hecho uso de cuatro símbolos de acción:
<AsSt> ::= <ASPI> := <Exp> #RAs <ASPI> ::= id #PId <Exp> ::= <Exp> + <T> #RS | <T> <T> ::= id #PId | Ct #PCtPoner un ejemplo del análisis sintáctico-semántico bottom-up de la instrucción A := B + 1.
<Instr> ::= If <Expr> #S2 then <Instr> #S1 |
If <Expr> #S2 then <Instr> else #S3 <Instr> #S1
Más adelante se verá cuáles son las tres acciones semánticas. Para que todas queden al final de una regla, basta cambiar estas reglas por: <Instr> ::= If <Expr1> then <Instr> #S1 |
If <Expr1> then <Instr> <Else> <Instr> #S1
<Expr1> ::= <Expr> #S2
<Else> ::= else #S3
a*b ab* a*(b+c/d) abcd/+* a*b+c*d ab*cd*+Los identificadores aparecen en el mismo orden. Los operadores en el de evaluación (de izquierda a derecha).
a*(-b+c/d) ab@cd/+*Existen dos problemas principales:
E ::= E + T Push + E ::= E - T Push - E ::= T T ::= T * F Push * T ::= T / F Push / T ::= F F ::= i Push i F ::= (E) F ::= - F Push @
<Operando> ::= id |
cte |
<Operando> <Operando> <Operador diádico> |
<Operando> <Operador monádico>
<Operador diádico> ::= + | - | * | / | ...
<Operador monádico> ::= @ | ...
Algoritmo de evaluación de una expresión en notación sufija que utiliza una pila:<Operando> ::= id
<Operando> ::= cte
<Operando> ::= <Operando> <Operando> <Operador diádico>
<Operando> ::= <Operando> <Operador monádico>
a:=b*c+d abc*d+:=
GOTO L L TR
if p then inst1 else inst2se convierte en
p L1 TRZ inst1 L2 TR inst2
L1: L2:
a[exp1; exp2; ...; expn]se convierte en
a exp1 exp2 ... expn SUBIN-n
(<Operador>, <Operando1>, <Operando2>, <Resultado>)Ejemplo:
(*,A,B,T)Una expresión se puede representar mediante un conjunto de cuádruplas. Ejemplo: la expresión a*b+c*d equivale a:
(*,a,b,t1) (*,c,d,t2) (+,t1,t2,t3)Ejemplo: la expresión c:=a[i;b[j]] equivale a:
(*,i,d1,t1) (+,t1,b[j],t2) (:=,a[t2],,c)
(1) (*,a,b) (2) (*,c,d) (3) (+,(1),(2))mientras que a*b+1 equivale a:
(1) (*,a,b) (2) (*,(1),1)Tripletes indirectos: se numeran arbitrariamente los tripletes y se da el orden de ejecución. Ejemplo, sean las instrucciones:
a := b*c b := b*cEquivalen a los tripletes
(1) (*,b,c) (2) (:=,(1),a) (3) (:=,(1),b)y el orden de ejecución es (1),(2),(1),(3). Esta forma es útil para preparar la optimización de código. Si hay que alterar el orden de las operaciones o eliminar alguna, es más fácil hacerlo ahí.
E ::= E + T E ::= E - T E ::= T T ::= T * F T ::= T / F T ::= F F ::= i F ::= (E) F ::= -FLa regla F::=i asocia a F como información semántica el identificador concreto.
Pila Entrada Regla Cuádrupla ----------- ------------- ------------ --------- | a*(b+c)| |a *(b+c)| F::=i |F(a) *(b+c)| T::=F |T(a) *(b+c)| |T(a)* (b+c)| |T(a)*( b+c)| |T(a)*(b +c)| F::=i |T(a)*(F(b) +c)| T::=F |T(a)*(T(b) +c)| E::=T |T(a)*(E(b) +c)| |T(a)*(E(b)+ c)| |T(a)*(E(b)+c )| F::=i |T(a)*(E(b)+F(c) )| T::=F |T(a)*(E(b)+T(c) )| E::=E+T |T(a)*(E(b)+T(c) )| E::=E+T (+,b,c,T1) |T(a)*(E(T1) )| |T(a)*(E(T1)) | F::=(E) |T(a)*F(T1) | T::=T*F (*,a,T1,T2) |T(T2) | E::=T |E(T2) |
unsigned int E (char *cadena, unsigned int i)
{
if (i<0) return i;
switch (cadena[i]) {
case 'i':
push (id);
i++;
i = V (cadena, i);
break;
case '(':
i++;
i = E (cadena, i);
i = C (cadena, i);
i = V (cadena, i);
break;
default: return -1;
}
return i;
}
unsigned int V (char *cadena, unsigned int i)
{
unsigned int j;
if (i<0) return i;
switch (cadena[i]) {
case '*':
case '/':
j = i;
i++;
i = T (cadena, i);
cuad (cadena[j], pop(), pop(), gen(Ti));
push (Ti);
i = X (cadena, i);
break;
case '+':
case '-':
j = i;
i++;
i = E (cadena, i);
cuad (cadena[j], pop(), pop(), gen(Ti));
push (Ti);
break;
}
return i;
}
unsigned int X (char *cadena, unsigned int i)
{
unsigned int j;
if (i<0) return i;
switch (cadena[i]) {
case '+':
case '-':
j = i;
i++;
i = E (cadena, i);
cuad (cadena[j], pop(), pop(), gen(Ti));
push (Ti);
break;
}
return i;
}
unsigned int T (char *cadena, unsigned int i)
{
if (i<0) return i;
switch (cadena[i]) {
case 'i':
push (id);
i++;
i = U (cadena, i);
break;
case '(':
i++;
i = E (cadena, i);
i = C (cadena, i);
i = U (cadena, i);
break;
default: return -2;
}
return i;
}
unsigned int U (char *cadena, unsigned int i)
{
if (i<0) return i;
unsigned int j;
switch (cadena[i]) {
case '*':
case '/':
j = i;
i++;
i = T (cadena, i);
cuad (cadena[j], pop(), pop(), gen(Ti));
push (Ti);
break;
}
return i;
}
unsigned int F (char *cadena, unsigned int i)
{
if (i<0) return i;
switch (cadena[i]) {
case 'i':
push (id);
i++;
break;
case '(':
i++;
i = E (cadena, i);
i = C (cadena, i);
break;
default: return -3;
}
return i;
}
unsigned int C (char *cadena, unsigned int i)
{
if (i<0) return i;
switch (cadena[i]) {
case ')':
i++;
break;
default: return -4;
}
return i;
}
<Instr> ::= If <Expr> S2 then <Instr> S1 |
If <Expr> S2 then <Instr> else S3 <Instr> S1
Una secuencia de cuádruplas equivalente a "If E1 then I1 else I2" (p-1) (?,?,?,t1) Análisis de E1
(p) (TRZ,(q+1),t1,) S2: Crear cuádrupla (p) | Push p
... Análisis de I1
(q) (TR,(r),,) S3: Crear cuádrupla (q)
Poner (cl.sig.) en top | Pop
Push (q)
(q+1) ... Análisis de I2
(r) S1: Poner (cl.sig.) en top | Pop
Una secuencia de cuádruplas equivalente a "If E1 then I1" (p-1) (?,?,?,t1) Análisis de E1
(p) (TRZ,(r),t1,) S2: Crear cuádrupla (p) | Push p
... Análisis de I1
(r) S1: Poner (cl.sig.) en top | Pop
Al generar la cuádrupla (p) no conocemos el valor de (q). Guardamos en una pila el número de la cuádrupla asociada y lo rellenamos más tarde, como indican los ejemplos.<Instr> ::= id : <Instr>Semántica asociada:
{
Buscar id en la tabla de símbolos;
if (no está)
Insertar id,valor=(etiqueta, declarada, cuádrupla siguiente);
else {
if (tipo==etiqueta && bit==no declarada) {
i=número de cuádrupla;
while (i) {
j=cuádrupla[i][2];
cuádrupla[i][2]=cuádrupla siguiente;
i=j;
}
Cambiar valor a (etiqueta, declarada, cuádrupla siguiente);
}
else error();
}
}
Sea la regla<Instr> ::= GOTO idSemántica asociada:
{
Buscar id en la tabla de símbolos;
if (no está) {
Insertar id,valor=(etiqueta, no declarada, cuádr.siguiente);
Generar cuádrupla (TR,,,);
}
else {
if (tipo==etiqueta) {
if (bit==declarada)
Generar cuádrupla (TR,número de cuádrupla,,);
else if (bit==no declarada) {
i=número de cuádrupla;
Cambiar valor a (etiqueta, no declarada, cuádr.siguiente);
Generar cuádrupla (TR,i,,);
}
}
else error();
}
}
Si se permiten etiquetas locales a bloques, podemos encontrar el siguiente caso: L: ...
{
...
GOTO L;
...
Tenemos ambigüedad: GOTO L puede ir a la etiqueta externa (ya definida o no) o a una etiqueta local al bloque posterior a la instrucción. Tenemos tres posibilidades: <Instr> ::= do <id> := <Expr> S1
, <Expr> S2
<CD1> <LInstr> end S5
<CD1> ::= , <Expr> S3 | ^ S4
Semántica asociada al análisis de "do x:=n1,n2,n3; I1; I2; end": Generar cuádruplas asociadas a instrucción de asignación x:=n1.
Guardar i=número de cuádrupla siguiente.
Guardar j=número de cuádrupla siguiente.
Generar cuádrupla (TRG,,x,(n2)).
Generar cuádrupla (TR,,,).
Generar cuádrupla (+,x,(n3),x).
Generar cuádrupla (TR,(i),,).
Hacer cuádrupla[j+1][2]=cuádrupla siguiente.
Generar cuádrupla (TR,(j+2),,).
Hacer cuádrupla[j][2]=cuádrupla siguiente.
Generar cuádrupla (:=,x,1,x).
Generar cuádrupla (TR,(i),,).
Hacer cuádrupla[j+1][2]=cuádrupla siguiente.
O | T F Y | T F NO| T F --|----- --|----- --|----- T | T T T | T F | F T F | T F F | F Fy la sintaxis adecuada para que la precedencia sea: NO, Y, O. Sin embargo, es posible simplificarlas considerablemente. Basta fijarse en la expresión
a Y (b O NO c)Si a es falso, no hace falta calcular el paréntesis, sabemos que el resultado es falso. Por tanto, redefiniremos la sintaxis y la semántica así:
<ZB> ::= <EB> <EB> ::= <TB> O <EB> | <TB> <TB> ::= <FB> Y <TB> | <FB> <FB> ::= i | ( <EB> ) | NO <FB> a O b <=> if (a) TRUE else b; a Y b <=> if (a) b else FALSE; NO a <=> if (a) FALSE else TRUE;
void ZB (char *cadena)
{
int FL=0, TL=0, i;
cuad (":=", "T", NULL, x);
i = EB (cadena, 0, &FL, &TL);
FILL (FL);
cuad (":=", "F", 0, x);
FILL (TL);
}
unsigned int EB (char *cadena, unsigned int i, int *FL, int *TL)
{
int tl=0;
i = TB (cadena, i, FL, &tl);
MERGE (TL, tl);
if (i<strlen(cadena)) switch (cadena[i]) {
case 'O':
i++;
FILL (*FL);
*FL = 0;
i = EB (cadena, i, FL, TL);
break;
default:
break;
}
return i;
}
unsigned int TB (char *cadena, unsigned int i, int *FL, int *TL)
{
int fl=0;
i = FB (cadena, i, &fl, TL);
MERGE (FL, fl);
if (i<strlen(cadena)) switch (cadena[i]) {
case 'Y':
i++;
FILL (*TL);
*TL = 0;
i = TB (cadena, i, FL, TL);
break;
default:
break;
}
return i;
}
unsigned int FB (char *cadena, unsigned int i, int *FL, int *TL)
{
if (i<strlen(cadena)) switch (cadena[i]) {
case 'i':
i++;
*TL = cuádrupla siguiente;
*FL = - cuádrupla siguiente;
cuad (TRB, id, 0, 0);
break;
case '(':
i++;
i = EB (cadena, i, FL, TL);
i = C (cadena, i);
break;
case 'NO':
i++;
i = FB (cadena, i, FL, TL);
*FL <-> *TL
break;
default: error (cadena, i);
}
else error (cadena, i);
return i;
}
unsigned int C (char *cadena, unsigned int i)
{
if (i<strlen(cadena)) switch (cadena[i]) {
case ')':
i++;
break;
default: error (cadena, i);
}
else error (cadena, i);
return i;
}
void FILL (int lista)
{
int i,j,n;
n = lista;
while (n) {
if (n>0) i=2; else i=3;
j = abs (n);
n = cuad[j][i];
cuad[j][i] = cuádrupla siguiente;
}
}
void MERGE (int *uno, int dos)
{
int i,k;
if (*uno==0) *uno = dos;
else {
k = *uno;
for (;;) {
if (k>0) i=2; else i=3;
k = abs (k);
if (cuad[k][i]==0) break;
k = quad[k][i];
}
cuad[k][i] = dos;
}
}
Analicemos "a O b O NO c" ZB ("a O b O NO c")
cuad (":=", "T", NULL, "X");
i = EB ("a O b O NO c", 0, &FL, &TL);
i = TB ("a O b O NO c", 0, FL, &tl);
i = FB ("a O b O NO c", 0, &fl, TL);
case id:
i=1;
*TL = 1;
fl = -1;
cuad (TRB, a, 0, 0);
MERGE (FL, fl);
FL = -1;
MERGE (TL, tl);
TL = 1;
case 'O':
i=2;
FILL (FL);
n = -1;
while (n) {
i = 3;
j = 1; (abs(FL))
n = 0; (cuad[1][3])
cuad[1][3] = 2;
}
FL = 0;
i = EB ("a O b O NO c", 2, FL, TL);
i = TB ("a O b O NO c", 2, FL, &tl);
i = FB ("a O b O NO c", 2, &fl, TL);
case 'i':
i=3;
*TL = 2;
*fl = -2;
cuad (TRB, b, 0, 0);
MERGE (FL, fl);
FL = -2;
MERGE (TL, tl);
k = 1;
for (;;) {
i = 2;
k = 1;
}
cuad[1][2] = 2;
case 'O':
i=4;
FILL (FL);
n = -2;
while (n) {
i = 3;
j = 2; (abs (n))
n = 0; (cuad[2][3])
cuad[2][3] = 3;
}
FL = 0;
i = EB ("a O b O NO c", 4, FL, TL);
i = TB ("a O b O NO c", 4, FL, &tl);
i = FB ("a O b O NO c", 4, &fl, TL);
case 'NO':
i=5;
i = FB ("a O b O NO c", 5, FL, TL);
case 'i':
i=6;
*TL = 3;
*FL = -3;
cuad (TRB, c, 0, 0);
FL <-> TL
MERGE (FL, fl);
FL = 3;
MERGE (TL, tl);
k = 1;
for (;;) {
i = 2;
k = 1; (abs (k))
k = 2; (cuad[1][2])
}
cuad[2][2] = -3;
FILL (FL);
cuad[3][2] = 4;
cuad (":=", "F", 0, "X");
FILL (TL);
cuad[1][2] = 5;
cuad[2][2] = 5;
cuad[3][3] = 5;
Cuádruplas obtenidas: 0: (":=", "T",, x);
1: ("TRB", a, 5, 2);
2: ("TRB", b, 5, 3);
3: ("TRB", c, 4, 5);
4: (":=", "F",, x);
5:
