-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLexico.hs
More file actions
192 lines (161 loc) · 4.96 KB
/
Lexico.hs
File metadata and controls
192 lines (161 loc) · 4.96 KB
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
{-
- Projeto do interpretador para a linguagem C++
-}
{-
- Módulo para o analisador léxico do interpretador. Para testar use os comandos:
- getProxLexema "/*comentario*/\n//comentario\nint main(){int b=a;return a;}"
- getLexemas "nome_do_arquivo.cpp"
- debug (getLexemas "nome_do_arquivo.cpp")
-}
module Lexico where
import Control.Exception -- throw, ErrorCall
import System.IO -- openFile, ReadMode
import System.IO.Unsafe -- unsafePerformIO
import Char -- isAlphaNum, isSpace, readLitChar
-- Retorna o primeiro elemento de uma lista de entrada.
cabeca (h:t) = h
-- Lê uma lista de entrada e retorna essa lista subtraída do seu primeiro elemento.
cauda (h:t) = t
-- Para depuração apenas! Imprime uma lista de strings separando-as com espaços.
debug :: [String] -> String
debug [] = ""
debug (h:t) =
h ++ " " ++ debug t
-- Lê um arquivo e retorna uma lista com seus lexemas. Autor: Umberto.
leitura :: String -> IO [Char]
leitura nomeDoArquivo =
do x <- openFile nomeDoArquivo ReadMode
y <- hGetContents x
return y
-- Lê um arquivo com código-fonte de C++ e retorna seus lexemas.
getLexemas :: String -> [String]
getLexemas nomeDoArquivo = stringToLexemas (unsafePerformIO (leitura nomeDoArquivo))
{-
- Obtém o próximo lexema do código-fonte de entrada.
- Retorna retornando o lexema e o código-fonte sem o lexema retornado.
- Exemplo de uso: getProxLexema "/*comentario*/\n//comentario\nint main(){int b=a;return a;}"
-}
getProxLexema :: String -> (String, String)
getProxLexema [] = ("","")
getProxLexema (h:t) =
if h == '/' then
let (fonte, lex) = barra t in
if lex == "" then
getProxLexema fonte
else
(lex, fonte)
else if (isAlphaNum h) || (h == '_') || (h == '.') then
let (fonte, nome) = getNomeLexema t [h] in
(nome, fonte)
else if isSpace h then
getProxLexema t
else if h == '"' then
let (fonte, string) = getString t [h] in
(string, fonte)
else if h == '\'' then
let (fonte, caractere) = getCaractere t in
(caractere, fonte)
else if elem h "()[]{},;+-*" then
( [h], t )
else if elem h "=><!" then
if cabeca t == '=' then
( ( h:['='] ), (cauda t) )
else if h == '<' && cabeca t == '<' then
( ( h:['<'] ), (cauda t) )
else if h == '>' && cabeca t == '>' then
( ( h:['>'] ), (cauda t) )
else
( [h], t )
else if h == '&' && cabeca t == '&' then
( "&&", (cauda t) )
else if h == '|' && cabeca t == '|' then
( "||", (cauda t) )
else
let msg = "simbolo inesperado \'" ++ [h] ++ "\'" in
throw (ErrorCall msg)
-- Converte uma string em uma lista de lexemas.
stringToLexemas "" = []
stringToLexemas str =
let (lexema, caudaStr) = getProxLexema str in
lexema : stringToLexemas caudaStr
-- Lê um lexema do tipo Char.
getCaractere :: String -> (String, String)
getCaractere (h:t) =
if h == '\'' || h == '\n' then
let msg = "caractere invalido" in
throw (ErrorCall msg)
else
let [ (caractere, fonte) ] = readLitChar (h:t) in
if ( fonte == [] ) || ( cabeca fonte /= '\'' ) then
let msg = "caractere invalido" in
throw (ErrorCall msg)
else
( (cauda fonte), ( ['\''] ++ [caractere] ++ ['\''] ) )
-- Lê um lexema do tipo String.
getString :: String -> String -> (String, String)
getString [] string =
let msg = "string invalida" in
throw (ErrorCall msg)
getString (h:t) string =
if h == '"' then
( t, (string ++ [h]) )
else if h == '\\' then
let [(caractere, fonte)] = readLitChar (h:t) in
getString fonte (string ++ [caractere])
else if h == '\n' then
let msg = "string invalida" in
throw (ErrorCall msg)
else
getString t (string ++ [h])
-- Lê um nome que pode ser um id ou uma palavra reservada.
getNomeLexema :: String -> String -> (String, String)
getNomeLexema [] nome = ([], nome)
getNomeLexema (h:t) nome =
if (isAlphaNum h) || (h == '_') || (h == '.') then
getNomeLexema t (nome ++ [h])
else
( (h:t), nome )
{-
- Função invocada quando já foi lida uma '/', podendo ser um comentário simples,
- um comentário múltiplo ou o operador de divisão. Dependendo do que for
- chamará a função adequada.
-}
barra :: String -> (String, String)
barra (h:t) =
if h == '/' then
(comentarioSimples t, "")
else if h == '*' then
(comentarioMulti t, "")
else
( (h:t), "/" )
-- Remove comentário simples do código.
comentarioSimples :: String -> String
comentarioSimples [] = []
comentarioSimples (h:t) =
if h == '\n' then
t
else
comentarioSimples t
-- Função que remove comentário múltiplo do código.
comentarioMulti :: String -> String
comentarioMulti [] =
let msg = "comentario \'/*\' nao terminado" in
throw (ErrorCall msg)
comentarioMulti (h:t) =
if h == '*' then
asteriscoComentario t
else
comentarioMulti t
{-
- Auxiliar para a função 'comentarioMulti'. Invocada quando um provável fim do comentário
- é detectado: '*'.
-}
asteriscoComentario :: String -> String
asteriscoComentario [] =
let msg = "comentario \'/*\' nao terminado" in
throw (ErrorCall msg)
asteriscoComentario (h:t) =
if h == '/' then
t
else
comentarioMulti (h:t)