Está en la página 1de 72

Analizador Lxico

ANALIZADOR LXICO
NDICE:
- INTRODUCCIN......................................................................................................2
- AUTMATAS FINITOS.............................................................................................3
- AUTMATAS FINITOS DETERMINISTAS (AFD)..................................................4
- AUTMATA FINITO NO DETERMINISTA (AFN....................................................5
- RELACIN ENTRE GRAMTICAS Y AUTMATAS............................................8
- EJERCICIOS DE CONSTRUCCIN DE AUTMATAS........................................10
- MINIMIZACIN DEL NMERO DE ESTADOS EN UN AFD..............................15
- CONSTRUCCIN DE UN AUTMATA FINITO
A PARTIR DE UNA EXPRESIN REGULAR.......................................................22
- IMPLEMENTACIN DE MQUINAS DE ESTADO FINITAS.............................31
- IDENTIFICACIN DE PALABRAS........................................................................36
- IDENTIFICACIN DE PREFIJOS..........................................................................37
- ALGUNOS EJEMPLOS DE ANALIZADORES LXICOS.....................................40
- LEX...........................................................................................................................58
- REFERENCIAS........................................................................................................63

Analizador Lxico

ANALIZADOR LXICO
El explorador, analizador lxico o "Scanner" es la parte del compilador que lee los
caracteres del programa fuente original y que construye unos smbolos intermedios (que
llamaremos "tokens"), por ejemplo las variables, los enteros, palabras reservadas y delimitadores.

caracteres

A.LXICO

smboloterminal

A.SINTCTICO

Podemos incorporar el anlisis lexicogrfico al anlisis sintctico. Las razones por las que
se separa del anlisis sintctico, en la prctica son:
Una gran parte del tiempo de compilacin se consume explorando caracteres. La
separacin nos permite concentrarnos ms para reducir este tiempo; por ejemplo una manera es
programando parte o todo el explorador en lenguaje ensamblador y esto es ms fcil si estn
separados. (En el caso del IBM 360, uno puede ejecutar una sola instruccin TRT que examinar
de 1 a 256 caracteres buscando cualquier carcter no blanco).
La sintaxis de los smbolos se puede describir con gramticas muy simples (regular o del
tipo 3). Si separamos la exploracin del reconocimiento sintctico, podemos desarrollar tcnicas
eficientes de reconocimiento que estn especialmente ajustadas a estas gramticas. Adems,
empleando estas tcnicas podemos desarrollar mtodos automticos para la construccin de
exploradores.
Como el explorador entrega un smbolo en vez de un carcter, el analizador sintctico
obtiene as mayor informacin sobre lo que tendr que hacer en cada caso. Adems, algunas de
las comprobaciones necesarias para reconocer smbolos son ms fciles de hacer de una manera
directa que con un analizador formal sintctico. Por ejemplo, es ms fcil reconocer lo que
significa la sentencia FORTRAN: DO10I = 1,10... viendo si viene primero una "," o un "("
despus del smbolo igual.
El desarrollo de lenguajes de alto nivel requiere cuidar las propiedades sintcticas y
lexicogrficas. La separacin de los dos, permite que las investiguemos independientemente.

Analizador Lxico

Se pueden tener varias representaciones externas del mismo programa fuente (ficha,
diskette, cinta de papel, etc.) o con distintos cdigos (EBCDIC, ASCII,...) o con formatos
distintos (caracteres de escape o tabuladores, minsculas,...). Entonces, en vez de tener
compiladores diferentes para cada caso, bastara tener exploradores diferentes, pero el resto del
compilador sera el mismo.
Generalmente el analizador lxico ser una subrutina llamada por el analizador sintctico
cuando necesite un nuevo smbolo; en vez de un programa separado que realice un anlisis
lexicogrfico completo del programa fuente y entregue al analizador sintctico una tabla
conteniendo el programa fuente en un formato interno de smbolos, con un gasto de memoria
enorme.
Paraobtener
unsmbolo

Programafuenteen

ANALIZADOR
SINTCTICO

EXPLORADOR
formadecaracteres
AUTMATAS FINITOS

Smbolo

AUTMATAS FINITOS
Los representamos por diagramas de transiciones; se produce una transicin (cambio de
estado) de acuerdo con una entrada.
- Determinista:
Con un smbolo determinado solo
podemos ir a un nico estado.
Existen dos tipos:
- No determinista:
Con un smbolo determinado podemos
ir a un conjunto de estados.
Para todo autmata no determinista existe uno determinista.

Analizador Lxico

AUTMATAS FINITOS DETERMINISTAS (AFD)


Se compone de la 5-tupla: ( K, VT, M, S, Z ):
- K: Conjunto de estados, es un alfabeto de elementos (smbolos) no terminales VN.
- VT: Conjunto de smbolos que el autmata acepta como lectura en la secuencia de
entrada, llamado "alfabeto de entrada".
- M: Matriz de transiciones; funcin que pasa de un K y VT a otro K.
M (e,t) = e' e,e' pertenecen a K, t pertenece a VT; e = estado
- S: Estado inicial (debe estar en K).
- Z: Conjunto de estados finales, debiendo estar todos en K.
Ejemplo:

VT
0
1
AFD=({A,B,C,},{0,1},M,A,C)
inicial

B
(S) A

B
C
B
VN
final
C
C
B
(Z)

estadodefallo.(Error).
Representacin en diagrama de estados:

Analizador Lxico

El lenguaje que acepta este autmata: Cualquier secuencia de ceros y unos que
comience por 1 y acabe en 0.
Representacin en el ordenador:

Tabla de transiciones:

Carcterdeentrada
Estado
actual

Estadoal
quesevaair

AUTMATA FINITO NO DETERMINISTA (AFN)


Se compone de la 5-tupla: ( K', VT', M', S', Z' )
- K':Conjunto de estados.
- VT':Conjunto de smbolos que el autmata acepta como secuencia de entrada.
- M':Matriz de transiciones; es la funcin de K' y VT' dando "subconjuntos" de K':
M'( e, t ) = { e1',...,en' }
- S':Conjunto de estados iniciales. S' est incluido en K'.
- Z':Conjunto de estados finales. Z' est incluido en K'.
* Todo AFN tiene su AFD: lo que querr decir que el lenguaje que aceptan ambos
autmatas finitos ser el mismo; para ello, suponemos que el conjunto de estados del AFN ser
un nico estado en el AFD que lo represente:
{e1,...,en}

[{e1,...,en}]

Analizador Lxico

* El conjunto de estados del AFD es el conjunto de las combinaciones de estados que


pueden hallarse en el AFN:
- Estado inicial [ S1,...,Sp ]
- Estados finales [ e1,...,eq ] ei pertenecen a Z'.
- Matriz de transiciones:
Conjunto de estados en AFN:
{ e1 ,..., en } t M N ( e1 ,t) M N ( e2 ,t) ... M N ( en ,t)

Un estado en AFD:
[ e1 ,..., en ] t [e1 ,...,em ]

MD([e1,...,en],t) = [e1',...,em']
Veamos un ejemplo:
AFN =( {A,B,C}, {a,b,c}, M, {A,B}, {C} )

abc

>A{B,C}

>B{B,C}

C{C}

Analizador Lxico

AFD

[A,B] > AB

K = { AB, BC, C }
S = { AB }
Z = { BC, C }
a

{ A, B }

{ A, B }

{ A, B }

{ B, C }
{ B, C }
{ C }

{ B, C }

{ B, C }
{ C }

{ C }

{ B, C }
{ B, C }

{ C }

{ C }

El estado BC es final puesto que C es final.


abc

>ABBCBC

BCBCC

CC

Si un estado es inicial y final a la vez implica que (vaco) pertenece al Lenguaje.

Analizador Lxico

RELACIN ENTRE GRAMTICAS Y AUTMATAS:


El lenguaje es igual para ambos:
0 1 1 0
Z

U 0 V 1

Z 1 1

Z 0 0

Gramticas regulares:
N

Ma

Z > U 0 > Z 1 0 > V 1 1 0 > 0 1 1 0

Autmata completo:

0 1 1 0 > V Z U Z

Analizador Lxico

- Es muy fcil a partir del autmata crear una gramtica regular: Las reglas son
representadas por transiciones. Los estados son smbolos no terminales, el estado final es el
smbolo principal. No se toma como smbolo el estado inicial.
En caso de dos o ms estados finales: se crea un nico (nuevo) estado final al que
llegarn todas las transiciones que llegaban a cada uno de los estados finales anteriores y estos
dejarn de ser estados finales (permanecen igual). El autmata se convierte ahora en no
determinista.
Ejemplo:

EJEMPLO:

Analizador Lxico

10

Analizador Lxico

DCa1010abbaL
CCbD>Lasecuencia
desmbolos
CBanoterminales
esla
BA0Casecuencia
deestados
AB1queatraviesa
elautmata.
A1Cb

Cb

Ba

A0

B1

A0

1
Ejercicios de construccin de autmatas donde V T = { 0, 1 } :
1.- Construir un autmata que acepte una secuencia de {0,1} en la
que cada vez que aparezcan dos unos les siga un cero.

11

Analizador Lxico

2.- Todo tercer smbolo es un 1: x x 1 x x 1 x ...


L= {xy1}

3.- Cualquier secuencia que tenga al menos un 1.

4.- Un nmero par de 1s y un nmero impar de 0s.


n1n0estado

parparA

parimparB

imparparC

imparimparD
Sifueraunnimparde1sy
parde0selestadofinalseraC.
5.- Hay un nmero par de 0s entre dos 1s. VT = { 0, 1 }
... 1 0 0 ... 0 1 ...
par

12

Analizador Lxico

6.- L = VT

{01}

L = VT

7.- Toda secuencia de la forma 1 0

{ 0, 1 }*

1{10}0

8.- Secuencia con tres unos:

NOTA:
Sinoexisteningnestadofinal,elautmatanoacepta
ningunasecuencia.

9.- Todas las secuencias en las que todo 1 va precedido y seguido


de un 0:

13

Analizador Lxico

Ejercicios de dado un autmata, ver qu lenguaje acepta.

1.01

>ABA

BBC

CCC

{1}0{0}1{01}

2.01

>ABC

BCB

CCC

0{1}

3.
01

>ABC

BDB

CCD

DDD

14

Analizador Lxico

0{1}1{0}

4.
1*c

>ABFF

BFCF

CCDC

DECC

EFFF

FFFF
Festadodefallo

1*{1c}*{(xc){1c}*}1

15

Analizador Lxico

MINIMIZACIN DEL NMERO DE ESTADOS DE UN AFD

0{1}0

1{1}0

El criterio para minimizar consiste en encontrar estados


que tengan transiciones equivalentes; estos estados los
reduciremos a uno solo.
LR > GR
AFN > AFD > AFD-mnimo.
Ejemplos:

16

Analizador Lxico

Procedimiento Sistemtico:
a) Consideremos el conjunto de estados del autmata AFD, incluyendo el estado de fallo:
E = { e1, e2, ..., en, }
b) Separamos por un lado los estados finales y por otro los dems; particin de E en dos
subconjuntos:
Estados finales: { ek,..., en } Estados no finales: { e1,...,
ej }.
c) Entramos en un bucle donde iremos haciendo sucesivas particiones hasta que stas se
nos queden como estados del autmata minimizado. Las particiones se realizan en base a que no
sean equivalentes cada una de las transiciones incluidas en la particin:
Repeat
Para todo Si y para todo tk VT
SI todos los ej Si realizan la misma transicin ENTONCES
nada.
SINO
equivalentes.

