Sei sulla pagina 1di 37

2011

PROGRAMACIN DE SISTEMAS

ITSJC 20/11/2011

NDICE
INTRODUCCIN...................................................................................................................................... 3 5.1 ANLISIS SEMNTICO ...................................................................................................................... 4 5.2 VERIFICACIN DE TIPOS EN EXPRESIONES ...................................................................................... 6 5.3 SISTEMAS DE TIPOS Y COMPROBADORES DE TIPOS ........................................................................ 7 5.4 ACCIONES AGREGADAS EN UN ANALIZADOR SINTCTICO DESCENDENTE (TOP- DOWN). ........... 16 5.5 PILA SEMNTICA EN UN ANALIZADOR SINTCTICO ASCENDENTE (BOTTOM-UP). GRAMTICA DE ATRIBUTOS ........................................................................................................................................... 24 5.6 ADMINISTRACIN TABLA DE SMBOLOS........................................................................................ 27 5.7 ERRORES SEMNTICOS .................................................................................................................. 30 CONCLUSIN........................................................................................................................................ 35 BIBLIOGRAFA....................................................................................................................................... 36

INTRODUCCIN

ANLISIS SEMNTICO
Un analizador sintctico (en ingls parser) es una de las partes de un compilador que transforma su entrada en un rbol de derivacin. El anlisis sintctico convierte el texto de entrada en otras estructuras (comnmente rboles), que son ms tiles para el posterior anlisis y capturan la jerarqua implcita de la entrada. Un analizador lxico crea tokens de una secuencia de caracteres de entrada y son estos tokens los que son procesados por el analizador sintctico para construir la estructura de datos, por ejemplo un rbol de anlisis o rboles de sintaxis abstracta. El anlisis sintctico tambin es un estado inicial del anlisis de frases de lenguaje natural. Es usado para generar diagramas de lenguajes que usan flexin gramatical, como los idiomas romances o el latn. Los lenguajes habitualmente reconocidos por los analizadores sintcticos son los lenguajes libres de contexto. Cabe notar que existe una justificacin formal que establece que los lenguajes libres de contexto son aquellos reconocibles por un autmata de pila, de modo que todo analizador sintctico que reconozca un lenguaje libre de contexto es equivalente en capacidad computacional a un autmata de pila. Los analizadores sintcticos fueron extensivamente estudiados durante los aos 70 del siglo XX, detectndose numerosos patrones de funcionamiento en ellos, cosa que permiti la creacin de programas generadores de analizadores sintticos a partir de una especificacin de la sintaxis del lenguaje en forma Backus-Naur por ejemplo, tales y como yacc, GNU bison y javaCC. Se compone de un conjunto de rutinas independientes, llamadas por los analizadores morfolgico y sintctico.

El anlisis semntico utiliza como entrada el rbol sintctico detectado por el anlisis sintctico para comprobar restricciones de tipo y otras limitaciones semnticas y preparar la generacin de cdigo.

En compiladores de un solo paso, las llamadas a las rutinas semnticas se realizan directamente desde el analizador sintctico y son dichas rutinas las que llaman al generador de cdigo. El instrumento ms utilizado para conseguirlo es la gramtica de atributos.

En compiladores de dos o ms pasos, el anlisis semntico se realiza independientemente de la generacin de cdigo, pasndose informacin a travs de un archivo intermedio, que normalmente contiene informacin sobre el rbol sintctico en forma linealizada (para facilitar su manejo y hacer posible su

almacenamiento en memoria auxiliar).

En cualquier caso, las rutinas semnticas suelen hacer uso de una pila (la pila semntic a) que contiene la informacin semntica asociada a los operandos (y a veces a los operadores) en forma de registros semnticos. El problema es que no tenemos garanta de que los dos procedimientos sean equivalentes. El segundo puede dar overflow, el primero prdida de precisin. La definicin del lenguaje debe especificar estos casos.

Las transformaciones posibles se pueden representar mediante un grafo cuyos nodos son los tipos de datos y cada arco indica una transformacin. Dado un operando de tipo A que se desea convertir al tipo B, se trata de encontrar una cadena de arcos que pase de A a B en el grafo anterior. Podra haber varios grafos, cada uno de los cuales se aplicar en diferentes condiciones, por ejemplo, uno para las asignaciones, otro para las expresiones, etc.

