Documentos de Académico
Documentos de Profesional
Documentos de Cultura
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
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
[{e1,...,en}]
Analizador Lxico
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 }
>ABBCBC
BCBCC
CC
Analizador Lxico
U 0 V 1
Z 1 1
Z 0 0
Gramticas regulares:
N
Ma
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
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
{ 0, 1 }*
1{10}0
NOTA:
Sinoexisteningnestadofinal,elautmatanoacepta
ningunasecuencia.
13
Analizador Lxico
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
0{1}0
1{1}0
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
18
Analizador Lxico
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
EXPRESIN REGULAR
AFN
AFD
figura *:
Diagrama de estados
equivalente
Sistema
27
de
transicin
Analizador Lxico
e = e 1 e2 = a b
a
/\
b VT
Concatenacin
28
Analizador Lxico
e = e1 e2
e = { e1 }
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
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
31
Analizador Lxico
a)Eliminartrans.
Tenemosdos
posibilidades
b)Trans.
AFD.
AFN
AFD.
-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
- 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
AFD.
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.
rutinassemnticas
estadose'
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
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.
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:
case S of
a:
b:
c:
42
Analizador Lxico
* x ... x ...
reescribimos x (......)
if ... then
else ...
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 ...)+
IDENTIFICACIN DE PALABRAS:
En todo compilador, existen palabras claves (BEGIN ELSE END ...) y no vale la
pena construir un autmata para ellas.
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
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
B string C nombre
C ':' decimal
A ':=' octal
47
Analizador Lxico
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*).
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);
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
(*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
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
level: levrange;
disx,
top: disprange;
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;
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;
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*) ;
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
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[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]
:='
:='
:='
:='
:='
:='
:='
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;
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
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;
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
{ 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