-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
375 lines (341 loc) · 22.8 KB
/
index.html
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
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
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
<!-- Author: Iago Lourenço ([email protected]) / index.html -->
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<link rel="icon" type="image/x-icon" href="public/favicon.ico" />
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>compi{LPD}lador</title>
<link rel="stylesheet" href="styles/dracula-theme.css" />
<link rel="stylesheet" href="styles/main.css" />
</head>
<body>
<script>
window.addEventListener('scroll', function () {
var header = document.querySelector('header');
header.classList.toggle('scrolled', window.scrollY > 0);
});
</script>
<header id="nav" class="menu">
<a href="./index.html">
<h1 class="logo">compi{<span class="logo_snip">LPD</span>}lador</h1>
</a>
<div id="button-container">
<a href="compilador" class="button">Acessar compilador</a>
<a href="maquina-virtual" class="button">Acessar máquina virtual</a>
</div>
</header>
<article>
<h2>Introdução</h2>
<p>Este projeto foi feito para a disciplina de Construção de Compiladores da PUC-Campinas e consiste na criação
de um compilador para a linguagem didádica LPD.</p>
<p>Foi definida uma linguagem didática e simples para a elaboração do projeto, sendo uma linguagem de
programação estruturada semelhante
à
linguagem de
programação estruturada PASCAL. Esta linguagem tem o nome de LPD (Linguagem de Programação Didática).
</p>
<p>O compilador desenvolvido para esta linguagem, nomeado
compi{LPD}lador contém os
módulos léxico,
sintático e
semântico, que fazem a análise do código, gerando no final um arquivo com linguagem de máquina onde o mesmo
será interpretado e executado por uma máquina virtual também criada pela equipe.</p>
</p>
<p>Este projeto foi desenvolvido em JavaScript puro e estilizado em CSS também puro, sem o uso de qualquer
framework ou extensão, sendo capaz de rodar em praticamente todos os navegadores!</p>
<h2>Documentação</h2>
<p>Abaixo disponibilizamos a documentação da linguagem e dos conceitos abordados pela disciplina de Construção
de Compiladores, assim como um resumo de cada módulo e conceito utilizado no compilador.
</p>
</p>
<a style="width: fit-content; display: inline-block; font-family: var(--mono); "
href="https://github.com/iaglourenco/CSD/blob/main/Notas%20de%20Aula%20de%20Compiladores.pdf">Notas
de Aula de Compiladores</a>
<h2>Módulos do compilador</h2>
<h3>Léxico</h3>
<p>Este módulo é responsável por realizar a análise léxica do código fonte, ou seja, a leitura do código fonte e
a
identificação dos tokens. Para isso, o módulo léxico deve realizar a leitura do código fonte e, a cada
caractere
lido, deve verificar se o mesmo pertence a algum dos conjuntos de caracteres definidos na tabela de
símbolos.
Caso o caractere pertença a algum conjunto, o mesmo deve ser concatenado a uma lista que representa os
tokens
identificados no código. Caso o caractere não pertença a nenhum conjunto, um erro deve ser lançado indicando
a linha e coluna do mesmo. O módulo léxico deve ser capaz de identificar os seguintes tokens:</p>
<ul>
<li>Palavras reservadas</li>
<li>Identificadores</li>
<li>Números</li>
<li>Operadores aritméticos</li>
<li>Operadores relacionais</li>
<li>Pontuação</li>
<li>Comentários</li>
</ul>
<p>A implementação do módulo léxico pode ser encontrada no
arquivo <a style="width: fit-content; display: inline-block;" target="_blank" noreferrer nopener
href="https://github.com/iaglourenco/CSD/blob/main/compilador/js/lexico.js">lexico.js</a>.</p>
<h4>Descrição em BNF da linguagem</h4>
<p>Para a descrição da linguagem LPD, foi utilizado a notação BNF (Backus-Naur Form), sendo uma notação para
especificar gramáticas formais.</p>
<p>Espaços, tabulações, caracteres não
imprimíveis e quebras de linha são ignorados.</p>
<details>
<summary>Clique para expandir</summary>
<pre class="code_container">
<code><programa>::= programa <identificador> ; <bloco>.</code>
<br>
<code><bloco>::= [<etapa de declaração de variáveis>][<etapa de declaração de sub-rotinas>]<comandos></code>
<br>
<code class="comment">//Declarações</code>
<br>
<code><etapa de declaração de variáveis>::= var <declaração de variáveis>;{<declaração de variáveis>;}</code>
<br>
<code><declaração de variáveis>::= <identificador> {, <identificador>} : <tipo></code>
<br>
<code><tipo> ::= (inteiro | booleano)</code>
<br>
<code><etapa de declaração de sub-rotinas> ::= (<declaração de procedimento>;|<declaração de função>;){<declaração de procedimento>;|<declaração de função>;}</code>
<br>
<code><declaração de procedimento> ::= procedimento <identificador>;<bloco></code>
<br>
<code><declaração de função> ::= funcao <identificador>: <tipo>;<bloco></code>
<br>
<code class="comment">//Comandos</code>
<br>
<code><comandos>::= inicio<comando>{;<comando>}[;]fim</code>
<br>
<code><comando>::= (<atribuição_chprocedimento>|<comando condicional> |<comando enquanto> |<comando
leitura> |<comando escrita> |<comandos>)</code>
<br>
<code><atribuição_chprocedimento>::= (<comando atribuicao>|<chamada de procedimento>)</code>
<br>
<code><comando atribuicao>::= <identificador> := <expressão></code>
<br>
<code><chamada de procedimento>::= <identificador></code>
<br>
<code><comando condicional>::= se <expressão> entao <comando> [senao <comando>]</code>
<br>
<code><comando enquanto> ::= enquanto <expressão> faca <comando></code>
<br>
<code><comando leitura> ::= leia ( <identificador> )</code>
<br>
<code><comando escrita> ::= escreva ( <identificador> )</code>
<br>
<code class="comment">//Expressões</code>
<br>
<code><expressão>::= <expressão simples> [<operador relacional><expressão simples>]</code>
<br>
<code><operador relacional>::= (!= | = | < | <= | > | >=)</code>
<br>
<code><expressão simples> ::= [ + | - ] <termo> {( + | - | ou) <termo> }</code>
<br>
<code><termo>::= <fator> {(\* | div | e) <fator>}</code>
<br>
<code><fator> ::= (<variável> | <número> | <chamada de função> | (<expressão>) | verdadeiro |
falso | nao <fator>)</code>
<br>
<code><variável> ::= <identificador></code>
<br>
<code><chamada de função> ::= <identificador ></code>
<br>
<code class="comment">//Números e identificadores</code>
<br>
<code><identificador> ::= <letra> {<letra> | <dígito> | \_ }</code>
<br>
<code><número> ::= <dígito> {<dígito>}</code>
<br>
<code><dígito> ::= (0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9)</code>
<br>
<code><letra> ::= (a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|
A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z)</code>
<br>
<code class="comment">//Comentários</code>
<code class="comment">/*Uma vez que os comentários servem apenas como documentação do código fonte, ao realizar
a compilação deste código faz-se necessário eliminar todo o conteúdo entre seus
delimitadores.*/</code>
<br>
<code>delimitadores : { }
<br><br>
</code>
</pre>
</details>
<h3>Sintático</h3>
<p>
Este módulo é responsável por realizar a análise sintática do código fonte, ou seja, a verificação da
estrutura
gramatical do código fonte. Para isso, o módulo sintático deve realizar a leitura dos tokens gerados pelo
módulo
léxico e verificar se estes tokens estão de acordo com a gramática definida para a linguagem. Caso o token
lido
não esteja de acordo com a gramática, um erro deve ser lançado indicando a linha e coluna do mesmo
</p>
<p>A partir do sintático os outros módulos são requisitados, fazendo com que o sintático seja o "motor" de todo
o compilador orquestrando todos os
outros módulos, produzindo no final de toda a execução o código em linguagem de máquina.
</p>
<p>A implementação do módulo sintático pode ser encontrada no
arquivo <a style="width: fit-content; display: inline-block;" target="_blank" noreferrer nopener
href="https://github.com/iaglourenco/CSD/blob/main/compilador/js/sintatico.js">sintatico.js</a>.
</p>
<h3>Semântico</h3>
<p>
Este módulo é responsável por realizar a análise semântica do código fonte, ou seja, verifica se as
sentenças tem um significado coerente do ponto de vista da semântica da linguagem. O módulo possui funções
que consultam a tabela de símbolos durante a analise de uma expressão e verifica se a sentença faz sentido
verificando a tipagem e significado dos tokens.
</p>
<p>O módulo possui funções como a conversão para o formato pós-fixo de expressões matemáticas facilitando
várias tarefas de verificação como as definidas a seguir, além de controlar a inserção e manutenção da
tabela de símbolos.</p>
<ul>
<li>Verificação da ocorrência da duplicidade na declaração de um identificador</li>
<li>Verificação de uso de identificadores não declarados</li>
<li>Verificação de compatibilidade de tipos</li>
<li>Verificação dos comandos escreva e leia (variável inteira)</li>
<li>Verificação de chamadas de procedimento e função</li>
<li>Verificação dos operadores unários – , + , nao</li>
</ul>
<p>É fácil perceber que as chamadas para o analisador semântico não passam de linhas de
comandos a serem inseridos no “corpo” do analisador sintático, nos locais apropriados.
Vale lembrar que a Linguagem LPD não permite a passagem de parâmetros nos
procedimentos e funções. Caso isso fosse permitido, então deveríamos também verificar a
consistência no número de argumentos e parâmetros, bem como sua compatibilidade de tipos.</p>
<p>A implementação do módulo semântico pode ser encontrada no
arquivo <a style="width: fit-content; display: inline-block;" target="_blank" noreferrer nopener
href="https://github.com/iaglourenco/CSD/blob/main/compilador/js/semantico.js">semantico.js</a>.
<h3>Tabela de Símbolos</h3>
<p>A tabela de símbolos é uma estrutura de dados contendo um registro para cada
identificador, com os campos contendo os atributos do identificador. As informações sobre o
identificador são coletadas pelas fases de análise de um compilador e usada pelas fases de
síntese de forma a gerar o código-alvo. Durante a Análise Lexical a cadeia de caracteres que
forma um identificador é armazenada em uma entrada da tabela de símbolos. As fases
seguintes do compilador acrescentam informações a esta entrada. A fase de geração utiliza as
informações armazenadas para gerar o código adequado.
</p>
<p>Para este projeto foi utilizado a tabela de símbolos como uma pilha sendo que uma vez terminada a compilação
de um procedimento os símbolos locais
são descartados. </p>
<p>Este modelo para a tabela, usando um vetor, supõe que as buscas serão sequenciais.
Isso pode ser proibitivo se o número de símbolos for muito grande. A mesma “lógica” de
funcionamento pode ser aplicada a outras organizações de tabela visando a melhoria no tempo
de acesso.</p>
<p>A implementação da tabela de símbolos pode ser encontrada no
arquivo <a style="width: fit-content; display: inline-block;" target="_blank" noreferrer nopener
href="https://github.com/iaglourenco/CSD/blob/main/compilador/js/tabelaSimbolos.js">tabelaSimbolos.js</a>.
</p>
<h3 id="gerador">Geração de código</h3>
<p>
O módulo de geração de código é responsável por gerar o código em linguagem de máquina a partir do código
fonte. Para isso é necessário que o código fonte esteja de acordo com a gramática da linguagem e que não
haja erros semânticos para isso o módulo de geração de código é o último módulo a ser executado, pois ele é
o
responsável por gerar o código em linguagem de máquina, ou seja, o código final.
</p>
<p>A seguir estão listadas as definições das instruções em linguagem de máquina:</p>
<ul>
<li><strong>START</strong> - Inicia o programa. Deve ser a primeira instrução do programa.</li>
<li><strong>HLT</strong> - Finaliza o programa. Deve ser a última instrução do programa.</li>
<li><strong>LDV</strong> k - Carrega o valor do local de memoria <strong>k</strong> no topo da memória.
</li>
<li><strong>LDC</strong> n - Carrega o valor <strong>n</strong> no topo da memória.</li>
<li><strong>STR</strong> v - Armazena no local de memoria <strong>v</strong> o valor do topo da memória.
</li>
<li><strong>ADD</strong> - Soma os dois valores do topo da memória e armazena o resultado no
topo da memória.</li>
<li><strong>SUB</strong> - Subtrai os dois valores do topo da memória e armazena o resultado no
topo da memória.</li>
<li><strong>MULT</strong> - Multiplica os dois valores do topo da memória e armazena o resultado
no
topo da memória.</li>
<li><strong>DIVI</strong> - Divide os dois valores do topo da memória e armazena o resultado no
topo da memória.</li>
<li><strong>INV</strong> - Inverte o sinal do valor do topo da memória.</li>
<li><strong>AND</strong> - Realiza a operação lógica AND entre os dois valores do topo da memória de
operandos e armazena o resultado no topo da memória.</li>
<li><strong>OR</strong> - Realiza a operação lógica OR entre os dois valores do topo da memória de
operandos e armazena o resultado no topo da memória.</li>
<li><strong>NEG</strong> - Realiza a operação lógica NOT entre os dois valores do topo da memória de
operandos e armazena o resultado no topo da memória.</li>
<li><strong>CME</strong> - Compara se o valor do topo da memória é menor que o valor do topo
menos 1 da memória. Se for, o valor 1 é armazenado no topo da memória. Caso contrário, o
valor 0 é armazenado no topo da memória.</li>
<li><strong>CMA</strong> - Compara se o valor do topo da memória é maior que o valor do topo
menos 1 da memória. Se for, o valor 1 é armazenado no topo da memória. Caso contrário, o
valor 0 é armazenado no topo da memória.</li>
<li><strong>CEQ</strong> - Compara se o valor do topo da memória é igual ao valor do topo menos
1 da memória. Se for, o valor 1 é armazenado no topo da memória. Caso contrário, o valor 0
é armazenado no topo da memória.</li>
<li><strong>CDIF</strong> - Compara se o valor do topo da memória é diferente do valor do topo
menos 1 da memória. Se for, o valor 1 é armazenado no topo da memória. Caso contrário, o
valor 0 é armazenado no topo da memória.</li>
<li><strong>CMEQ</strong> - Compara se o valor do topo da memória é menor ou igual ao valor do
topo menos 1 da memória. Se for, o valor 1 é armazenado no topo da memória. Caso contrário,
o valor 0 é armazenado no topo da memória.</li>
<li><strong>CMAQ</strong> - Compara se o valor do topo da memória é maior ou igual ao valor do
topo menos 1 da memória. Se for, o valor 1 é armazenado no topo da memória. Caso contrário,
o valor 0 é armazenado no topo da memória.</li>
<li><strong>RD</strong> - Lê um valor do teclado e armazena no topo da memória.</li>
<li><strong>PRN</strong> - Imprime o valor do topo da memória.</li>
<li><strong>ALLOC</strong> b,o - Aloca espaço na memória sendo <strong>b=base</strong> e
<strong>o=offset</strong>.
</li>
<li><strong>DALLOC</strong> b,o - Desaloca espaço na memória sendo <strong>b=base</strong> e
<strong>o=offset</strong>.
</li>
<li><strong>CALL</strong> f - Chama uma função f.</li>
<li><strong>RETURN</strong> - Retorna o valor de uma função.</li>
<li><strong>JMP</strong> p - Desvia o fluxo de execução para uma instrução com o rotulo <strong>p</strong>.
</li>
<li><strong>JMPF</strong> p - Desvia o fluxo de execução para uma instrução com o rotulo <strong>p</strong>
se o valor do
topo da memória for igual a 0.</li>
<li><strong>NULL</strong> - Instrução nula. Não faz nada.</li>
</ul>
<p>A implementação do módulo de geração de código pode ser encontrada no arquivo <a
style="width: fit-content; display: inline-block;" target="_blank" noreferrer nopener
href="https://github.com/iaglourenco/CSD/blob/main/compilador/js/gerador.js">gerador.js</a>.
</p>
<h3 id="vm">Máquina virtual</h3>
<p>
A máquina virtual é responsável por executar o código gerado pelo compilador. Ela é
composta por um conjunto de instruções, <a style="width: fit-content; display: inline-block;"
href="#gerador">definidas anteriormente</a>, que são executadas
sequencialmente. A
máquina
virtual é composta por um espaço de programa e um espaço de memória.
</p>
<p>
O espaço de programa é composto por um conjunto de instruções que são executadas
sequencialmente, salvo quando há uma instrução de desvio de fluxo. O espaço de memória
é composto por um conjunto de células de memória que podem ser acessadas por meio de
um endereço. Cada célula de memória pode armazenar um valor inteiro.
</p>
<p>A máquina possui também uma interface para depuração, que permite visualizar o estado da
máquina em cada instrução executada. </p>
<p>A implementação da máquina virtual pode ser encontrada no arquivo <a
style="width: fit-content; display: inline-block;" target="_blank" noreferrer nopener
href="https://github.com/iaglourenco/CSD/blob/main/maquina-virtual/js/maquina.js">maquina.js</a>.
<h2>Agradecimentos</h2>
<p>Agradecemos ao professor <a style="width: fit-content; display: inline-block;" target="_blank" noreferrer
nopener href="https://www.linkedin.com/in/ricardo-lu%C3%ADs-de-freitas-312b7b169/">Ricardo
Luís de
Freitas</a> pela oportunidade de participar do projeto e por todo o conhecimento compartilhado
durante o
desenvolvimento do mesmo.</p>
<p>A todos os outros grupos que desenvolveram o mesmo projeto, e que contribuiram de alguma forma para o nosso
aprendizado.</p>
</article>
<footer id=" footer">
<div style="display: flex; justify-content: center;"><a target="_blank" noreferrer nopener
href="https://github.com/iaglourenco">@iagolourenco</a>
<!-- <a target="_blank" noreferrer nopener href="https://github.com/fabioirokawa">@fabioirokawa</a> -->
<!-- <a target="_blank" noreferrer nopener href="https://github.com/marcoslelis">@marcoslelis</a> -->
</div>
<a target="_blank" noreferrer nopener href="https://github.com/iaglourenco/CSD">Ver projeto no GitHub</a>
<p>© 2022 Todos os direitos reservados.</p>
</footer>
</body>
</html>