Si

se

subdivide

en

17

subconjuntos

de

transiciones

Analizador Lxico

Until no se produzca una nueva subdivisin.

18

Analizador Lxico

d) Construccin del AFD minimizado.


Hay que tener en cuenta el estado de fallo, ya que este
procedimiento requiere que las transiciones sean exhaustivas.
Ejemplo:

Primeraparticin:

{A,B,C,}{D,E}
Conel"0":

{A,B,C,}{D,E}

19

Analizador Lxico

Segundaparticin:

{A,}{B,C}{D,E}
Conel"1":

{A,}{B,C}{D,E}

Terceraparticin:

{A}{}{B,C}{D,E}

BD
AFDmnimo:

20

Analizador Lxico

Otroejemplo:

01

>113

274

365

414

514

676

773

Elestado2noesalcanzablenuncaluegoesposibleeliminarlo.

Primeraparticin:

Estadosnofinales

Estadosfinales

{1,3,5,7}{4,6}

Transicionescon"0"

Segundaparticin:

{1,5,7}{3}{4,6}

21

Analizador Lxico

Transicionescon"1"

22

Analizador Lxico

Terceraparticin:

{1,7}{3}{5}{4,6}

Transicionescon"0"
{1,7}{3}{5}{4,6}
Transicionescon"1"

AFDmnimo:
01

{1,7}>113

{4,6}212

{3}324

{5}412

EjerciciosdeminimizacindeAFD
1.
xy

>141

251

345

426

517

23

Analizador Lxico

614

725

24

Analizador Lxico

EstadosnofinalesEstadosfinales

{3,4,5}{1,2,6,7}

Transicionesconx

{3}{4,5}{1,2}{6,7}

Transicionescony

{3}{4,5}{1,2}{6,7}

Transicionesconx

AFDmnimo:
xy

{1,2}>141

{3}344

{4,5}416

{6,7}614
Elestado3lopodemoseliminarporquenoesalcanzable.
xy

>141

416

25

Analizador Lxico

614

26

Analizador Lxico

CONSTRUCCIN DE UN AUTMATA FINITO A PARTIR DE UNA EXPRESIN


REGULAR:

EXPRESIN REGULAR

AFN

AFD

Las expresiones regulares se utilizan para expresar el lenguaje que ha de reconocer el


analizador lxico. Veamos como a partir de una expresin regular podemos construir un autmata
finito.
Los smbolos a aceptar son: ( ) { } [ ] concatenacin.
Creamos un AFD para una expresin regular e en cuatro pasos:
1.- Construir un sistema de transicin para e.
2.- Construir un diagrama de estados para el sistema de transicin.
3.- Construir un AFN a partir del diagrama de estados.
4.- Construir un AFD del AFN.
Los pasos 3 y 4 los hemos visto, veamos pues los pasos 1 y 2.
Def: Un "sistema de transicin" es un diagrama de estados con un nico estado inicial S y un
nico estado final Z. S slo tiene arcos que salen de l, mientras que Z slo tiene arcos que llegan
a l. Adems, un arco puede llamarse con el smbolo nulo . (ver figura *).
La idea del funcionamiento de un sistema de transicin es la misma que la del diagrama de
estados; con la diferencia de los arcos : Si el estado actual es A y un arco lleva al estado B;
entonces consideramos como estados actuales el A o el B; o sea que el siguiente estado puede
suceder al A o al B.

figura *:

Diagrama de estados
equivalente

Sistema

27

de

transicin

Analizador Lxico

TH.- Existe un sistema de transicin para cualquier diagrama de estados.


Construccin: Sea S un diagrama de estados, con estados iniciales S1, S2,..., Sn y estados
finales Z1, Z2,..., Zm. Aadimos un estado nuevo S, que ser el nuevo estado inicial (nico) con
arcos de nombre que van de l a los estados S1,..., Sn. Aadimos tambin un nuevo estado Z,
que ser el estado final nico, con arcos que llegan a l desde los estados Z1,..., Zm.
TH.- Para cada expresin regular e, existe un sistema de transicin que acepta e.
Veamos como se construye el sistema de transicin para las siguientes expresiones
regulares:
e=
e=a
a VT

e = e 1 e2 = a b
a

/\

b VT

Concatenacin

28

Analizador Lxico

e = e1 e2

Nos interesa evitar las transiciones , siempre que sea posible.


e = [ e1 ]

e = { e1 }

No siempre son equivalentes.


Esta es la que est bien

Ejemplo:

e=(ab){ab}

Si llamamos e1 = ( a b ) y e2 = { a b } entonces e = e1 e2
Si e3 = a b entonces e1 = ( e3 ) y e2 = { e3 }

29

Analizador Lxico

El sistema de transicin nos quedar:

Ejercicios de sistemas de transicin a partir de expresiones regulares


1.- e = { ( a [ b ] { c } ) ( d { f } ) }
e = { e1 }
e 1 = e2 e 3
e 2 = e4 e5

e4 = a

e 5 = e6 e 7
e6 = [ e8 ]

e8 = b

e 7 = { e9 }

e9 = c

e3 = e10 e11
e11 = { e12 }

e10 = d
e12 = f

30

Analizador Lxico

2.- N Real en FORTRAN: [ + - ] d { d } . { d } [ E [ + - ] d { d } ]

31

Analizador Lxico

Vamos a pasar a un AFD:

a)Eliminartrans.
Tenemosdos
posibilidades
b)Trans.
AFD.

AFN

AFD.

a) Reglas de eliminacin de las transiciones :


El ltimo paso es el construir un diagrama de estados para un sistema de transicin.
Debemos suprimir los arcos llamados . Esto lo realizamos en un cierto orden, tal que el estado
del que vengo (B) no parten ramas .
(*)

-Si B no es estado inicial o no le llega ninguna transicin de otro estado, lo podemos eliminar
porque no ser accesible.
-Si B es final, hacemos final a A.
-Si A es inicial, hacemos inicial a B.

32

Analizador Lxico

Si no tengo la situacin (*), entonces tendr (**):