5.2 VERIFICACIN DE TIPOS EN EXPRESIONES

Para analizar los diferentes tipos que intervienen dentro de un programa, el compilador debe contar con una estructura interna que le permita manejar cmodamente las expresiones de tipos. Estructura interna: Debe ser fcilmente manipulable, pues su creacin se realizar conforme se hace la lectura del programa fuente Debe permitir comparar fcilmente las expresiones asignadas a distintos trozosde cdigo, especialmente a los identificadores de variables. La forma ms habitual de representacin son los grafos acclicos dirigidos (GADs) La ventaja de estas representaciones es que ocupan poca memoria y por tanto la comprobacin rapidez. de equivalencia se efecta con

Comprobacin de tipos Una caracterstica importante del sistema de tipos de un lenguajede programacin es el conjunto de reglas que permiten decidir cundo dos expresiones de tipo representan al mismo tipo. En muchos casos estas reglas no se definen como parte de las especificaciones del lenguaje.1. Diferentes interpretaciones de los creadores de compiladores. Estas diferencias afectan a la compatibilidad entre diferentes dialectos de un mismo lenguaje. Tres formas de equivalencia: Estructural Nominal

Funcional. Ejemplo: los tipos de A y de B son funcionalmente equivalentes:void Ordenar (int mat[], int

n){ /* ... */ }int A[10], B[20];Ordenar(A,10); Ordenar(B,20);Diferencia entre tipos compatibles y tipos funcionalmente equivalentes:En el primer caso, el compilador realiza sobre uno de ellos una transformacin interna paraque ambos se transformen en tipos equivalentes.En el segundo caso no se realiza ninguna modificacin interna, sino que se relaja el criterio de equivalencia.

5.3 SISTEMAS DE TIPOS Y COMPROBADORES DE TIPOS

Definicin

Una forma adecuada de representar los tipos dentro de un

compilador es usando un lenguaje de expresiones de tipo. Un lenguaje de las expresiones de tipo debe describir de manera clara y sencilla los tipos del lenguaje fuente. No confunda este lenguaje con el sub-lenguaje del lenguaje fuente que consiste en las declaraciones o definiciones. No tienen por que ser iguales. El compilador traduce las declaraciones de tipo en expresiones de tipo. El lenguaje de las expresiones de tipo es la representacin interna que el compilador tiene de estas declaraciones y depende del compilador. El lenguaje de las declaraciones no. * Un sistema de tipos de un lenguaje/compilador es el conjunto de reglas del lenguaje (que es traducido e interpretado por el compilador que permiten asignar expresiones de tipo a las instancias de uso de los objetos del programa.

Si bien el sistema de tipos es una propiedad del lenguaje, no es raro que los compiladores introduzcan modificaciones en el sistema de tipos del lenguaje. Por ejemplo en Pascal el tipo de un array incluye los ndices del array10.1). Esto y las reglas de equivalencia de tipos de Pascal limitan gravemente la generosidad de las funciones en Pascal. Por eso algunos compiladores Pascal permiten en una llamada a funcin la compatibilidad de tipos entre arrays de diferente tamao y diferentes conjuntos de ndices.

Desgraciadamente la forma en la que lo hacen puede diferir de compilador a compilador.

Definicin

Un comprobador de tipos verifica que el uso de los objetos en los

constructos de uso se atiene a lo especificado en sus declaraciones o definiciones de acuerdo a las reglas especificadas por el sistema de tipos.

Tipado Dinmico

Esttico

Tipado

Un lenguaje de programacin tiene tipado esttico si su comprobacin de tipos ocurre en tiempo de compilacin sin tener que comprobar equivalencias en tiempo de ejecucin.

Un lenguaje de programacin tiene tipado dinmico si el lenguaje realiza comprobaciones de tipo en tiempo de ejecucin. En un sistema de tipos dinmico los tipos suelen estr asociados con los valores no con las variables.

El tipado dinmico hace mas sencilla la escritura de metaprogramas: programas que reciben como datos otros cdigos y los manipulan para producir nuevos cdigos. Parse::Eyapp y Parse::Treeregexp son ejemplos de metaprogramacin. Cada vez que escribimos un procesador de patrones, templates o esqueletos de programacin estamos haciendo meta- programacin.

