forked from jdortizv/teoria-de-la-compilacion
-
Notifications
You must be signed in to change notification settings - Fork 0
/
yylex.py
164 lines (132 loc) · 4.85 KB
/
yylex.py
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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
###< 2016-08-28 18:12:00.904393 >###
#
# yylex.py
# analizador lexico para el lenguaje bcc
#
import sys, shlex, pickle
import dataTree as dt
#
# analizador lexico
#
def yylex(filename, quiet=False):
# estructura de datos.
# crea un arbol para almacenar la informacion
# generada por las distintas componentes
# del interprete
DATA = dt.TreeNode('DATA', {'filename': filename})
SOURCECODE = dt.SubNode(DATA, 'SOURCECODE')
TOKENTABLE = dt.SubNode(DATA, 'TOKENTABLE')
SYNTAXTREE = dt.SubNode(DATA, 'SYNTAXTREE')
SYMBOLTABLE = dt.SubNode(DATA, 'SYMBOLTABLE')
# preparacion del codigo fuente.
# sourceCode es un vector donde cada elemento
# es una linea del codigo fuente incluyendo
# comentarios. Despues almacena el codigo
# en la estructura de datos
sourceCode = open(filename, 'r').readlines()
for i, line in enumerate(sourceCode):
lineno = i
x = dt.SubNode(SOURCECODE, lineno)
if line[-1] == '\n':
line = line[:-1]
x.text = line
#
# yyputtoken.
# esta es uan funcion auxiliar que agrega cada token y su
# correspondiente lexema a la tabla de tokens de forma
# secuencial.
# yyputtoken crea un nuevo nodo a la tabla se simbolos
#
def yyputtoken(token, lexeme, lineno):
#
dt.SubNode(TOKENTABLE, token, dict(lexeme=lexeme, lineno=lineno))
#
# analizador lexico.
# esta es la rutina de analisis lexico como tal.
# se procesa una linea a la vez, para todas las
# lineas del codigo fuente
lineno = -1
for line in sourceCode:
# shlex.
# es una utilidad de python que permite descomponer
# una cadena de texto en sus lexemas componentes. shlex
# descarta automaticamente las lineas de comentarios.
#
# lexemes.
# es una lista de strings, donde cada string es un lexema
lexemes = list(shlex.shlex(line))
n = 0
lineno += 1
while n < len(lexemes):
# lex1: es el lexema actual
# lex2: es el lexema actual concatenado con el
# siguiente. se requiere para poder reconocer
# algunas secuencias como '>=' que shlex
# separa en '>' y '='
lex1 = lexemes[n]
lex2 = lexemes[n] + lexemes[n+1] if n+1 < len(lexemes) else None
# en este punto se inicia el reconocimiento de cada
# uno de los lexemas que conforman el codigo fuente
if lex1[0] == "'" or lex1[0] == '"':
#
yyputtoken('STR', lex1, lineno)
#
elif lex1 in 'function var end write when do if else while return'.split():
#
yyputtoken(lex1.upper(), lex1, lineno)
#
elif lex2 in ':= =='.split():
yyputtoken(lex2, lex2, lineno)
n += 1
elif lex1 in ': , ; ( ) { } < + *'.split():
yyputtoken(lex1, lex1, lineno)
elif lex1 in 'true false'.split():
yyputtoken('BOOL', lex1, lineno)
elif lex1 in 'bool num'.split():
yyputtoken('DATATYPE', lex1, lineno)
elif lex1 == '@':
yyputtoken('UFID', lex2, lineno)
n += 1
elif lex1 == '$':
yyputtoken('BFID', lex2, lineno)
n += 1
elif (lex1 == '.' and
n+1 < len(lexemes) and
lexemes[n+1].isdigit()):
lex1 = '.' + lexemes[n+1]
yyputtoken('NUM', lex1, lineno)
n += 1
elif lex1.isdigit():
if n+1 < len(lexemes) and lexemes[n+1] == '.':
lex1 += '.'
n += 1
if n+1 < len(lexemes) and lexemes[n+1].isdigit():
lex1 += lexemes[n+1]
n += 1
yyputtoken('NUM', lex1, lineno)
elif lex1.isalnum():
yyputtoken('ID', lex1, lineno)
else:
msg = '{}:Lexical error at line <{}>: '.format(filename, lineno)
msg += 'Unexpected symbol <{}>'.format(lex1)
# msg += '--> ' + sourceCode[lineno]
print(msg)
sys.exit()
n += 1
yyputtoken('END', 'end', len(lexemes))
# en este punto se han reconocido todos los
# lexemas y se procede a almacenar el resultado
# en un archivo en disco
with open(filename + '.dataTree', 'wb') as f:
pickle.dump(DATA, f)
if quiet == False:
#
dt.printTree(TOKENTABLE)
#
if __name__ == '__main__':
if len(sys.argv) > 1:
for filename in sys.argv[1:]:
yylex(filename)
else:
filename = input()
yylex(filename)