-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLexico.py
287 lines (265 loc) · 9.79 KB
/
Lexico.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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
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
280
281
282
283
284
285
286
287
# ┌----------------------------- ANÁLISIS LÉXICO --- -----------------------------┐
# | Convenciones léxicas implementando autómatas de estado finito. |
# | - PALABRAS RESERVADAS: |
# | * main * repeat, until |
# | * if, then, else * cin, cout |
# | * while |
# | * int, real, boolean |
# | - SÍMBOLOS ESPECIALES: + - * / < <= > >= == != := ( ) { } // /**/ ++ -- , ; |
# | - IDENTIFICADORES: Como en cualquier otro lenguaje. |
# └-------------------------------------------------------------------------------┘
# Algunas palabras reservadas, simbolos especiales han sido desactivados debido a que
# no fueron usados(as) en implementaciones posteriores (do, end, TKN_PERCENT no se usó)
import sys
from enum import Enum
class STATE(Enum):
pass
# Estados generales
ERROR = 0
BEGGIN = 1
END = 2
# Comentario Simple | Comentario multiple
SIMPLE_COMMENT = 3
IN_MULTIPLE_COMMENT = 4
IN_MULTIPLE_COMMENT_END = 5 # Asterisco antes de cerrar
# Operadores
ADDITION = 6
SUBSTRACTION = 7
DIFFERENCE = 8
MULTIPLICATION = 9
# Operadores logicos
DOUBLE_ADDITION = 10
DOUBLE_SUBSTRACTION = 11
# Cadena
IN_STRING = 12
# Numeros
IN_NUMERAL = 13
IN_FLOAT = 14
# Comparacion
IN_LESS = 15
IN_GREATER = 16
IN_NEGATION = 17
IN_ASSIGNMENT = 18
IN_EQUAL = 19
# Fin clase STATE
# Agrega la información del Token: fila col tipoToken CaracteresDesde(punteroAntiguo-punteroActual)
# (Suma 1 por cuestiones de formato)
def appendWithOne(tkn):
global estado
arreglo.append(str(lineaActual) + " " + str(colActual - (contador - cont_inicial)) + " " + tkn +
" " + linea[cont_inicial:contador + 1])
estado = STATE.END
def append(tkn):
global estado
arreglo.append(str(lineaActual) + " " + str(colActual - (contador - cont_inicial)) + " " + tkn +
" " + linea[cont_inicial:contador])
decreasing()
estado = STATE.END
def decreasing():
global contador, colActual
contador -= 1
colActual -= 1
# ----------------------------------- INICIO DE ANALISIS LEXICO ------------------------------
# Para leer desde txt:
# archivo = open("Input.txt")
# Leer el archivo de entrada como argumento (En conjunto con IDE(Java)):
fileLocation = sys.argv[1]
archivo = open(fileLocation)
linea = archivo.read()
linea += "\n"
archivo.close()
pReservadas = {
"main": "TKN_MAIN",
"if": "TKN_IF",
"then": "TKN_THEN",
"else": "TKN_ELSE",
# "end": "TKN_END",
# "do": "TKN_DO",
"while": "TKN_WHILE",
"repeat": "TKN_REPEAT",
"until": "TKN_UNTIL",
"cin": "TKN_CIN",
"cout": "TKN_COUT",
"real": "TKN_REAL",
"int": "TKN_INT",
"boolean": "TKN_BOOLEAN"}
sEspeciales = {
'(': "TKN_LPAREN",
')': "TKN_RPAREN",
'{': "TKN_LBRACE",
'}': "TKN_RBRACE",
';': "TKN_SEMICOLON",
',': "TKN_COMMA"}
estado = STATE.BEGGIN # TOKEN en el que se encuentra
cont_inicial = 0 # Contará las posiciones desde la última
contador = 0 # Puntero que recorrerá el texto
lineaActual = 1 # Linea del archivo en la que se encuentra
lineasExtras = 0 # Contará los \n de un bloque de comentarios
colActual = 1 # Contador de columna en que se encuentra
arreglo = []
errores = []
keys = sEspeciales.keys() # Contendrá todas las llaves para los simbolos especiales
keys2 = pReservadas.keys() # Contendrá todas las llaves para las palabras reservadas
# Cuando hago contador -= 1 es porque vamos a repetir la lectura de ese caracter que rompió con la secuencia del
# token anterior encontrado. colActual -= 1 para seguir con el correcto conteo.
while contador < len(linea):
caracter = linea[contador]
# INICIO DE AUTÓMATA
if estado == STATE.BEGGIN:
if ((caracter >= 'A') & (caracter <= 'Z')) | ((caracter >= 'a') & (caracter <= 'z')) | (caracter == '_'):
estado = STATE.IN_STRING
elif (caracter >= '0') & (caracter <= '9'):
estado = STATE.IN_NUMERAL
elif (caracter == ' ') | (caracter == '\t') | (caracter == '\n'):
colActual += 1
if caracter == '\n':
lineaActual += 1
colActual = 1
cont_inicial = (contador + 1)
contador += 1
continue
elif caracter == '/':
estado = STATE.DIFFERENCE
elif caracter == '+':
# appendWithOne("TKN_ADD")
estado = STATE.ADDITION
elif caracter == '-':
estado = STATE.SUBSTRACTION
# appendWithOne("TKN_MINUS")
elif caracter == '<':
estado = STATE.IN_LESS
elif caracter == '>':
estado = STATE.IN_GREATER
elif caracter == ':':
estado = STATE.IN_ASSIGNMENT
elif caracter == '!':
estado = STATE.IN_NEGATION
elif caracter == '=':
estado = STATE.IN_EQUAL
elif caracter == '*':
appendWithOne("TKN_MULTI")
elif caracter == '%':
appendWithOne("TKN_PERCENT")
elif caracter in keys:
appendWithOne(sEspeciales.get(caracter))
else:
estado = STATE.ERROR # Estado de Error
elif estado == STATE.IN_STRING:
if ((caracter < 'A') | (caracter > 'Z')) & ((caracter < 'a') | (caracter > 'z')) & \
((caracter < '0') | (caracter > '9')) & (caracter != '_'):
if linea[cont_inicial:contador] in keys2:
append(pReservadas.get(linea[cont_inicial:contador]))
else:
append("TKN_ID")
elif estado == STATE.IN_NUMERAL:
if caracter == '.':
if (linea[contador + 1] >= '0') & (linea[contador + 1] <= '9'):
estado = STATE.IN_FLOAT
else:
estado = STATE.ERROR
elif (caracter < '0') | (caracter > '9'):
append("TKN_NUM")
elif estado == STATE.IN_FLOAT:
if (caracter < '0') | (caracter > '9'):
append("TKN_NUM")
elif estado == STATE.DIFFERENCE:
if caracter == '*':
estado = STATE.IN_MULTIPLE_COMMENT
elif caracter == '/':
estado = STATE.END # Forma de terminar
while (contador < len(linea)) & (linea[contador] != '\n'):
contador += 1
# Quitamos todos los caracteres que continuan en la linea
while linea[cont_inicial] == '\n':
cont_inicial += 1
lineaActual += 1
colActual = 1
else:
append("TKN_DIV")
elif estado == STATE.IN_MULTIPLE_COMMENT:
if caracter == '*':
estado = STATE.IN_MULTIPLE_COMMENT_END
elif caracter == "\n":
lineasExtras += 1
elif estado == STATE.IN_MULTIPLE_COMMENT_END:
if caracter == "\n":
lineasExtras += 1
if caracter == '/':
estado = STATE.END # Terminó, volvemos al estado inicial
# appendWithOne("TKN_COMMENT")
if linea[contador + 1] == '\n':
cont_inicial += 1
lineaActual += lineasExtras
lineasExtras = 0
elif caracter == '*':
estado = STATE.IN_MULTIPLE_COMMENT_END
else:
estado = STATE.IN_MULTIPLE_COMMENT
elif estado == STATE.ADDITION:
if caracter == '+':
appendWithOne("TKN_PPLUS")
# elif (caracter >= '0') & (caracter <= '9'): # Para numeros con signo +3
# estado = STATE.IN_NUMERAL
# decreasing()
else:
append("TKN_ADD")
elif estado == STATE.SUBSTRACTION:
if caracter == '-':
appendWithOne("TKN_LLESS")
# # elif (caracter >= '0') & (caracter <= '9'): # Para numeros con signo -3
# # estado = STATE.IN_NUMERAL
# # decreasing()
else:
append("TKN_MINUS")
elif estado == STATE.IN_LESS:
if caracter == '=':
appendWithOne("TKN_ELESS")
else:
append("TKN_LESS")
elif estado == STATE.IN_GREATER:
if caracter == '=':
appendWithOne("TKN_EMORE")
else:
append("TKN_MORE")
elif estado == STATE.IN_ASSIGNMENT:
if caracter == '=':
appendWithOne("TKN_ASSIGN")
else:
decreasing()
estado = STATE.ERROR
elif estado == STATE.IN_NEGATION:
if caracter == '=':
appendWithOne("TKN_NEQUAL")
else:
decreasing()
estado = STATE.ERROR
elif estado == STATE.IN_EQUAL:
if caracter == '=':
appendWithOne("TKN_EQUAL")
else:
decreasing()
estado = STATE.ERROR
if estado == STATE.END:
cont_inicial = (contador + 1)
estado = STATE.BEGGIN
if estado == STATE.ERROR:
appendWithOne("TKN_ERROR")
cont_inicial = (contador + 1)
estado = STATE.BEGGIN
contador += 1
colActual += 1
# FIN DE AUTÓMATA (while)
# Si está en estado de error el ultimo caracter/linea no es valido(a) o
# si está en un estado NO TERMINANTE (DIF. de END o BEGGIN) hubo Comentario multiple sin cerrar
if (estado == STATE.ERROR) | ((estado != STATE.END) & (estado != STATE.BEGGIN)):
decreasing()
if (estado == STATE.IN_MULTIPLE_COMMENT) | (estado == STATE.IN_MULTIPLE_COMMENT_END):
arreglo.append(str(lineaActual) + " " + str(colActual) + " TKN_ERROR " + "[Comentario]")
else:
appendWithOne("TKN_ERROR")
for tokens in arreglo:
print(tokens)
output = open("Tokens.txt", "w+")
for tokens in arreglo:
output.write(tokens + "\n")
output.close()