El lenguaje en el que se escribe el metaprograma se denomina metalenguaje. El lenguaje al que se traduce el metaprograma se denomina lenguaje objeto. La capacidad de un lenguaje de programacin para ser su propio metalenguaje se denomina reflexividad. Para que haya reflexin es conveniente que el cdigo sea un tipo de estructura de datos soportado por el lenguaje al mismo nivel que otros tipos bsicos y que sea posible traducir dinmicamente texto a cdigo.

Tipado Fuerte y Tipado Dbil

Definicin

Aunque el significado de los trminos Fuertemente Tipado y su

contrario Dbilmente Tipado varan con los autores, parece haber consenso en que los lenguajes con tipado fuerte suelen reunir alguna de estas caractersticas:

La comprobacin en tiempo de compilacin de las violaciones de las restricciones impuestas por el sistema de tipos. El compilador asegura que para cualesquiera operaciones los operandos tienen los tipos vlidos. Toda operacin sobre tipos invlidos es rechazada bien en tiempo de compilacin o de ejecucin. Algunos autores consideran que el trmino implica desactivar cualquier conversin de tipos implcita. Si el programador quiere una conversin deber explicitarla. La ausencia de modos de evadir al sistema de tipos.

Que el tipo de un objeto de datos no vare durante la vida del objeto. Por ejemplo, una instancia de una clase no puede ver su clase alterada durante la ejecucin.

Sobrecarga, Polimorfismo e Inferencia de Tipos

Un smbolo se dice sobrecargado si su significado vara dependiendo del contexto. En la mayora de los lenguajes Los operadores aritmticos suelen estar sobrecargados, dado que se sustancian en diferentes algoritmos segn sus operandos sean enteros, flotantes, etc.

En algunos lenguajes se permite la sobrecarga de funciones. as es posible tener dos funciones llamadas min:

u = min(x,y); /* Puede que correcto: x e y seran truncados a enteros. Tipo entero */

v = min(a,b); /* Correcto: Tipo devuelto es entero */

w = min(c,d); /* Correcto: Tipo devuelto es string */

t = min(x,c); /* Error */

Ejercicio Cmo afecta al anlisis de mbito la sobrecarga de operadores?

La inferencia de tipos hace referencia a aquellos algoritmos que deducen automticamente en tiempo de compilacin - sin informacin adicional del programador, o bien con anotaciones parciales del programador - el tipo asociado con un uso de un objeto del programa. Un buen nmero de lenguajes de programacin funcional permiten implantar inferencia de tipos (Haskell, OCaml, ML, etc). Vase como ejemplo de inferencia de tipos la siguiente sesin en OCaml:

pl@nereida:~/src/perl/attributegrammar/Language-AttributeGrammar0.08/examples$ ocaml

Objective Caml version 3.09.2

10

# let minimo = fun i j -> if i<j then i else j;;

val minimo : 'a -> 'a -> 'a = <fun>

# minimo 2 3;;

- : int = 2

# minimo 4.9 5.3;;

- : float = 4.9

# minimo "hola" "mundo";;

- : string = "hola"

El compilador OCaml infiere el tipo de las expresiones. As el tipo asociado con la funcin minimo es 'a -> 'a -> 'a que es una expresin de tipo que contiene variables de tipo. El operador -> es asociativo a derechas y asi la expresin debe ser leda como 'a -> ('a -> 'a). Bsicamente dice: es una funcin que toma un argumento de tipo 'a (donde 'a es una variable tipo que ser instanciada en el momento del uso de la funcin) y devuelve una funcin que toma elementos de tipo 'a y retorna elementos de tipo 'a.

11

Definicin

Aunque podra pensarse que una descripcin mas adecuada del

tipo de la funcin minimo fuera 'a x 'a -> 'a, lo cierto es que en algunos lenguajes funcionales es usual que todas las funciones sean consideradas como funciones de una sla variable. La funcin de dos variables 'a x 'a -> 'a puede verse como una funcin 'a -> ('a -> 'a). En efecto la funcin minimo cuando recibe un argumento retorna una funcin: # let min_mundo = minimo

"mundo";;

val min_mundo : string -> string = <fun>

# min_mundo "pedro";;

- : string = "mundo"

# min_mundo "antonio";;

- : string = "antonio"

# min_mundo 4;;

This expression has type int but is here used with type string

# min_mundo (string_of_int(4));;

- : string = "4"

Esta estrategia de reducir funciones de varias variables a funciones de una variable que retornan funciones de una variable se conoce con el nombre de