(**)

- El nuevo estado rene las propiedades de todos los estados, si alguno era inicial, el
nuevo estado ser inicial y si alguno era final, el nuevo estado ser final.
Veamos un ejemplo: ( a b ) { a b }

33

Analizador Lxico

b) Basndonos en el diagrama de transiciones se puede pasar al AFD.


Utilizando el mismo mtodo de AFN

AFD.

Vemoslo con el ejemplo:

Estados iniciales: { A, B, C } = A' (puedo llegar con una transicin )


Desde A' con una sola "a": { D, F, G, H, I, L } = B' (ser final por contener a L)
Desde A' con una sola "b": { E, F, G, H, I, L } = C' (ser final)
Desde B' con una sola "a": { J, L, G, H, I } = D' (ser final)
Desde B' con una sola "b": { K, L, G, H, I } = E' (final)
Desde C' con una sola "a": { J, L, G, H, I } = D'
Desde C' con una sola "b": { K, L, G, H, I } = E'
Desde D' con una sola "a": { J, L, G, H, I } = D'
Desde D' con una sola "b": { K, L, G, H, I } = E'
Desde E' con una sola "a": { J, L, G, H, I } = D'
Desde E' con una sola "b": { K, L, G, H, I } = E'

34

Analizador Lxico

AFDmnimo:

