Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/pgvalle/simplifiedluacompiler
https://github.com/pgvalle/simplifiedluacompiler
Last synced: about 8 hours ago
JSON representation
- Host: GitHub
- URL: https://github.com/pgvalle/simplifiedluacompiler
- Owner: pgvalle
- License: mit
- Created: 2023-11-10T13:34:38.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2023-11-27T02:44:35.000Z (12 months ago)
- Last Synced: 2023-11-27T16:06:24.815Z (12 months ago)
- Language: C++
- Size: 1.01 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Simplified Lua Compiler
## Gramática
A gramática original está no documento
[analise-sintatica.pdf](assets/analise-sintatica.pdf) dentro do diretório assets.\
Seguem as observações da transformação LL(1):1. `Params` e `Names` eram redundantes na gramática.
2. `FunctionBody` não era necessário.
3. `Names` e `Name` eu chamei de `Ids` e `id`, respectivamente.
4. `Stmt` tinha múltiplas regras que iam em “`local ...`” e “`for ...`”.
5. `Block`, `Exps`, `Field`, `BinOp`, `Vars`, `Function` e `Names` estavam ok.
6. `Exp` tinha recursão à esquerda.
7. `PrefixExp` e `Var` tinham recursão indireta. Taquei `PrefixExp` em `Var`, que ganhou recursão à esquerda.\
Depois taquei `Var` em `PrefixExp` porque o First de ambos são iguais.
8. O "OPT" virou "?" para facilitar.```
Block
::= (Stmt;)*Stmt
::= Vars = Exps
| Function
| do Block end
| while Exp do Block end
| if Exp then Block (elseif Exp then Block ElseIf)* (else Block)? end
| return Exps?
| break
| for id Fors
| local DeclsFors
::= (, id)* in Exps do Block end
| = Exp, Exp (, Exp)? do Block endDecls
::= Ids = Exps
| FunctionExp
::= not Exp Exp2
| -Exp Exp2
| PrefixExp Exp2
| Function Exp2
| { Fields? } Exp2
| nil Exp2
| true Exp2
| false Exp2
| Number Exp2
| String Exp2Exp2
::= BinOp Exp Exp2
| ɛExps
::= Exp (, Exp)*PrefixExp
::= id Var2
| ( Exp ) Var2Field
::= [ Exp ] = Exp
| id = ExpFields
::= Field (, Field)*BinOp
::= or | and | < | > | <= | >= | ~= | == | .. | + | - | * | / | ^Var
::= id Var2
| ( Exp ) [ Exp ] Var2Var2
::= [ Exp ] Var2
| ɛVars
::= Var (, Var)*Function
::= function id? ( Ids? ) Block endIds
::= id (, id)*
```## First
```
Block ( break do for function id if local return while ϵ
Stmt ( break do for function id if local return while
Fors , in =
Decls function id
Exp ( - false function id nil not number string true {
Exp2 or and < > <= >= ~= == .. + - * / ^ ϵ
Exps ( - false function id nil not number string true { ϵ
PrefixExp ( id
Field [ id
Fields [ id ϵ
BinOp or and < > <= >= ~= == .. + - * / ^ ϵ
Ids id
Var ( id
Var2 [ ϵ
Vars ( id
Function function
```## Follow
```
Block EOTS else elseif end
Stmt ;
Fors ;
Decls ;
Exp ) , ] do then or and < > <= >= ~= == .. + - * / ^
Exp2 ) , ] do then or and < > <= >= ~= == .. + - * / ^
Exps ; do
PrefixExp ) , ] do then or and < > <= >= ~= == .. + - * / ^
Field ,
Fields }
BinOp ( - false function id nil not number string true {
Ids ) =
Var , =
Var2 ) , = ] or and < > <= >= ~= == .. + - * / ^ do then
Vars =
Function ) , ] ; do then or and < > <= >= ~= == .. + - * / ^
```## Implementação
O analisador sintático está dividido em três arquivos:
[Parser.h](source/Parser.h), [ParserBase.cpp](source/ParserBase.cpp) e
[ParserRules.cpp](source/ParserRules.cpp). Utilizei orientação a objetos, assim
como no trabalho de análise léxica. Então existe uma classe Parser, e ela tem um
Lexer e um Token como campos.#### Observações Gerais
A Primeira coisa importante a se dizer se trata dos nomes das variáveis no
código. `Exp` virou `Expression`, `Stmt` virou `Statement` e por ai vai.Um outro ponto é sobre os métodos que implementam as regras. Eu fiz algumas
coisas diferentes de como está na gramática:1. Criei um procedimento para o padrão `do Block end` chamado `do_statement()`.
Eu chamo ele toda vez que o padrão aparece. O porém é que em teoria deveria
existir uma regra `DoStmt` ou algo assim, mas criá-la deixaria a gramática
maior, então considerei isso somente para a implementação.
2. As implementações de algumas coisas, como as dos comandos for e if, ficaram
meio grandinhas. Por isso eu modulei um pouco mais o código, mesmo não tendo (e
eu não querendo adicionar) as regras `ForStmt` e `IfStmt` na gramática.
3. `Vars` e `Fields` só são chamados dentro de `Stmt` e suas implementações são
pequenas. Então simplesmente os implementei diretamente dentro de `Exp`.#### Funcionamento
**NOTA:** O executável precisa exatamente de 1 argumento: o caminho (relativo
ou absoluto) do arquivo a analisar.`parse()` pega o primeiro token e passa a execução para
`Block`. Quando `Block` termina, `parse()` verifica se o token atual é o `EOTS`.
Se for, ótimo. Senão, continua chamando `Block` enquanto não for.Para tratamento de erro, implementei o método `panic(err_msg, sync_sets)`, que
descarta tokens até que se ache algum dentro de `sync_sets`. No caso de encontrar
`EOTS`, o programa termina.## Testes
![teste 1](tests/test1.png "Test1")
![teste 2](tests/test2.png "Test2")
![teste 2](tests/test3.png "Test3")