12

currying o aplicacin parcial.

El polimorfismo es una propiedad de ciertos lenguajes que permite una interfaz uniforme a diferentes tipos de datos.

Se conoce como funcin polimorfa a una funcin que puede ser aplicada o evaluada sobre diferentes tipos de datos.

Un tipo de datos se dice polimorfo si es un tipo de datos generalizado o no completamente especificado. Por ejemplo, una lista cuyos elementos son de cualquier tipo.

Se

llama

Polimorfismo

Ad-hoc

aquel

en

el

que

el

nmero

de

combinaciones que pueden usarse es finito y las combinaciones deben ser definidas antes de su uso. Se habla de polimorfismo paramtrico si es posible escribir el cdigo sin mencin especfica de los tipos, de manera que el cdigo puede ser usado con un nmero arbitrario de tipos. Por ejemplo, la herencia y la sobrecarga de funciones y mtodos son mecanismos que proveen polimorfismo ad-hoc. Los lenguajes funcionales, como OCaml suelen proveer polimorfismo paramtrico. En OOP el polimorfismo paramtrico suele denominarse programacin genrica

En el siguiente ejemplo en OCaml construimos una funcin similar al map de Perl. La funcin mymap ilustra el polimorfismo paramtrico: la funcin puede ser usada con un nmero arbitrario de tipos, no hemos tenido que hacer ningn tipo de declaracin explcita y sin embargo el uso incorrecto de los tipos es sealado como un error:

13

Equivalencia de Expresiones de Tipo

La introduccin de nombres para las expresiones de tipo introduce una ambigedad en la interpretacin de la equivalencia de tipos. Por ejemplo, dado el cdigo:

typedef int v10[10];

v10 a;

int b[10];

Se considera que a y b tienen tipos compatibles?

Se habla de equivalencia de tipos estructural cuando los nombres de tipo son sustituidos por sus definiciones y la equivalencia de las expresiones de tipo se traduce en la equivalencia de sus rboles sintcticos o DAGs. Si los nombres no son sustituidos se habla de equivalencia por nombres o de equivalencia de tipos nominal.

Si utilizamos la opcin de sustituir los nombres por sus definiciones y permitimos en la definicin de tipo el uso de nombres de tipo no declarados se pueden producir ciclos en el grafo de tipos.

14

El lenguaje C impide la presencia de ciclos en el grafo de tipos usando dos reglas:

1.

Todos los identificadores de tipo han de estar definidos antes de su uso,

con la excepcin de los punteros a registros no declarados

2.

Se usa equivalencia estructural para todos los tipos con la excepcin de las

struct para las cuales se usa equivalencia nominal

nereida:~/src/perl/testing>

gcc

-fsyntax-only

typeequiv.c typeequiv.c: En la funcin 'main': typeequiv.c:19: error: tipos incompatibles en la asignacin

En lenguajes dinmicos una forma habitual de equivalencia de tipos es el tipado pato:

Definicin

Se denomina duck typing o tipado pato a una forma de tipado

dinmico en la que el conjunto de mtodos y propiedades del objeto determinan la validez de su uso. Esto es: dos objetos pertenecen al mismo tipo-pato si implementan/soportan la misma interfaz independientemente de si tienen o no una relacin en la jerarqua de herencia.

15

5.4 ACCIONES AGREGADAS EN UN ANALIZADOR SINTCTICO DESCENDENTE (TOP- DOWN).


Generacin intermedias de representaciones

Existen

dos

representaciones

intermedias

principales:

Notacin sufija Cudruplas

Los operadores didicos (o binarios) pueden especificarse mediante tres notaciones principales:

Prefija: el operador didico es analizado antes que sus operandos. sus operandos. Sufija: el operador didico es analizado despus que sus operandos. Infija: el operador didico es analizado entre

En los lenguajes de programacin clsicos, los operadores didicos se representan usualmente en notacin infija. La notacin prefija permite al operador influir sobre la manera en que se procesan sus operandos, pero a cambio suele exigir mucha ms memoria. La sufija no permite esa influencia, pero es ptima en proceso de memoria y permite eliminar el procesado de los parntesis.

16

Los operadores mondicos slo pueden presentarse en notacin prefija o sufija.