{A'}{B',C',D',E'}

con"a":

{A'}{B',C',D',E'}

con"b":

RESUMEN

ExpresinRegular

Diagramadetransicin

35

Analizador Lxico

AFN
AFD
AFDmnimo.

IMPLEMENTACIN DE MQUINAS DE ESTADO FINITAS:

- Mtodos explcitos: En el programa que implementa la


mquina existe una variable que
representa el estado del autmata..
Existen dos tipos:
- Mtodos implcitos: El estado est implcito en la
posicin del programa.

- Mtodos explcitos: Tenemos una matriz de transiciones del autmata:


Var-est. := matriz-transic. [var.est., smbolo]
smbolos

rutinassemnticas

estadose'

A veces, la matriz est vaca debido a transiciones con estado de fallo, y no es


recomendable usar una matriz, ya que sta se hace muy grande.
- Un mtodo alternativo es utilizar una tabla de transiciones, en la cual hacemos una
bsqueda de la siguiente forma:
smbolonuevoestado

S1e1'
S2e2'
ndice..
..

36

Analizador Lxico

..
nil

37

Analizador Lxico

donde cada una de las filas de la matriz la convertimos en una tabla; con el smbolo buscaramos
en la tabla.
En realidad sera una serie de tablas, cada una para un estado:

estado

tabladetransiciones

- Otra posibilidad es con listas de transiciones para cada smbolo:

estadoactual

nuevoestado
abc...

Anivelprogramticosepuedehacer:
caseestadoof

a:estado:=m

38

Analizador Lxico

- Mtodos implcitos:
- Un mtodo implcito puede ser aquel en el que hay un trozo de programa asociado a
cada estado; as mismo en cada trozo de programa hay una sentencia "case" para cada smbolo al
que puede llegar. Para cada valor de la variable smbolo se realizarn ciertas acciones (las que
vimos que estaban asociadas a cada transicin), y luego un salto a otro estado. (la transicin en
s):

casesimbol.of

a:

goto
estadon.
b:

goto
.
.
.
casesimb.of

a:

estadom.
goto
.
.
.
Ejemplo:

>

39

Analizador Lxico

40

Analizador Lxico

A:caseSof

a,b:

gotoB
c:A

gotoC
x:

gotoA

B:

B
RETURN

C:caseSof

a:

C
gotoB

otherwase:ERROR.

- Otro mtodo es mediante la utilizacin del vector de transiciones o vector de saltos;


donde el ndice es el smbolo y el contenido una direccin:

dir1

dir2

.
smbolo.
.

dirn

Muchas direcciones (al ser de transiciones fallo) se repetirn, en ese caso sera interesante
tener una tabla de saltos, as los contenidos seran dobles:

41

Analizador Lxico

gotodir
smbolo1dir1
adir
smbolo2dir2d
ddir
ndice..<>
..*dir
..
..
smbolondirn..
..
Cuando nos encontremos el smbolo en la tabla, hacemos un goto dir n; este mtodo es ms
lento debido a la bsqueda, pero no existen repeticiones.
- Otra forma de implementarlo es a base de IF:
En el ejemplo: A:

if (S=a) or (S=b) then ...


else if (S=c) then ...
else if (S=x) then ... goto A
else ERROR

- El mtodo implcito ms corriente es el denominado "mtodo programtico" y lo


implementaremos mediante instrucciones: "while", "if", "repeat", etc; interpretamos el autmata
como un diagrama de flujo. Generalmente, lo que se hace es coger la expresin regular
directamente y escribir el programa, no hace falta construir el autmata. As las construcciones de
expresiones regulares en forma de programas son:
*abc

case S of
a:

b:

c:

42

Analizador Lxico

* x ... x ...

reescribimos x (......)

una sola barra


... ...
* [x ...]

if ... then
else ...

if S=x then ...

Tenemos que comprobar que el primer smbolo no coincide con el primer smbolo
despus del corchete ([x...] x).
* La concatenacin supone una secuencia de instrucciones.
* {x ...}
* (x ...)+

while S=x do ...


repeat ... until S<>x

IDENTIFICACIN DE PALABRAS:
En todo compilador, existen palabras claves (BEGIN ELSE END ...) y no vale la
pena construir un autmata para ellas.

Generalmente se utilizan los siguientes mtodos:


- Mtodo del ndice: Se utiliza un ndice para cada palabra y lo calculamos en funcin de la
palabra. Sirve para lenguajes con pocos smbolos identificadores.

43

Analizador Lxico

- Lista lineal: Las palabras se colocan por orden alfabtico y se hace una bsqueda dicotmica.
Para ahorrar tiempo de bsqueda subdividimos la lista en listas de tamaos de palabra.
- Hash: Se calcula un ndice en funcin de la palabra, que nos da una entrada en un vector donde
cada contenido apunta a una lista encadenada para resolver las colisiones.
i=f(palabra)

IDENTIFICACIN DE PREFIJOS:
A veces, en el texto fuente las palabras no estn delimitadas, es decir, no existe
delimitador que nos indique el final de la secuencia. Como solucin, podemos construir un AFD
que cuando alcance el ltimo carcter entonces llegue a un estado final, pero para ello no deben
existir palabras con un mismo prefijo.
As, son vlidos los mtodos de implementacin de AFD, pero no tiene sentido aplicar
mtodos basados en ndices, y una lista lineal sera muy costosa. Por lo tanto, usamos un mtodo
con diferentes listas cada una con un nmero diferente de caracteres; iremos partiendo y
buscando en las listas hasta encontrar la palabra existente.
Ejemplo:1caract.2caract.3caract....

.
FORK=...FOR
....
.
.

44

Analizador Lxico

TABLA DE TRANSICIONES
Posee la siguiente forma:

estado:smbolodir=e'

..
..
..

xfallo

Consideremos, por ejemplo, el autmata capaz de reconocer el lenguaje L = { ACE,


BAD, BADE, BED }. Supongamos que tenemos una lista asociada con cada estado en la que se
obtengan las transiciones:

smboloterminal(finaldesecuencia).
.
.
1A2.
B36D9
ERRORERROR
2C47ACE
ERRORERROR
3A58E10
E6BAD
ERRORERROR
4E79BED
ERRORERROR
5D810BADE
ERRORERROR

45

Analizador Lxico

.
.
Sin embargo, si ahora aadimos la secuencia ADD, tendramos que tener una transicin
desde el estado 2 a un nuevo estado con el smbolo D. Si esto lo queremos reflejar en la lista
tenemos que hacer una insercin en medio de ella, lo que supone desplazar todos los elementos
de la lista un puesto hacia abajo.
Existe un mtodo alternativo, en el cual las transiciones se realizan si el smbolo no
coincide con el de la lista; si coincide se sigue comparando con el resto de los smbolos del estado
hasta que encontremos un delimitador de palabra; as se pueden hacer inserciones de nuevas
palabras al final de la lista. Es ms, al tiempo que vamos admitiendo palabras del lenguaje
podemos ir construyendo el autmata (y por consiguiente la lista).
Ahora la lista sera la siguiente; suponiendo el orden: ACE, BAD, BADE, BED:
SiaadimosADD:

1A2
1A2
C
C5
E
E
"ACE"

2B
2B
A4
A4
D
D
3"BAD"
3
3E
3E
"BADE"

4E
4E
D
D
"BED"

5D

46

Analizador Lxico

Veamos ahora algunos ejemplos de A. Lxicos:


1.- Dada la siguiente gramtica BNF:
A
B
C

B string C nombre
C ':' decimal
A ':=' octal

Construir en Pascal un analizador lxico para los correspondientes smbolos terminales:


"string" tiene el formato usual, "nombre" es un identificador alfanumrico comenzando por letra,
"decimal" y "octal" son constantes numricas enteras, distinguindose la segunda porque
comienza por la cifra 0. Los blancos y finales de lnea sirven de separadores. Se admiten
comentarios a partir de un ';' hasta el final de la lnea.

47

Analizador Lxico

program al1p89 (fuente, output);


const
ceof = '$';
ceoln = '#';
mc = 10;
type simb = (ident, octal, decimal, strin, dosp, asig, finfich);
var
fuente : text;
c : char;
s : simb;
cs : record
cars : packed array [1..mc] of char;
long : 0..mc;
end;
procedure error (n : integer);
begin
write ('Error nm. ', n, ' : ');
case n of
1 : writeln ('cifra no permitida en octal.');
2 : writeln ('string inacabada.');
3 : writeln ('carcter no permitido.');
4 : writeln ('nmero demasiado largo.');
5 : writeln ('string demasiado larga.');
end;
end;
procedure sigcar;
begin
if eof (fuente) then c := ceof
else if eoln (fuente) then begin
c := ceoln;
readln (fuente)
end else read (fuente, c);
end;

48

Analizador Lxico

procedure lex;
label 1;
var erralmc : Boolean;
procedure inic;
var i : integer;
begin
erralmc := false;
with cs do begin
long := 0;
for i := 1 to mc do cars [i] := ' '
end
end;
procedure almc;
begin
with cs do begin
erralmc := not (long < mc);
if not erralmc then begin
long := long + 1;
cars [long] := c
end
end
end;
begin (*lex*)
1:
while c in [' ', ';', ceoln] do
if c = ';' then repeat sigcar until c in [ceoln,
ceof]
else sigcar;
if c in ['A'..'Z', 'a'..'z'] then begin
s := ident;
inic;
repeat
almc;
sigcar
until not (c in ['A'..'Z', 'a'..'z', '0'..'9'])
end else if c in ['0'..'9'] then begin
if c = '0' then s := octal else s := decimal;

49

Analizador Lxico

inic;
repeat
almc;
sigcar;
if s = octal then if c in ['8', '9'] then error
(1)
until not (c in ['0'..'9']);
if erralmc then error (4);
end else if c = '"' then begin
s := strin;
inic;
repeat
repeat
sigcar;
if not (c in ['"', ceoln, ceof]) then
almc
until c in ['"', ceoln, ceof];
if c = '"' then begin
sigcar;
if c = '"' then almc
end else begin
error (2);
erralmc := false
end
until c <> '"';
if erralmc then error (5)
end else if c = ':' then begin
sigcar;
if c = '=' then begin
s := asig;
sigcar
end else s := dosp
end else if c = ceof then s := finfich
else begin
error (3);
sigcar;
goto 1
end;
end (*lex*);

50

Analizador Lxico

begin (*program*)
assign (fuente, 'fuente');
reset (fuente);
sigcar;
repeat
lex;
writeln (ord (s), ' ', cs.cars)
until s = finfich;
close (fuente)
end (*program*).

2.- Vamos a ver el A. lxico del Compilador de Pascal llamado P4:

51

Analizador Lxico

Compiler Listing
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

(*$c+,t-,d-,l-*)
(***********************************************
*
*
*
*
*
Portable Pascal compiler
*
*
************************
*
*
*
*
Pascal P4
*
*
*
*
*
*
Authors:
*
*
Urs Ammann
*
*
Kesav Nori
*
*
Christian Jacobi
*
*
*
*
Address:
*
*
*
*
Institut Fuer Informatik
*
*
Eidg. Technische Hochschule
*
*
CH-8096 Zuerich
*
*
*
*
*
*
*
*
*
*
*
************************************************)
program pascalcompiler(input,output,prr);

const displimit = 20; maxlevel = 10;


intsize
=
1;
intal
=
1;
realsize
=
1;
realal
=
1;
charsize
=
1;
charal
=
1;
charmax
=
1;
boolsize
=
1;
boolal
=
1;
ptrsize
=
1;
adral
=
1;
setsize
=
1;
setal
=
1;
stackal
=
1;
stackelsize =
1;
strglgth
=
16;
sethigh
=
47;
setlow
=
0;
ordmaxchar =
63;
ordminchar =
0;
maxint
= 32767;
lcaftermarkstack = 5;
fileal
= charal;

52

Analizador Lxico

57
(* stackelsize = minimum size for 1 stackelement
58
= k*stackal
59
stackal
= scm(all other al-constants)
60
charmax
= scm(charsize,charal)
61
scm = smallest common multiple
62
lcaftermarkstack >= 4*ptrsize+max(x-size)
63
= k1*stackelsize
*)
64
maxstack
=
1;
65
parmal
= stackal;
66
parmsize
= stackelsize;
67
recal
= stackal;
68
filebuffer =
4;
69
maxaddr
= maxint;
70
71
72
73 type
(*describing:*)
74
(*************)
75
76
77
(*basic symbols*)
78
(***************)
79
80
symbol=(ident,intconst,realconst,stringconst,notsy,mulop,addop,relop,
81
lparent,rparent,lbrack,rbrack,comma,semicolon,period,arrow,
82
colon,becomes,labelsy,constsy,typesy,varsy,funcsy,progsy,
83
procsy,setsy,packedsy,arraysy,recordsy,filesy,forwardsy,
84
eginsy,ifsy,casesy,repeatsy,whilesy,forsy,withsy,
85
otosy,endsy,elsesy,untilsy,ofsy,dosy,tosy,downtosy,
86
hensy,othersy);
87
operator = (mul,rdiv,andop,idiv,imod,plus,minus,orop,ltop,leop,geop,gtop
88
eqop,inop,noop);
89
setofsys = set of symbol;
90
chtp = (letter,number,special,illegal,
91
chstrquo,chcolon,chperiod,chlt,chgt,chlparen,chspace);
92
93
(*constants*)
94
(***********)
95
96
cstclass = (reel,pset,strg);
97
csp = ^ constant;
98
constant = record case cclass: cstclass of
99
reel: (rval: packed array [1..strglgth] of char);
100
pset: (pval: setty);
101
strg: (slgth: 0..strglgth;
102
sval: packed array [1..strglgth] of char)
103
end;
104
105
valu = record case intval: boolean of (*intval never set nor tested*)
106
true: (ival: integer);
107
false: (valp: csp)
108
end;
109
110
(*data structures*)

53

Analizador Lxico
111
112
113
114
115
116
117
118
119
120

(*****************)
levrange = 0..maxlevel; addrrange = 0..maxaddr;
structform = (scalar,subrange,pointer,power,arrays,records,files,
tagfld,variant);
declkind = (standard,declared);
stp = ^ structure; ctp = ^ identifier;

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

case form: structform of


scalar:
(case scalkind: declkind of
declared: (fconst: ctp); standard: ());
subrange: (rangetype: stp; min,max: valu);
pointer: (eltype: stp);
power:
(elset: stp);
arrays:
(aeltype,inxtype: stp);
records: (fstfld: ctp; recvar: stp);
files:
(filtype: stp);
tagfld:
(tagfieldp: ctp; fstvar: stp);
variant: (nxtvar,subvar: stp; varval: valu)
end;

structure = packed record


marked: boolean;
size: addrrange;

(*for test phase only*)

(*names*)
(*******)
idclass = (types,konst,vars,field,proc,func);
setofids = set of idclass;
idkind = (actual,formal);
alpha = packed array [1..8] of char;
identifier = packed record
name: alpha; llink, rlink: ctp;
idtype: stp; next: ctp;
case klass: idclass of
konst:(values: valu);
vars: (vkind: idkind; vlev: levrange; vaddr: addrrange);
field: (fldaddr: addrrange);
proc,
func: (case pfdeckind: declkind of
standard: (key: 1..15);
declared: (pflev: levrange; pfname: integer;
case pfkind: idkind of
actual: (forwdecl, extern:
boolean)))
end;
disprange = 0..displimit;
where = (blck,crec,vrec,rec);
(*expressions*)
(*************)
attrkind = (cst,varbl,expr);
vaccess = (drct,indrct,inxd);
attr = record typtr: stp;

54

Analizador Lxico
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

case kind: attrkind of


cst:
(cval: valu);
varbl: (case access: vaccess of
drct: (vlevel: levrange; dplmt: addrrange);
indrct: (idplmt: addrrange))
end;
testp = ^ testpointer;
testpointer = packed record
elt1,elt2 : stp;
lasttestp : testp
end;
(*labels*)
(********)
lbp = ^ labl;
labl = record nextlab: lbp; defined: boolean;

185
labval, labname: integer
186
end;
187
188
extfilep = ^filerec;
189
filerec = record filename:alpha; nextfile:extfilep end;
190
191(*------------------------------------------------------------------*)
192
193
194 var
195
(*returned by source program scanner
196
insymbol:
197
**********)
198
199
sy: symbol;
(*last symbol*)
200
op: operator;
(*classification of last symbol*)
201
val: valu;
(*value of last constant*)
202
lgth: integer;
(*length of last string constant*)
203
id: alpha;
(*last identifier (possibly truncated)*)
204
kk: 1..8;
(*nr of chars in last identifier*)
205
ch: char;
(*last character*)
206
eol: boolean;
(*end of line flag*)
207
208
209
(*counters:*)
210
(***********)
211
212
chcnt: integer;
(*character counter*)
213
lc,ic: addrrange;
(*data location and instruction counter*)
214
linecount: integer;
215
216
217
(*switches:*)
218
(***********)
219
220
dp,
(*declaration part*)
221
prterr,
(*to allow forward references in pointer type
222
declaration by suppressing error message*)
223
list,prcode,prtables: boolean;
(*output options for

55

Analizador Lxico
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248

249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279

-- source program listing


-- printing symbolic code
-- displaying ident and struct tables
-->procedure option*)
debug: boolean;
(*pointers:*)
(***********)
parmptr,
intptr,realptr,charptr,
boolptr,nilptr,textptr: stp;
utypptr,ucstptr,uvarptr,
ufldptr,uprcptr,ufctptr,
fwptr: ctp;
fextfilep: extfilep;
globtestp: testp;

(*pointers to entries of standard ids*)


(*pointers to entries for undeclared ids*)
(*head of chain of forw decl type ids*)
(*head of chain of external files*)
(*last testpointer*)
(*bookkeeping of declaration levels:*)
(************************************)

level: levrange;
disx,
top: disprange;

(*current static level*)


(*level of last id searched by searchid*)
(*top of display*)

display:
(*where:
means:*)
array [disprange] of
packed record
(*=blck:
id is variable id*)
fname: ctp; flabel: lbp; (*=crec:
id is field id in record with*)
case occur: where of
(*
constant address*)
crec: (clev: levrange; (*=vrec:
id is field id in record with*)
cdspl: addrrange);(*
variable address*)
vrec: (vdspl: addrrange)
end;
(* --> procedure withstatement*)
(*error messages:*)
(*****************)
errinx: 0..10;
(*nr of errors in current source line*)
errlist:
array [1..10] of
packed record pos: integer;
nmr: 1..400
end;

(*expression compilation:*)
(*************************)
gattr: attr;

(*describes the expr currently compiled*)


(*structured constants:*)

56

Analizador Lxico
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312

313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335

(***********************)
constbegsys,simptypebegsys,typebegsys,blockbegsys,selectsys,facbegsys,
statbegsys,typedels: setofsys;
chartp : array[char] of chtp;
rw: array [1..35(*nr. of res. words*)] of alpha;
frw: array [1..9] of 1..36(*nr. of res. words + 1*);
rsy: array [1..35(*nr. of res. words*)] of symbol;
ssy: array [char] of symbol;
rop: array [1..35(*nr. of res. words*)] of operator;
sop: array [char] of operator;
na: array [1..35] of alpha;
mn: array [0..60] of packed array [1..4] of char;
sna: array [1..23] of packed array [1..4] of char;
cdx: array [0..60] of -4..+4;
pdx: array [1..23] of -7..+7;
ordint: array [char] of integer;
intlabel,mxint10,digmax: integer;
(*------------------------------------------------------------------*)
procedure endofline;
var lastpos,freepos,currpos,currnmr,f,k: integer;
begin
if errinx > 0 then
(*output error messages*)
begin write(output,linecount:6,' **** ':9);
lastpos := 0; freepos := 1;
for k := 1 to errinx do
begin
with errlist[k] do
begin currpos := pos; currnmr := nmr end;

if currpos = lastpos then write(output,',')


else
begin
while freepos < currpos do
begin write(output,' '); freepos := freepos + 1 end;
write(output,'^');
lastpos := currpos
end;
if currnmr < 10 then f := 1
else if currnmr < 100 then f := 2
else f := 3;
write(output,currnmr:f);
freepos := freepos + f + 1
end;
writeln(output); errinx := 0
end;
linecount := linecount + 1;
if list and (not eof(input)) then
begin write(output,linecount:6,' ':2);
if dp then write(output,lc:7) else write(output,ic:7);
write(output,' ')
end;
chcnt := 0

57

Analizador Lxico
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376

377
378
379
380
381
382
383
384
385
386
387
388
389
390
391

end

(*endofline*) ;

procedure error(ferrnr: integer);


begin
if errinx >= 9 then
begin errlist[10].nmr := 255; errinx := 10 end
else
begin errinx := errinx + 1;
errlist[errinx].nmr := ferrnr
end;
errlist[errinx].pos := chcnt
end (*error*) ;
procedure insymbol;
(*read next basic symbol of source program and return its
description in the global variables sy, op, id, val and lgth*)
label 1,2,3;
var i,k: integer;
digit: packed array [1..strglgth] of char;
string: packed array [1..strglgth] of char;
lvp: csp; test: boolean;
procedure nextch;
begin if eol then
begin if list then writeln(output); endofline
end;
if not eof(input) then
begin eol := eoln(input); read(input,ch);
if list then write(output,ch);
chcnt := chcnt + 1
end
else
begin writeln(output,'
*** eof ','encountered');
test := false
end
end;
procedure options;
begin
repeat nextch;
if ch <> '*' then

begin
if ch = 't' then
begin nextch; prtables := ch = '+' end
else
if ch = 'l' then
begin nextch; list := ch = '+';
if not list then writeln(output)
end
else
if ch = 'd' then
begin nextch; debug := ch = '+' end
else
if ch = 'c' then
begin nextch; prcode := ch = '+' end;
nextch

58

Analizador Lxico
392
end
393
until ch <> ','
394 end (*options*) ;
395
396 begin (*insymbol*)
397 1:
398
repeat while ((ch = ' ') or (ch = ' ')) and not eol do nextch;
399
test := eol;
400
if test then nextch
401
until not test;
402
if chartp[ch] = illegal then
403
begin sy := othersy; op := noop;
404
error(399); nextch
405
end
406
else
407
case chartp[ch] of
408
letter:
409
begin k := 0;
410
repeat
411
if k < 8 then
412
begin k := k + 1; id[k] := ch end ;
413
nextch
414
until chartp[ch] in [special,illegal,chstrquo,chcolon,
415
chperiod,chlt,chgt,chlparen,chspace];
416
if k >= kk then kk := k
417
else
418
repeat id[kk] := ' '; kk := kk - 1
419
until kk = k;
420
for i := frw[k] to frw[k+1] - 1 do
421
if rw[i] = id then
422
begin sy := rsy[i]; op := rop[i]; goto 2 end;
423
sy := ident; op := noop;
424 2:
end;
425
number:
426
begin op := noop; i := 0;
427
repeat i := i+1; if i<= digmax then digit[i] := ch; nextch
428
until chartp[ch] <> number;
429
if ((ch = '.') and (input^ <> '.')) or (ch = 'e') then
430
begin
431
k := i;
432
if ch = '.' then
433
begin k := k+1; if k <= digmax then digit[k] := ch;
434
nextch; (*if ch = '.' then begin ch := ':'; goto 3 end;*)
435
if chartp[ch] <> number then error(201)
436
else
437
repeat k := k + 1;
438
if k <= digmax then digit[k] := ch; nextch
439
until chartp[ch] <> number
440
end;

441
442
443
444
445
446
447

if ch = 'e' then
begin k := k+1; if k <= digmax then digit[k] := ch;
nextch;
if (ch = '+') or (ch ='-') then
begin k := k+1; if k <= digmax then digit[k] := ch;
nextch
end;

59

Analizador Lxico
448
if chartp[ch] <> number then error(201)
449
else
450
repeat k := k+1;
451
if k <= digmax then digit[k] := ch; nextch
452
until chartp[ch] <> number
453
end;
454
new(lvp,reel); sy:= realconst; lvp^.cclass := reel;
455
with lvp^ do
456
begin for i := 1 to strglgth do rval[i] := ' ';
457
if k <= digmax then
458
for i := 2 to k + 1 do rval[i] := digit[i-1]
459
else begin error(203); rval[2] := '0';
460
rval[3] := '.'; rval[4] := '0'
461
end
462
end;
463
val.valp := lvp
464
end
465
else
466 3:
begin
467
if i > digmax then begin error(203); val.ival := 0 end
468
else
469
with val do
470
begin ival := 0;
471
for k := 1 to i do
472
begin
473
if ival <= mxint10 then
474
ival := ival*10+ordint[digit[k]]
475
else begin error(203); ival := 0 end
476
end;
477
sy := intconst
478
end
479
end
480
end;
481
chstrquo:
482
begin lgth := 0; sy := stringconst; op := noop;
483
repeat
484
repeat nextch; lgth := lgth + 1;
485
if lgth <= strglgth then string[lgth] := ch
486
until (eol) or (ch = '''');
487
if eol then error(202) else nextch
488
until ch <> '''';
489
lgth := lgth - 1;
(*now lgth = nr of chars in string*)
490
if lgth = 0 then error(205) else
491
if lgth = 1 then val.ival := ord(string[1])
492
else
493
begin new(lvp,strg); lvp^.cclass:=strg;
494
if lgth > strglgth then
495
begin error(399); lgth := strglgth end;
496
with lvp^ do
497
begin slgth := lgth;
498
for i := 1 to lgth do sval[i] := string[i]
499
end;
500
val.valp := lvp
501
end
502
end;
503
chcolon:
504
begin op := noop; nextch;

60

Analizador Lxico
505
if ch = '=' then
506
begin sy := becomes; nextch end
507
else sy := colon
508
end;
509
chperiod:
510
begin op := noop; nextch;
511
if ch = '.' then
512
begin sy := colon; nextch end
513
else sy := period
514
end;
515
chlt:
516
begin nextch; sy := relop;
517
if ch = '=' then
518
begin op := leop; nextch end
519
else
520
if ch = '>' then
521
begin op := neop; nextch end
522
else op := ltop
523
end;
524
chgt:
525
begin nextch; sy := relop;
526
if ch = '=' then
527
begin op := geop; nextch end
528
else op := gtop
529
end;
530
chlparen:
531
begin nextch;
532
if ch = '*' then
533
begin nextch;
534
if ch = '$' then options;
535
repeat
536
while (ch <> '*') and not eof(input) do nextch;
537
nextch
538
until (ch = ')') or eof(input);
539
nextch; goto 1
540
end;
541
sy := lparent; op := noop
542
end;
543
special:
544
begin sy := ssy[ch]; op := sop[ch];
545
nextch
546
end;
547
chspace: sy := othersy
548 end (*case*)
549 end (*insymbol*) ;
550
551 procedure enterid(fcp: ctp);
552
(*enter id pointed at by fcp into the name-table,
553
which on each declaration level is organised as
554
an unbalanced binary tree*)
555
var nam: alpha; lcp, lcpl: ctp; lleft: boolean;
556 begin nam := fcp^.name;
557
lcp := display[top].fname;
558
if lcp = nil then
559
display[top].fname := fcp
560
else
561
begin
562
repeat lcpl := lcp;
563
if lcp^.name = nam then
(*name conflict, follow right link*)
564
begin error(101); := lcp^.rlink; lleft := false end
565
else

61

Analizador Lxico
566
567
568

if lcp^.name < nam then


begin lcp := lcp^.rlink; lleft := false end
else begin lcp := lcp^.llink; lleft:=true end

3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829

new(ucstptr,konst);
with ucstptr^ do
begin name :=
; idtype := nil; next := nil ;
values.ival := 0; klass := konst
end;
new(uvarptr,vars);
with uvarptr^ do
begin name :=
; idtype := nil; vkind := actual;
next := nil; vlev := 0; vaddr := 0; klass := vars
end;
new(ufldptr,field);
with ufldptr^ do
begin name :=
; idtype := nil; next := nil; fldaddr := 0;
klass := field
end;
new(uprcptr,proc,declared,actual);
with uprcptr^ do
begin name :=
; idtype:= nil; forwdecl := false;
next := nil; extern := false; pflev := 0; genlabel(pfname);
klass := proc; pfdeckind := declared; pfkind := actual
end;
new(ufctptr,func,declared,actual);
with ufctptr^ do
begin name :=
; idtype := nil; next := nil;
forwdecl := false; extern := false; pflev := 0; genlabel(pfname);
klass := func; pfdckind := declared; pfkind := actual
end
end (*enterundecl*);
procedure initscalars;
begin fwptr := nil;
prtables := false; list := true; prcode := true; debug := true;
dp := true; prterr := true; errinx := 0;
intlabel := 0; kk := 8; fextfilep := nil;
lc := lcaftermarkstack+filebuffer*charmax;
(* note in the above reservation of buffer store for 2 text files *)
ic := 3; eol := true; linecount := 0;
ch := ' '; chcnt := 0;
globtestp := nil;
mxint10 := maxint div 10; digmax := strglgth - 1;
end (*initscalars*) ;
procedure initsets;
begin
constbegsys := [addop,intconst,realconst,stringconst,ident];
simptypebegsys := [lparent] + constbegsys;
typebegsys:=[arrow,packedsy,arraysy,recordsy,setsy,filesy]+simptypebegsys;
typedels := [arraysy,recordsy,setsy,filesy];
blockbegsys := [labelsy,constsy,typesy,varsy,procsy,funcsy,beginsy];
selectsys := [arrow,period,lbrack];
facbegsys := [intconst,realconst,stringconst,ident,lparent,lbrack,notsy];
statbegsys := [beginsy,gotosy,ifsy,whilesy,repeatsy,forsy,withsy,casesy];
end (*initsets*) ;
procedure inittables;
procedure reswords;
begin
rw[ 1] := 'if
rw[ 4] := 'to
rw[ 7] := 'end
rw[10] := 'div

';
';
';
';

rw[ 2]
rw[ 5]
rw[ 8]
rw[11]

:=
:=
:=
:=

'do
'in
'for
'mod

62

';
';
';
';

rw[ 3]
rw[ 6]
rw[ 9]
rw[12]

:=
:=
:=
:=

'of
'or
'var
'set

';
';
';
';

Analizador Lxico
3830
3831
3832

3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886

rw[13] := 'and
rw[16] := 'else
rw[19] := 'case

'; rw[14] := 'not


'; rw[17] := 'with
'; rw[20] := 'type

'; rw[15] := 'then


'; rw[18] := 'goto
';

';
';

rw[21] := 'file
'; rw[22] := 'begin
';
rw[23] := 'until
'; rw[24] := 'while
'; rw[25] := 'array
rw[26] := 'const
'; rw[27] := 'label
';
rw[28] := 'repeat '; rw[29] := 'record '; rw[30] := 'downto
rw[31] := 'packed '; rw[32] := 'forward '; rw[33] := 'program
rw[34] := 'function'; rw[35] := 'procedur';
frw[1] := 1; frw[2] := 1; frw[3] := 7; frw[4] := 15; frw[5]
frw[6] := 28; frw[7] := 32; frw[8] := 34; frw[9] := 36;
end (*reswords*) ;
procedure symbols;
begin
rsy[ 1] := ifsy;
rsy[ 2] := dosy;
rsy[ 4] := tosy;
rsy[ 5] := relop;
rsy[ 7] := endsy;
rsy[ 8] := forsy;
rsy[10] := mulop;
rsy[11] := mulop;
rsy[13] := mulop;
rsy[14] := notsy;
rsy[16] := elsesy;
rsy[17] := withsy;
rsy[19] := casesy;
rsy[20] := typesy;
rsy[21] := filesy;
rsy[22] := beginsy;
rsy[23] := untilsy;
rsy[24] := whilesy;
rsy[26] := constsy;
rsy[27] := labelsy;
rsy[28] := repeatsy; rsy[29] := recordsy;
rsy[31] := packedsy; rsy[32] := forwardsy;
rsy[34] := funcsy;
rsy[35] := procsy;
ssy['+'] := addop ;
ssy['-'] := addop;
ssy['/'] := mulop ;
ssy['('] := lparent;
ssy['$'] := othersy ; ssy['='] := relop;
ssy[','] := comma ;
ssy['.'] := period;
ssy['['] := lbrack ; ssy[']'] := rbrack;
ssy['^'] := arrow ;
ssy['<'] := relop;
ssy[';'] := semicolon;
end (*symbols*) ;

rsy[ 3]
rsy[ 6]
rsy[ 9]
rsy[12]
rsy[15]
rsy[18]

:=
:=
:=
:=
:=
:=

';
';
';
:= 22;

ofsy;
addop;
varsy;
setsy;
thensy;
gotosy;

rsy[25] := arraysy;
rsy[30] := downtosy;
rsy[33] := progsy;
ssy['*'] :=
ssy[')'] :=
ssy[' '] :=
ssy['''']:=
ssy[':'] :=
ssy['>'] :=

mulop;
rparent;
othersy;
othersy;
colon;
relop;

procedure rators;
var i: integer;
begin
for i := 1 to 35 (*nr of res words*) do rop[i] := noop;
rop[5] := inop; rop[10] := idiv; rop[11] := imod;
rop[6] := orop; rop[13] := andop;
for i := ordminchar to ordmaxchar do sop[chr(i)] := noop;
sop['+'] := plus; sop['-'] := minus; sop['*'] := mul; sop['/'] := rdiv;
sop['='] := eqop; sop['<'] := ltop; sop['>'] := gtop;
end (*rators*) ;
procedure procmnemonics;
begin
sna[ 1] :=' get'; sna[ 2]
sna[ 5] :=' rdc'; sna[ 6]
sna[ 9] :=' wrc'; sna[10]
sna[13] :=' rst'; sna[14]
sna[17] :=' exp'; sna[18]
sna[21] :=' rln'; sna[22]
end (*procmnemonics*) ;

:='
:='
:='
:='
:='
:='

put';
wri';
wrs';
eln';
sqt';
wln';

sna[ 3]
sna[ 7]
sna[11]
sna[15]
sna[19]
sna[23]

63

:='
:='
:='
:='
:='
:='

rdi';
wro';
pak';
sin';
log';
sav';

sna[ 4]
sna[ 8]
sna[12]
sna[16]
sna[20]

:='
:='
:='
:='
:='

rdr';
wrr';
new';
cos';
atn';

Analizador Lxico
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896

3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943

procedure instrmnemonics;
begin
mn[ 0] :=' abi'; mn[ 1]
mn[ 4] :=' and'; mn[ 5]
mn[ 8] :=' eof'; mn[ 9]
mn[12] :=' int'; mn[13]
mn[16] :=' mpr'; mn[17]
mn[20] :=' odd'; mn[21]
mn[24] :=' sqi'; mn[25]

mn[28] :=' uni'; mn[29]


mn[32] :=' ent'; mn[33]
mn[36] :=' ixa'; mn[37]
mn[40] :=' mov'; mn[41]
mn[44] :=' xjp'; mn[45]
mn[48] :=' geq'; mn[49]
mn[52] :=' leq'; mn[53]
mn[56] :=' str'; mn[57]
mn[60] :=' ujc';
end (*instrmnemonics*) ;

:='
:='
:='
:='
:='
:='
:='

abr';
dif';
flo';
ior';
ngi';
sbi';
sqr';

mn[ 2]
mn[ 6]
mn[10]
mn[14]
mn[18]
mn[22]
mn[26]

:='
:='
:='
:='
:='
:='
:='

adi';
dvi';
flt';
mod';
ngr';
sbr';
sto';

mn[ 3]
mn[ 7]
mn[11]
mn[15]
mn[19]
mn[23]
mn[27]

:='
:='
:='
:='
:='
:='
:='

adr';
dvr';
inn';
mpi';
not';
sgs';
trc';

:='
:='
:='
:='
:='
:='
:='
:='

stp';
fjp';
lao';
mst';
chk';
grt';
les';
ujp';

mn[30]
mn[34]
mn[38]
mn[42]
mn[46]
mn[50]
mn[54]
mn[58]

:='
:='
:='
:='
:='
:='
:='
:='

csp';
inc';
lca';
ret';
cup';
lda';
lod';
ord';

mn[31]
mn[35]
mn[39]
mn[43]
mn[47]
mn[51]
mn[55]
mn[59]

:='
:='
:='
:='
:='
:='
:='
:='

dec';
ind';
ldo';
sro';
equ';
ldc';
neq';
chr';

procedure chartypes;
var i : integer;
begin
for i := ordminchar to ordmaxchar do chartp[chr(i)] := illegal;
chartp['a'] := letter ;
chartp['b'] := letter ; chartp['c'] := letter ;
chartp['d'] := letter ; chartp['e'] := letter ;
chartp['f'] := letter ; chartp['g'] := letter ;
chartp['h'] := letter ; chartp['i'] := letter ;
chartp['j'] := letter ; chartp['k'] := letter ;
chartp['l'] := letter ; chartp['m'] := letter ;
chartp['n'] := letter ; chartp['o'] := letter ;
chartp['p'] := letter ; chartp['q'] := letter ;
chartp['r'] := letter ; chartp['s'] := letter ;
chartp['t'] := letter ; chartp['u'] := letter ;
chartp['v'] := letter ; chartp['w'] := letter ;
chartp['x'] := letter ; chartp['y'] := letter ;
chartp['z'] := letter ; chartp['0'] := number ;
chartp['1'] := number ; chartp['2'] := number ;
chartp['3'] := number ; chartp['4'] := number ;
chartp['5'] := number ; chartp['6'] := number ;
chartp['7'] := number ; chartp['8'] := number ;
chartp['9'] := number ; chartp['+'] := special ;
chartp['-'] := special ; chartp['*'] := special ;
chartp['/'] := special ; chartp['('] := chlparen;
chartp[')'] := special ; chartp['$'] := special ;
chartp['='] := special ; chartp[' '] := chspace ;
chartp[','] := special ; chartp['.'] := chperiod;
chartp['''']:= chstrquo; chartp['['] := special ;
chartp[']'] := special ; chartp[':'] := chcolon ;
chartp['^'] := special ; chartp[';'] := special ;
chartp['<'] := chlt
; chartp['>'] := chgt
;
ordint['0'] := 0; ordint['1'] := 1; ordint['2'] := 2;
ordint['3'] := 3; ordint['4'] := 4; ordint['5'] := 5;
ordint['6'] := 6; ordint['7'] := 7; ordint['8'] := 8;
ordint['9'] := 9;

64

Analizador Lxico
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960

end;
procedure
begin
cdx[ 0]
cdx[ 4]
cdx[ 8]
cdx[12]
cdx[16]
cdx[20]
cdx[24]
cdx[28]
cdx[32]
cdx[36]
cdx[40]
cdx[44]
cdx[48]

initdx;
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=

0;
-1;
0;
-1;
-1;
0;
0;
-1;
0;
-1;
-2;
-1;
-1;

cdx[ 1]
cdx[ 5]
cdx[ 9]
cdx[13]
cdx[17]
cdx[21]
cdx[25]
cdx[29]
cdx[33]
cdx[37]
cdx[41]
cdx[45]
cdx[49]

3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000

cdx[52]
cdx[56]
cdx[60]
pdx[ 1]
pdx[ 5]
pdx[ 9]
pdx[13]
pdx[17]
pdx[21]
end;

:=
:=
:=
:=
:=
:=
:=
:=
:=

-1;
-1;
0;
-1;
-2;
-3;
-1;
0;
-1;

cdx[53] := -1; cdx[54] := +1; cdx[55] := -1;


cdx[57] := 0; cdx[58] := 0; cdx[59] := 0;
pdx[ 2]
pdx[ 6]
pdx[10]
pdx[14]
pdx[18]
pdx[22]

:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=

:=
:=
:=
:=
:=
:=

0;
-1;
0;
-1;
0;
-1;
0;
0;
-1;
+1;
0;
0;
-1;

-1;
-3;
-4;
0;
0;
-1;

cdx[ 2]
cdx[ 6]
cdx[10]
cdx[14]
cdx[18]
cdx[22]
cdx[26]
cdx[30]
cdx[34]
cdx[38]
cdx[42]
cdx[46]
cdx[50]

pdx[ 3]
pdx[ 7]
pdx[11]
pdx[15]
pdx[19]
pdx[23]

:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=

-1;
-1;
0;
-1;
0;
-1;
-2;
0;
0;
+1;
0;
0;
+1;

cdx[ 3]
cdx[ 7]
cdx[11]
cdx[15]
cdx[19]
cdx[23]
cdx[27]
cdx[31]
cdx[35]
cdx[39]
cdx[43]
cdx[47]
cdx[51]

:= -2; pdx[ 4]
:= -3; pdx[ 8]
:= 0; pdx[12]
:= 0; pdx[16]
:= 0; pdx[20]
:= -1;

:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=

-1;
-1;
-1;
-1;
0;
0;
0;
0;
0;
+1;
-1;
-1;
+1;

:= -2;
:= -3;
:= -2;
:= 0;
:= 0;

begin (*inittables*)
reswords; symbols; rators;
instrmnemonics; procmnemonics;
chartypes; initdx;
end (*inittables*) ;
begin
(*initialize*)
(************)
initscalars; initsets; inittables;
(*enter standard names and standard types:*)
(******************************************)
level := 0; top := 0;
with display[0] do
begin fname := nil; flabel := nil; occur := blck end;
enterstdtypes;
stdnames; entstdnames;
enterundecl;
top := 1; level := 1;
with display[1] do
begin fname := nil; flabel := nil; occur := blck end;

(*compile:* ) rewrite(prr); (* comment this out when compiling with pcom *)


(**********)
insymbol;
programme(blockbegsys+statbegsys-[casesy]);
end.

65

Analizador Lxico

66

Analizador Lxico

LEX:
- LEX: Esta es una herramienta usada para la generacin automtica de analizadores lxicos.
Estudiaremos cmo construir un analizador lxico a partir de una especificacin de
smbolos terminales (tokens) en forma de lista de expresiones regulares.
El programa fuente LEX es una especificacin de un analizador lxico, consistente en un
conjunto de expresiones regulares, junto con una accin para cada expresin regular. La accin
ser una parte del cdigo que ser ejecutada si se reconoce un smbolo terminal especificado por
la correspondiente expresin terminal. Normalmente, una accin indicar al analizador sintctico
que encontr el smbolo terminal, generando su entrada en la tabla de smbolos, etc. La salida del
LEX es un programa que ser el analizador lxico construido en base a la especificacin fuente
de LEX.
Podemos ver a LEX como un compilador para un lenguaje muy bueno para escribir
analizadores lxicos y otras tareas de procesamiento de textos. El LEX nos proporciona como
salida un programa que simula un autmata finito. Este programa usa una tabla de transiciones
como datos. Esto es mostrado en la figura, donde el analizador lxico L es la tabla de transiciones
ms el programa que simula un autmata finito arbitrario expresado como una tabla de
transiciones. Solo L se incluira en el compilador a construir.

LEXCompiladorAnalizador

fuenteLEXlxicoL

TextodeAnalizadorSecuenciade

entradalxicoLsmbolosterminales

67

Analizador Lxico

DEFINICIONES AUXILIARES:
El programa fuente LEX consta de dos partes, una secuencia de "definiciones auxiliares"
seguida por una secuencia de "reglas de traslacin". Las definiciones auxiliares son secuencias de
la forma:
D 1 = R1
D 2 = R2
.
.
.
D n = Rn
Di son nombres distintos y cada Ri es una expresin regular cuyos smbolos pertenecen a
U { D1, D2, ..., Di-1 }, es decir, caracteres o nombres previamente definidos. Los Di son
nombres de expresiones regulares. es nuestro alfabeto de entrada (por ejemplo: conjuntos de
caracteres ASCII o EBCDIC).
Ejemplo: Podemos definir los identificadores para un lenguaje de programacin tpico con
la siguiente secuencia de definiciones auxiliares:
letra = A B ... Z
dgito = 0 1 ... 9
identificador = letra ( letra dgito )*

REGLAS DE TRASLACIN:
Son sentencias de la forma:
P1 { A1 }
P2 { A2 }
.
.
.
Pm { Am }

68

Analizador Lxico

donde cada Pi es una expresin regular llamada "patrn" (pattern), sobre el alfabeto
compuesto por y los nombres de definiciones auxiliares. Los patrones describen la forma de los
smbolos terminales. Cada Ai es un fragmento de programa que describe la accin que el
analizador lxico debe realizar cuando se encuentra con Pi.
Los Ai's estarn escritos en un lenguaje de programacin convencional; aqu usaremos,
para nuestros ejemplos, un "pseudo-lenguaje" informal que es bastante sencillo. Para crear el
analizador lxico L, cada uno de los Ai debe ser compilado en cdigo mquina.
El analizador lxico L creado por LEX se comporta de la siguiente forma: L lee su
entrada, un carcter cada vez, hasta que encuentre el prefijo ms largo de la entrada que coincida
con la expresin regular, Pi. Una vez L ha encontrado este prefijo, lo extrae de la entrada y lo
ubica en el buffer llamado TOKEN. Entonces L ejecutar la accin Ai. Una vez finalizada Ai, L
devolver el control al reconocedor. Cuando se requiera, L repetir esta serie de acciones con la
entrada restante.
Es posible que ninguno de los smbolos terminales indicados en las expresiones regulares
coincida con algn prefijo de la entrada. En este caso, se produce un error, y L deber transferir
el control a alguna rutina de manejo de errores. Tambin es posible que dos o ms patrones
coincidan con el mismo prefijo ms largo de la entrada restante. Si esto ocurre, L deber decidir
en favor del smbolo terminal que llegue primero en la lista de reglas de traslacin.
Ejemplo: Consideremos el conjunto de smbolos terminales siguiente:
Token
Cdigo
Valor

begin
1

end
2

if
3

then
4

else
5

identificador
6
puntero a la tabla de smbolos
constante
7
puntero a la tabla de smbolos
<
8
1
<=
8
2
=
8
3
<>
8
4
>
8
5
>=
8
6

69

Analizador Lxico

Daremos una especificacin LEX para estos smbolos terminales.


El analizador lxico producido por LEX siempre devolver una cantidad simple, de tipo
token, al reconocedor. Tambin pasar un valor, ste estar en la variable global LEXVAL.
El programa que se muestra a continuacin es un programa LEX que define el analizador
lxico deseado:
DEFINICIONES AUXILIARES
letra = A B ... Z
dgito = 0 1 ... 9
REGLAS DE TRASLACIN
BEGIN
END
IF
THEN
ELSE
letra(letradgito)*
dgito+
<
<=
=
<>
>
>=

{ return 1 }
{ return 2 }
{ return 3 }
{ return 4 }
{ return 5 }
{ LEXVAL := INSTALL(); return 6 }
{ LEXVAL := INSTALL(); return 7 }
{ LEXVAL := 1; return 8 }
{ LEXVAL := 2; return 8 }
{ LEXVAL := 3; return 8 }
{ LEXVAL := 4; return 8 }
{ LEXVAL := 5; return 8 }
{ LEXVAL := 6; return 8 }

Supongamos que al analizador lxico resultante de las reglas anteriores le llega como
entrada BEGIN seguido por blancos. Tanto el primer patrn como el sexto coinciden con
BEGIN, y el patrn no coincide con una string ms larga. Como el patrn para la palabra
reservada BEGIN precede al de identificador, en la lista anterior, el conflicto es resuelto en favor
de la palabra reservada. En general, la estrategia de resolucin de ambigedades de LEX facilita
la eleccin de palabras reservadas sobre identificadores colocando estas en la cabeza de la lista.

70

Analizador Lxico

Para el siguiente ejemplo, supongamos que <= son los dos primeros caracteres ledos.
Aunque el patrn < coincide con el primer carcter, este no es el patrn que coincide con el
prefijo ms largo de la entrada. Entonces la estrategia LEX que comprueba el prefijo ms largo
con un patrn se encarga de resolver de una forma fcil el conflicto entre < y <= en la forma
deseada. (eligiendo como siguiente smbolo terminal a <=).
EL OPERADOR "LOOKAHEAD":
Ciertos lenguajes de programacin necesitan la caracterstica "lookahead" para especificar
correctamente sus analizadores lxicos. Un ejemplo tpico de FORTRAN es la secuencia: DO 10
I=1.25 donde no podemos saber que no es una sentencia DO hasta no ver el punto decimal, sino
que en este caso es una asignacin del identificador DO10I. Usaremos / como un operador en la
expresin regular que indicar que el smbolo terminal acaba en el punto donde aparece / si lo
encontramos en la entrada. Entonces una especificacin para la palabra reservada DO podra ser:
DO / (letradgito)* = (letradgito)*,
Con esta especificacin, el analizador lxico mirara hacia delante hasta encontrar la coma
para estar seguro de que no es una sentencia de asignacin. Con lo que solo los caracteres D y O
anteriores a / sern extrados de la entrada y ubicados en el buffer TOKEN.

71

Analizador Lxico

REFERENCIAS BIBLIOGRFICAS:
[Aho 77]
Aho, A. V. and J. D. Ullman. Principles of Compiler Design.
Addison-Wesley Pub. Co. Reading, Massachusetts, EE.UU.
[Aho 86]
Aho, A. V., R. Sethi and J. D. Ullman. Compilers; Principles, Techniques, and Tools.
Addison-Wesley Pub. Co. Reading, Massachusetts, EE.UU.
[Aho 90]
Aho, A. V., R. Sethi y J. D. Ullman. Compiladores; Principios, tcnicas y herramientas.
Addison-Wesley Iberoamericana (Versin en Castellano).
[Sanchis 86]
Sanchis Llorca, F. J. y Galan Pascual, C. Compiladores; Teora y construccin. Paraninfo.
S. A. Madrid.
[Snchez 89]
Snchez Dueas, G. y J. A. Valverde Andreu. Compiladores e Intrpretes; Un enfoque
pragmtico. (2 Edicin. Corregida y ampliada).
Daz de Santos. Madrid.
[Gries 75]
Gries, D. Construccin de Compiladores
Paraninfo. Madrid.
[P4]
Pemberton, S. and M.C. Daniels. Pascal
Assembler/Interppreter. Ellis Horwood-Publishers

Implementation.

Compiler

and

[Fortes 87]
Fortes, J. Recopilacin de apuntes de la asignatura Traductores e Intrpretes. Curso 8687.
[LEX]
Chapter5. Lex: A Lexical Analyzer.
XENIX. Programmer's Guide.

72

También podría gustarte