Adems, un rbol sintctico puede representarse en forma de tuplas de n elementos, de la forma (operador, operando-1, ..., operando-k, nombre). Las tuplas pueden tener longitud variable o fija (con operandos nulos). Las ms tpicas son las cudruplas, aunque stas pueden representarse tambin en forma de tripletes.

Notacin sufija

Llamada tambin postfija o polaca inversa, se usa para representar expresiones sin necesidad de parntesis.

Ejemplos:

a*b a*(b+c/d)

ab*

abcd/+* a*b+c*d ab*cd*+

Los identificadores aparecen en el mismo orden. Los operadores en el de evaluacin (de izquierda a derecha).

Problema: operadores mondicos (unarios). O bien se transforman en didicos (binarios) o se cambia el smbolo.

17

Ejemplo: -a se convierte en 0-a o en @a a*(-b+c/d) ab@cd/+* Existen dos problemas principales:

Construir la notacin sufija a partir de la infija.

Analizar la notacin sufija en el segundo paso de la compilacin.

Rutina semntica para transformar de infijo a sufijo

Si el analizador sintctico es bottom-up, hacemos la siguiente suposicin: "Cuando aparece un no terminal V en el asidero, la cadena polaca correspondiente a la subcadena que se redujo a V ya ha sido generada".

Se utiliza una pila donde se genera la salida, inicialmente vaca. Las acciones semnticas asociadas a las reglas son:

E ::= E + T + E ::= E - T E ::= T T ::= T * F ::= T / F F F ::= i

Push Push -

Push * T Push / T ::=

Push i

F ::= (E)

F ::= - F

Push @

18

Anlisis de la notacin sufija

La gramtica completa que permite analizar la notacin sufija es:

<Operando> ::= id |

cte |

<Operando> <Operando> <Operador didico> |

<Operando> <Operador mondico>

<Operador didico> ::= + | - | * | / | ...

<Operador mondico> ::= @ | ...

Algoritmo de evaluacin de una expresin en notacin sufija que utiliza una pila:

Si el prximo smbolo es un identificador, se pasa a la pila. Corresponde a la aplicacin de la regla <Operando> ::= id

Si

el

prximo

smbolo

es

una

constante,

se

pasa

la

pila.

Corresponde a la aplicacin de la regla <Operando> ::= cte

19

Si el prximo smbolo es un operador didico, se aplica el operador a los dos operandos situados en lo alto de la pila y se sustituyen stos por el resultado de la operacin. Corresponde a la aplicacin de la regla <Operando> ::= <Operando> <Operando> <Operador didico>

Si el prximo smbolo es un operador mondico, se aplica el operador al operando situado en lo alto de la pila y se sustituye ste por el resultado de la operacin. Corresponde a la aplicacin de la regla <Operando> ::= <Operando> <Operador mondico>

Ejemplo: calcular ab@cd/+*.

Extensin de la notacin sufija a otros operadores

La asignacin, teniendo en cuenta que podemos no querer valor resultante. Adems, no interesa tener en la pila el valor del identificador izquierdo, sino su direccin. a:=b*c+d abc*d+: = La transferencia (GOTO).

20

GOTO L

L TR

La instruccin condicional

if p then inst1 else inst2 se convierte en p L1 TRZ inst1 L2 TR inst2

L1: L2:

Subndices:

a[exp1; exp2; ...; expn]

se convierte en

a exp1 exp2 ... expn SUBIN-n

Cudruplas

Tripletes

21

No se pone el resultado, se sustituye por referencias a tripletes. Por ejemplo: la expresin a*b+c*d equivale a:

(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 ejecucin. Ejemplo, sean las instrucciones:

a := b*c b := b*c Equivalen a los tripletes

(1) (*,b,c)

(2) (:=,(1),a) (3) (:=,(1),b) y el orden de ejecucin es (1),(2),(1),(3). Esta forma es til para preparar la optimizacin de cdigo. Si hay que alterar el orden de las operaciones o eliminar alguna, es ms fcil hacerlo ah. Generacin automtica de cudruplas

En un anlisis bottom-up, asociamos a cada smbolo no terminal una informacin semntica, y a cada regla de produccin una accin semntica. Ejemplo, sea la

22

gramtica

E ::= E + T E ::= E - T E ::= T T ::= T * F T ::= T / F T ::= F F ::= i

F ::= (E) F ::= -F

La regla F::=i asocia a F como informacin semntica el identificador concreto.

La regla F::=(E) asocia a F como informacin semntica la informacin semntica asociada a

E.

La regla U::=V asocia a U como informacin semntica la informacin semntica asociada a

V.

La

regla

U::=VoW

analiza la

compatibilidad

de los

operandos,

crea la

cudrupla

(o,Sem(V),Sem(W),Ti) y asocia a U la informacin semntica Ti.

23

La regla U::=oV crea la cudrupla (o,Sem(V),,Ti) y asocia a U la informacin semntica Ti. La informacin semntica se suele almacenar en otra pila paralela. Ejemplo: anlisis de a*(b+c)

5.5 PILA SEMNTICA EN UN ANALIZADOR SINTCTICO ASCENDENTE (BOTTOM-UP). GRAMTICA DE ATRIBUTOS


Es una extensin de la notacin de Backus que consiste en introducir en las reglas sintcticas ciertos smbolos adicionales no sintcticos (smbolos de accin) que, en definitiva, se reducen a llamadas implcitas o explcitas a rutinas semnticas.

Por ejemplo: sea la gramtica simplificada que analiza las instrucciones de asignacin:

<AsSt> ::= id #PId := <Exp> #RAs

<Exp> ::= <Exp> + <T> #RS | <T>

<T>

::= id #PId | Ct #PCt

Se observar que hemos hecho uso de cuatro smbolos de accin:

#PId: PUSH a la pila semntica el registro asociado al identificador.

#PCt: PUSH a la pila semntica el registro asociado a la constante.

24

#RS: Realizar suma: POP los dos registros superiores de la pila; comprobar que es posible sumarlos; realizar la suma (mediante una llamada al generador de cdigo) o generar representacin intermedia (si es una compilacin en dos o ms pasos); PUSH registro semntico del resultado en la pila semntica. #RAs: Realizar asignacin: POP los dos registros superiores de la pila; comprobar que es posible realizar la asignacin; realizarla (mediante una llamada al generador de cdigo) o generar representacin intermedia (si es una compilacin en dos o ms pasos).

En los analizadores sintcticos top-down basados en gramticas LL(1), la introduccin de los smbolos de accin en las rutinas correspondientes es trivial. En los analizadores bottom-up basados en gramticas SLR(1) es ms delicado, pues los estados del anlisis se mueven simultneamente sobre varias reglas. Slo en el momento de realizar una reduccin sabemos exactamente dnde estamos. Por ello, se suele introducir la restriccin de que los smbolos de accin deben estar situados nicamente al final de una regla. Cuando no se cumple esto (como en el ejemplo anterior) es trivial conseguirlo, introduciendo smbolos no terminales adicionales. Algunos generadores de analizadores sintcticos (como YACC) lo realizan automticamente. En nuestro ejemplo, quedara:

<AsSt> ::= <ASPI> := <Exp> #RAs

<ASPI> ::= id #PId

<Exp> ::= <Exp> + <T> #RS | <T>

<T>

::= id #PId | Ct #PCt

Poner un ejemplo del anlisis sintctico-semntico bottom-up de la instruccin

25

A := B + 1. Otro ejemplo: instrucciones condicionales con las reglas <Instr> ::= If <Expr> #S2 then <Instr> #S1 |

If <Expr> #S2 then <Instr> else #S3 <Instr> #S1

Ms adelante se ver cules son las tres acciones semnticas. 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

26

5.6 ADMINISTRACIN TABLA DE SMBOLOS


En informtica, una tabla de smbolos es una estructura de datos que usa el proceso de traduccin de un lenguaje de programacin, por un compilador o un intrprete, dnde cada smbolo en el cdigo fuente de un programa est asociado con informacin tal como la ubicacin, el tipo de datos y el mbito de cada variable, constante o procedimiento.

Una implementacin comn de una tabla de smbolos puede ser una tabla hash, la cual ser mantenida a lo largo de todas las fases del proceso de compilacin.

Puede tratarse como una estructura transitoria o voltil, que sea utilizada nicamente en el proceso de traduccin de un lenguaje de programacin, para luego ser descartada, o integrada en la salida del proceso de compilacin para una explotacin posterior, como puede ser por ejemplo, durante una sesin de depuracin, o como recurso para obtener un informe de diagnstico durante o despus la ejecucin de un programa.

Los smbolos en la tabla de smbolos pueden referirse a variables, a funciones o a tipos de datos en el cdigo fuente de un programa.

La tabla de smbolos forma parte de cada fichero que contiene el cdigo objeto durante el enlazado o linking de los diferentes ficheros; recae en la responsabilidad del linker o enlazador resolver cualquier referencia no resuelta.

27

Tabla de smbolos en lenguaje C

Como ya se dijo en el esbozo la tabla de smbolos es una estructura de datos que se crea en tiempo de traduccin del programa fuente. Es como un diccionario variable, debe darle apoyo a la insercin, bsqueda y cancelacin de nombres (identificadores) con sus atributos asociados, representando las vinculaciones con las declaraciones. Debe aclararse que no necesariamente deber estar representada en una tabla como su nombre indica ya que tambin se emplean rboles, pilas , etc.

Los smbolos se guardan en la tabla con su nombre y una serie de atributos opcionales que dependern del lenguaje y de los objetivos del procesador, este conjunto de atributos almacenados se denominan registro de la tabla de smbolos.

La siguiente representa una serie de atributos que no es necesaria para todos los compiladores, sin embargo cada uno de ellos se puede utilizar en la implementacin de un compilador particular.

nombre del identificador.

direccin en tiempo de ejecucin a partir del cual se almacenara el identificador si es una variable. tipo del identificador. Si es una funcin el tipo que devuelve la funcin.

numero de dimensiones del array(arreglo), o numero de miembros de una estructura o clase, o nmeros de parmetros si se trata de una funcin. tamao mximo o rango de cada una de las dimensiones de los array, si tiene dimensin esttica. etc..

28

Operaciones con la Tabla se smbolos (TS a partir de ahora).

En general en la TS se realizan dos operaciones: la insercin y la bsqueda. En C la operacin de insercin se realiza cuando se procesa una declaracin. Hay dos posibilidades: que la TS este ordenada (o sea, nombres de variables por orden alfabtico) o que no este ordenada.

Si esta ordenada, entonces la operacin de insercin llama a un procedimiento de bsqueda para encontrar el lugar donde colocar los atributos del identificador a insertar, por lo que en este caso la insercin lleva tanto tiempo como la bsqueda. En cambio, si no est ordenada la TS, la insercin se simplifica mucho

aunque se complica la bsqueda, pues debe examinar toda la tabla.

En la bsqueda, se detectan los identificadores que no hayan sido declarados previamente, emitiendo un mensaje de error.

ejemplo en lenguaje C: Undefined simbolo 'x', si es una variable que desea usarse pero no se declaro.

En la insercin, se detectan identififcadores que ya han sido declarados previamente, emitiendo un mensaje de error

ejemplo en C: mltiple declaration for 'x' si x ya estaba en TS.

29

5.7 ERRORES SEMNTICOS

En cierto modo, este tipo de error es el ms difcil de depurar, ya que ni el compilador ni el sistema proporcionan informacin sobre qu est fallando. Lo nico cierto es que el programa no se est comportando como debera.

El primer paso es intentar encontrar una correspondencia entre el cdigo del programa y el comportamiento que se observa. Necesitas formar una hiptesis acerca de qu es lo que el programa est haciendo. Uno de los inconvenientes que hacen esta tarea difcil es que los ordenadores funcionan muy rpido.

Muchas veces sera deseable que se pudiese ralentizar el programa hasta una velocidad humana, y con algunos depuradores es posible. Pero el tiempo que se emplea en intercalar algunas instrucciones print en el cdigo es bastante menor que el que se tarda en configurar el depurador, aadir y eliminar puntos de interrupcin y avanzar por el programa hasta el lugar en el que se produce el error.

Pregntate lo siguiente:

Hay algo que el programa debera hacer pero que, por contra, no parece estar haciendo? Encuentra la porcin de cdigo que realiza esa funcin y asegrate de que se ejecuta en el momento que debera. Est ocurriendo algo inesperado? Encuentra la porcin de cdigo que realiza esa funcin y comprueba si se est ejecutando en un momento inadecuado. Una seccin del cdigo produce efectos inesperados? Asegrate de que comprendes el cdigo en cuestin, especialmente si implica llamadas a funciones o mtodos en otros mdulos de Python. Lee la documentacin sobre las funciones que utiliza. Intenta probarlas examinando los resultados producidos por los casos ms simples posibles.

30

Para programar necesitas un modelo mental de cmo funcionan los programas. Cuando un programa no se comporta como debera, es muy frecuente que esto se deba ms al modelo mental que al programa en s mismo.

La mejor manera de corregir tu modelo mental es dividir el programa en sus componentes - usualmente las funciones y los mtodos- y comprobarlos por separado. Una vez que encuentres la discrepancia entre el modelo mental y la realidad, podrs resolver el problema.

Por supuesto, debes crear y comprobar los componentes a medida que desarrollas el programa. Si encuentras un problema, tan slo debera haber una pequea parte de cdigo nuevo cuyo funcionamiento no ha sido comprobado

Siempre y cuando sean legibles, no hay ningn problema por escribir expresiones largas, pero pueden ser difciles de depurar. Una buena opcin es dividir estas expresiones complejas en una serie de asignaciones temporales de variables.

La versin explcita es ms sencilla de leer porque los nombres de variable aaden informacin adicional, y es ms sencillo de depurar porque se puede determinar el tipo de las variables intermedias y mostrar sus valores.

Otro problema con las expresiones largas es que el orden en el que se evalan puede diferir del esperado. Por ejemplo, para traducir a Python la expresin

podras escribir:

y = x / 2 * math.pi;

31

Esto no es correcto, ya que la multiplicacin y la divisin tienen la misma prioridad en una expresin, y estas se evalan de izquierda a derecha. As, esta expresin es x pi / 2.

Una buena forma de depurar las expresiones es aadir parntesis para explicitar el orden de evaluacin:

y = x / (2 * math.pi);

Cuando no ests seguro del orden de evaluacin, usa parntesis. Esto no slo conseguir que el orden de evaluacin sea el deseado, sino que adems facilitar la lectura del programa a las personas que no conocen las reglas de precedencia. Si tienes una instruccin return con una expresin compleja, no podrs imprimir el valor que devuelve antes de salir de la funcin o mtodo. De nuevo, utiliza una variable temporal. Por ejemplo, en lugar de:

return self.manos[i].eliminarCoincidencias()

podras escribir: cuenta self.manos[i].eliminarCoincidencias() =

return cuenta

32

As puedes mostrar el valor de cuenta antes de volver de la funcin o mtodo.

Lo primero que debes hacer es alejarte del ordenador unos minutos. Los ordenadores emiten ondas que afectan al cerebro, causando:

Frustracin o ira.

Creencias supersticiosas (el ordenador me odia) o mgicas (el programa solo funciona cuando llevo la gorra al revs). Programacin factorial (intentar escribir todos los programas posibles hasta encontrar el que hace lo que se quiere).

Si sufres cualquiera de estos sntomas, levntate y da un paseo. Cuando ests tranquilo, piensa en el programa. Qu est haciendo? Cules son las posibles causas de este comportamiento? Cundo fue la ltima vez que funcionaba, y qu hiciste despus?

A veces, encontrar un error no es ms que cuestin de tiempo. A menudo, los errores se encuentran alejndose del ordenador y dejando la mente divagar. Algunos de los mejores lugares para encontrar errores son trenes, duchas y la cama, justo antes de dormir.

A veces ocurre. Hasta los mejores programadores se quedan atascados de vez en cuando. El trabajar mucho en un programa puede impedir encontrar sus errores. Cuatro ojos ven ms que dos: busca ayuda.

33

Antes de involucrar a otra persona, asegrate de que has agotado todas las tcnicas descritas aqu. El programa debe ser tan simple como sea posible, y deberas haber encontrado el caso mnimo que provoca el error. Deberas tener instrucciones print en los lugares adecuados (y sus mensajes deberan ser comprensibles). Has de comprender el problema lo

suficientemente bien como para describirlo de manera concisa.

Si alguien te va a ayudar, dale toda la informacin que necesita:

Hay algn mensaje de error? Qu significa y a qu parte del programa se refiere? Qu fue lo ltimo que se hizo antes de que ocurriese el error? Cules son las ltimas lneas de cdigo que se escribieron? En qu nuevo caso de prueba falla?

Qu es lo que has intentado hasta ahora y qu has conseguido averiguar?

Cuando encuentres un error, piensa qu es lo que podras haber hecho para encontrarlo ms rpido. La prxima vez que veas algo parecido, sers capaz de encontrar el error rpidamente.

34

CONCLUSIN

35

BIBLIOGRAFA

36

Potrebbero piacerti anche