Skip to content

This is a compiler for the L language, an artifical language of the Compilers discipline. Our generated assembly is compatible with the 8086 processor with registers of 16 bits.

License

Notifications You must be signed in to change notification settings

xXHachimanXx/Compiler-project-for-the-L-lang

Repository files navigation

Compiler-project-for-the-L-lang

This is a compiler for the L language, an artifical language of the Compilers discipline.

Our generated assembly is compatible with the 8086 processor with registers of 16 bits.

Running the compiler

Compiling the L language to .asm on Linux:

javac -encoding "UTF-8" Main.java && java Main < test/simple.l > 8086/simple.asm; rm *.class

Transforming the .asm file to an .exe file

To test our .asm files, we used DosBox to emulate a 16 bit operational system like DOS.

Inside DosBox run:

mount c: /COMPLETE/PATH/TO/THE/8086/FOLDER/ON/YOUR/COMPUTER
c:
masm simple; | link simple;
simple.exe

if masm simple; | link simple; does not work for you, you can use:

masm /L simple.asm
link simple.obj
simple.exe

You can refresh the file system running rescan.

If you wanna debug the .exe file, you can simple run debug simple.exe, then, inside the debugger, use t to go to next line, r to show registers and d ds:0 to show 128 memory positions from the start of the data segment. More commands can be found on https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc722863(v=technet.10)?redirectedfrom=MSDN.

Language Grammar

This grammar can be loaded on https://www.bottlecaps.de/rr/ui.

PROGRAM ::= ((VAR_DECLS | CONST_DECLS) ';')* 'main' '{' TERMINATED_STATEMENT* '}'

TERMINATED_STATEMENT ::=
    WRITE_STATEMENT ';'
    | WRITELN_STATEMENT ';'
    | READLN_STATEMENT ';'
    | IF_STATEMENT
    | FOR_STATEMENT
    | ASSIGN_STATEMENT ';'

STATEMENT ::=
    WRITE_STATEMENT
    | WRITELN_STATEMENT
    | READLN_STATEMENT
    | IF_STATEMENT
    | FOR_STATEMENT
    | ASSIGN_STATEMENT

WRITE_STATEMENT ::= 'write' '(' EXPRESSION (',' EXPRESSION)* ')'

WRITELN_STATEMENT ::= 'writeln' '(' EXPRESSION (',' EXPRESSION)* ')'

READLN_STATEMENT ::= 'readln' '(' IDENTIFIER ('[' EXPRESSION ']')? ')'

IF_STATEMENT ::= 'if' '(' EXPRESSION ')' 'then' STATEMENT_OR_STATEMENTS ('else' STATEMENT_OR_STATEMENTS)?

FOR_STATEMENT ::= 'for' '(' COMMA_SEPARATED_STATEMENTS? ';' EXPRESSION ';' COMMA_SEPARATED_STATEMENTS? ')' STATEMENT_OR_STATEMENTS

ASSIGN_STATEMENT ::= IDENTIFIER ('[' EXPRESSION ']')? ':=' EXPRESSION

COMMA_SEPARATED_STATEMENTS ::= STATEMENT (',' STATEMENT)*

STATEMENT_OR_STATEMENTS ::= TERMINATED_STATEMENT | '{' TERMINATED_STATEMENT* '}'

CHARACTER ::= [a-zA-Z0-9_ .,;:(){}[=<>%+*/'"] | ']' | '-'

CHAR_CONST ::= "'" CHARACTER "'"

STRING ::= '"' CHARACTER* '"'

INTEGER ::= [0-9]+

BOOLEAN_CONST ::= 'TRUE' | 'FALSE'

HEX_CHAR ::= '0' [0-9ABCDEF] [0-9ABCDEF] 'h'

CONST ::= ('+' | '-')? INTEGER | HEX_CHAR | CHAR_CONST | STRING | BOOLEAN_CONST

IDENTIFIER ::= ( '_' [a-zA-Z0-9_]* [a-zA-Z0-9] | [a-zA-Z] ) [a-zA-Z0-9_]*

VAR_DECL ::= IDENTIFIER ('[' CONST ']' | ':=' CONST)?

VAR_DECLS ::= ('int' | 'char' | 'boolean') VAR_DECL (',' VAR_DECL)*

CONST_DECL ::= IDENTIFIER '=' CONST

CONST_DECLS ::= 'final' CONST_DECL (',' CONST_DECL)*

PRIMARY_EXPRESSION ::=
    CONST
    | '(' EXPRESSION ')'
    | IDENTIFIER ('[' EXPRESSION ']')?

UNARY_EXPRESSION ::= (('not' | '+' | '-') UNARY_EXPRESSION) | PRIMARY_EXPRESSION

MULTIPLICATIVE_EXPRESSION ::= UNARY_EXPRESSION (('*' | '/' | '%' | 'and') UNARY_EXPRESSION)*

ADDITIVE_EXPRESSION ::= MULTIPLICATIVE_EXPRESSION (('+' | '-' | 'or') MULTIPLICATIVE_EXPRESSION)*

RELATIONAL_EXPRESSION ::= ADDITIVE_EXPRESSION (('=' | '<>' | '<' | '>' | '<=' | '>=') ADDITIVE_EXPRESSION)*

EXPRESSION ::= RELATIONAL_EXPRESSION

Language Grammar with Translation Scheme using professor's notation

PROGRAM -> {1} { [VAR_DECLS | CONST_DECLS] ';' }* 'main' '{' {TERMINATED_STATEMENT}* '}' {2}
{1} {
    MOV AX, data
    MOV DS, AX
}
{2} {
    MOV AH, 4CH
    INT 21H
}

CONST_DECLS -> 'final' CONST_DECL {',' CONST_DECL}*

CONST_DECL -> IDENTIFIER {1} '=' CONST {2}
{1} {
    se tabela.get(IDENTIFIER.lex) != null entao ERRO
    IDENTIFIER.classe = constante
    IDENTIFIER.tamanho = 0
    IDENTIFIER.endereco = contador_global_endereco
}
{2} {
    IDENTIFIER.tipo = CONST.tipo
    se IDENTIFIER.tipo = inteiro entao {
        contador_global_endereco += 2
        dw CONST.lex   # declare word
    }
    senao se IDENTIFIER.tipo = caractere entao {
        contador_global_endereco += 1
        db CONST.lex   # declare byte
    }
    senao se IDENTIFIER.tipo = booleano entao {
        contador_global_endereco += 1
        se CONST.lex = TRUE entao {
            db 1
        } senao {
            db 0
        }
    }
}

VAR_DECLS -> ('int' | 'char' | 'boolean') {1} VAR_DECL {',' {2} VAR_DECL1}*
{1} {
    tipo = guardar o tipo ('int' | 'char' | 'boolean') numa variavel
    VAR_DECL.tipo = tipo # passa o tipo por parâmetro para VAR_DECL
}
{2} {
    VAR_DECL1.tipo = tipo # passa o tipo por parâmetro para VAR_DECL1
}

VAR_DECL -> IDENTIFIER {1} ( '[' CONST {2} ']' | ':=' CONST {3} | lambda {4} )
{1} {
    se tabela.get(IDENTIFIER.lex) != null entao ERRO
    IDENTIFIER.classe = variavel
    IDENTIFIER.endereco = contador_global_endereco
    IDENTIFIER.tipo = VAR_DECL.tipo
    IDENTIFIER.tamanho = 0
}
{2} {
    IDENTIFIER.tamanho = CONST.lex
    se IDENTIFIER.tipo = inteiro entao {
        contador_global_endereco += IDENTIFIER.tamanho * 2
        dw IDENTIFIER.tamanho DUP(?) # declare word array
    }
    senao {
        contador_global_endereco += IDENTIFIER.tamanho
        db IDENTIFIER.tamanho DUP(?) # declare byte array
    }
}
{3} {
    se IDENTIFIER.tipo != CONST.tipo entao ERRO
    se IDENTIFIER.tipo = inteiro entao {
        contador_global_endereco += 2
        dw CONST.lex # declare word
    }
    senao se IDENTIFIER.tipo = caractere entao {
        contador_global_endereco += 1
        db CONST.lex # declare byte
    }
    senao se IDENTIFIER.tipo = booleano entao {
        contador_global_endereco += 1
        se CONST.lex = TRUE entao {
            db 1
        } senao {
            db 0
        }
    }
}
{4} {
    se IDENTIFIER.tipo = inteiro entao {
        contador_global_endereco += 2
        dw 0 # declare word
    }
    senao {
        contador_global_endereco += 1
        db 0 # declare byte
    }
}

TERMINATED_STATEMENT -> WRITE_STATEMENT ';'
TERMINATED_STATEMENT -> WRITELN_STATEMENT ';'
TERMINATED_STATEMENT -> READLN_STATEMENT ';'
TERMINATED_STATEMENT -> IF_STATEMENT
TERMINATED_STATEMENT -> FOR_STATEMENT
TERMINATED_STATEMENT -> ASSIGN_STATEMENT ';'

WRITE_STATEMENT -> 'write' '(' EXPRESSION {1} {',' EXPRESSION1 {2}}* ')'
{1} {
    se EXPRESSION.tamanho > 0 e EXPRESSION.tipo != string entao ERRO
    se EXPRESSION.tipo = inteiro entao {
        db "-00000", '$' ; Cria uma string na área de dados para 
        mov ax, ds:[EXPRESSION.end] ; Traz o inteiro para ax
        mov di, contador_global_endereco
        contador_global_endereco += 7
        mov cx, 0 ;contador
        cmp ax,0 ;verifica sinal
        R0 := NovoRot
        jge R0 ;salta se número positivo

        mov bl, 2Dh ;senão, escreve sinal -
        mov ds:[di], bl
        add di, 1 ;incrementa índice
        neg ax ;toma módulo do número

        R0:
            mov bx, 10 ;divisor
        R1 := NovoRot
        R1:
            add cx, 1 ;incrementa contador
            mov dx, 0 ;estende 32bits p/ div.
            idiv bx ;divide DXAX por BX
            push dx ;empilha valor do resto
            cmp ax, 0 ;verifica se quoc. é 0
            jne R1 ;se não é 0, continua

        R2 := NovoRot
        ;agora, desemp. os valores e escreve o string
        R2:
            pop dx ;desempilha valor
            add dx, 30h ;transforma em caractere
            mov ds:[di],dl ;escreve caractere
            add di, 1 ;incrementa base
            add cx, -1 ;decrementa contador
            cmp cx, 0 ;verifica pilha vazia
            jne R2 ;se não pilha vazia, loop

            mov dx, '$' ;coloca '$'
            mov ds:[di],dl ;escreve caractere
            add di, 1 ;incrementa base
    }
    senao se EXPRESSION.tipo = caractere entao {
        db "0", '$'

        mov al, ds:[EXPRESSION.end] ; Traz o caractere para al
        mov ds:[contador_global_endereco], al ; Coloca na string
        contador_global_endereco += 2
    }
    senao se EXPRESSION.tipo = booleano entao {
        db "0", '$'

        mov al, ds:[EXPRESSION.end] ; Traz o booleano da memória
        mov ah, 0 ; Limpa possível lixo em AH
        cmp ax, 0 ; Compara o valor booleano com 0
        R0 := NovoRot
        je R0

        mov al, '1' ; Se nao for igual a 0
        R1 := NovoRot
        jmp R1

        R0: ; Se for igual a 0
            mov al, '0'

        R1: ; Se for igual a 1
            mov ds:[contador_global_endereco], al ; Coloca na string
            contador_global_endereco += 2
    }
    senao se EXPRESSION.tipo = string entao {
        mov dx, EXPRESSION.end
        mov ah, 09h
        int 21h
    }
}
{2} {
    se EXPRESSION1.tamanho > 0 e EXPRESSION1.tipo != string entao ERRO
    se EXPRESSION1.tipo = inteiro entao {
        db "-00000", '$'
        mov ax, ds:[EXPRESSION1.end] ; Traz o inteiro para ax
        mov di, contador_global_endereco
        contador_global_endereco += 7
        mov cx, 0 ;contador
        cmp ax,0 ;verifica sinal
        R0 := NovoRot
        jge R0 ;salta se número positivo

        mov bl, 2Dh ;senão, escreve sinal -
        mov ds:[di], bl
        add di, 1 ;incrementa índice
        neg ax ;toma módulo do número

        R0:
            mov bx, 10 ;divisor
        R1 := NovoRot
        R1:
            add cx, 1 ;incrementa contador
            mov dx, 0 ;estende 32bits p/ div.
            idiv bx ;divide DXAX por BX
            push dx ;empilha valor do resto
            cmp ax, 0 ;verifica se quoc. é 0
            jne R1 ;se não é 0, continua

        R2 := NovoRot
        ;agora, desemp. os valores e escreve o string
        R2:
            pop dx ;desempilha valor
            add dx, 30h ;transforma em caractere
            mov ds:[di],dl ;escreve caractere
            add di, 1 ;incrementa base
            add cx, -1 ;decrementa contador
            cmp cx, 0 ;verifica pilha vazia
            jne R2 ;se não pilha vazia, loop

            mov dx, '$' ;coloca '$'
            mov ds:[di],dl ;escreve caractere
            add di, 1 ;incrementa base
    }
    senao se EXPRESSION1.tipo = caractere entao {
        db "0", '$'

        mov al, ds:[EXPRESSION1.end] ; Traz o caractere para al
        mov ds:[contador_global_endereco], al ; Coloca na string
        contador_global_endereco += 2
    }
    senao se EXPRESSION1.tipo = booleano entao {
        db "0", '$'

        mov al, ds:[EXPRESSION1.end] ; Traz o booleano da memória
        mov ah, 0 ; Limpa possível lixo em AH
        cmp ax, 0 ; Compara o valor booleano com 0
        R0 := NovoRot
        je R0

        mov al, '1' ; Se nao for igual a 0
        R1 := NovoRot
        jmp R1

        R0: ; Se for igual a 0
            mov al, '0'

        R1: ; Se for igual a 1
            mov ds:[contador_global_endereco], al ; Coloca na string
            contador_global_endereco += 2
    }
    senao se EXPRESSION1.tipo = string entao {
        mov dx, EXPRESSION1.end
        mov ah, 09h
        int 21h
    }
}

WRITELN_STATEMENT -> 'writeln' '(' EXPRESSION {1} {',' EXPRESSION1 {2}}* ')' {3}
{1} {
    se EXPRESSION.tamanho > 0 e EXPRESSION.tipo != string entao ERRO
    se EXPRESSION.tipo = inteiro entao {
        db "-00000", '$'
        mov ax, ds:[EXPRESSION.end] ; Traz o inteiro para ax
        mov di, contador_global_endereco
        contador_global_endereco += 7
        mov cx, 0 ;contador
        cmp ax,0 ;verifica sinal
        R0 := NovoRot
        jge R0 ;salta se número positivo

        mov bl, 2Dh ;senão, escreve sinal -
        mov ds:[di], bl
        add di, 1 ;incrementa índice
        neg ax ;toma módulo do número

        R0:
            mov bx, 10 ;divisor
        R1 := NovoRot
        R1:
            add cx, 1 ;incrementa contador
            mov dx, 0 ;estende 32bits p/ div.
            idiv bx ;divide DXAX por BX
            push dx ;empilha valor do resto
            cmp ax, 0 ;verifica se quoc. é 0
            jne R1 ;se não é 0, continua

        R2 := NovoRot
        ;agora, desemp. os valores e escreve o string
        R2:
            pop dx ;desempilha valor
            add dx, 30h ;transforma em caractere
            mov ds:[di],dl ;escreve caractere
            add di, 1 ;incrementa base
            add cx, -1 ;decrementa contador
            cmp cx, 0 ;verifica pilha vazia
            jne R2 ;se não pilha vazia, loop

            mov dx, '$' ;coloca '$'
            mov ds:[di],dl ;escreve caractere
            add di, 1 ;incrementa base
    }
    senao se EXPRESSION.tipo = caractere entao {
        db "0", '$'

        mov al, ds:[EXPRESSION.end] ; Traz o caractere para al
        mov ds:[contador_global_endereco], al ; Coloca na string
        contador_global_endereco += 2
    }
    senao se EXPRESSION.tipo = booleano entao {
        db "0", '$'

        mov al, ds:[EXPRESSION.end] ; Traz o booleano da memória
        mov ah, 0 ; Limpa possível lixo em AH
        cmp ax, 0 ; Compara o valor booleano com 0
        R0 := NovoRot
        je R0

        mov al, '1' ; Se nao for igual a 0
        R1 := NovoRot
        jmp R1

        R0: ; Se for igual a 0
            mov al, '0'

        R1: ; Se for igual a 1
            mov ds:[contador_global_endereco], al ; Coloca na string
            contador_global_endereco += 2
    }
    senao se EXPRESSION.tipo = string entao {
        mov dx, EXPRESSION.end
        mov ah, 09h
        int 21h
    }
}
{2} {
    se EXPRESSION1.tamanho > 0 e EXPRESSION1.tipo != string entao ERRO
    se EXPRESSION1.tipo = inteiro entao {
        db "-00000", '$'
        mov ax, ds:[EXPRESSION1.end] ; Traz o inteiro para ax
        mov di, contador_global_endereco
        contador_global_endereco += 7
        mov cx, 0 ;contador
        cmp ax,0 ;verifica sinal
        R0 := NovoRot
        jge R0 ;salta se número positivo

        mov bl, 2Dh ;senão, escreve sinal -
        mov ds:[di], bl
        add di, 1 ;incrementa índice
        neg ax ;toma módulo do número

        R0:
            mov bx, 10 ;divisor
        R1 := NovoRot
        R1:
            add cx, 1 ;incrementa contador
            mov dx, 0 ;estende 32bits p/ div.
            idiv bx ;divide DXAX por BX
            push dx ;empilha valor do resto
            cmp ax, 0 ;verifica se quoc. é 0
            jne R1 ;se não é 0, continua

        R2 := NovoRot
        ;agora, desemp. os valores e escreve o string
        R2:
            pop dx ;desempilha valor
            add dx, 30h ;transforma em caractere
            mov ds:[di],dl ;escreve caractere
            add di, 1 ;incrementa base
            add cx, -1 ;decrementa contador
            cmp cx, 0 ;verifica pilha vazia
            jne R2 ;se não pilha vazia, loop

            mov dx, '$' ;coloca '$'
            mov ds:[di],dl ;escreve caractere
            add di, 1 ;incrementa base
    }
    senao se EXPRESSION1.tipo = caractere entao {
        db "0", '$'

        mov al, ds:[EXPRESSION1.end] ; Traz o caractere para al
        mov ds:[contador_global_endereco], al ; Coloca na string
        contador_global_endereco += 2
    }
    senao se EXPRESSION1.tipo = booleano entao {
        db "0", '$'

        mov al, ds:[EXPRESSION1.end] ; Traz o booleano da memória
        mov ah, 0 ; Limpa possível lixo em AH
        cmp ax, 0 ; Compara o valor booleano com 0
        R0 := NovoRot
        je R0

        mov al, '1' ; Se nao for igual a 0
        R1 := NovoRot
        jmp R1

        R0: ; Se for igual a 0
            mov al, '0'

        R1: ; Se for igual a 1
            mov ds:[contador_global_endereco], al ; Coloca na string
            contador_global_endereco += 2
    }
    senao se EXPRESSION1.tipo = string entao {
        mov dx, EXPRESSION1.end
        mov ah, 09h
        int 21h
    }
}
{3} {
    db 13, 10, '$' ; 13 = '\r', 10 = '\n'
    mov dx, contador_global_endereco
    contador_global_endereco += 3
    mov ah, 09h
    int 21h
}

READLN_STATEMENT -> 'readln' '(' IDENTIFIER {1} ( '[' {2} EXPRESSION {3} ']' | lambda {4} ) ')'
{1} {
    se tabela.get(IDENTIFIER.lex).classe = constante entao ERRO

    db 255 DUP(?) ; cria o buffer

    mov dx, contador_global_endereco
    mov al, 0FFh ;ou tam do vetor
    mov ds:[contador_global_endereco], al
    mov ah, 0Ah
    int 21h ; le os caracteres

    mov ah, 02h ; gera a quebra de linha
    mov dl, 0Dh
    int 21h
    mov DL, 0Ah
    int 21h
}
{2} {
    se tabela.get(IDENTIFIER.lex).tamanho = 0 entao ERRO
}
{3} {
    se EXPRESSION.tipo != inteiro ou EXPRESSION.tamanho > 0 entao ERRO
    se tabela.get(IDENTIFIER.lex).tipo = inteiro entao {
        mov di, contador_global_endereco + 2 ;posição do string
        mov ax, 0 ;acumulador
        mov cx, 10 ;base decimal
        mov dx, 1 ;valor sinal +
        mov bh, 0
        mov bl, ds:[di] ;caractere
        cmp bx, 2Dh ;verifica sinal -
        R0 := NovoRot
        jne R0 ;se não negativo
        mov dx, -1 ;valor sinal -
        add di, 1 ;incrementa posição
        mov bl, ds:[di] ;próximo caractere
        R0:
        push dx ;empilha sinal
        mov dx, 0 ;reg. multiplicação
        R1 := NovoRot
        R1:
        cmp bx, 0dh ;verifica fim string ('\r')
        R2 := NovoRot
        je R2 ;salta se fim string
        imul cx ;mult. 10
        add bx, -48 ;converte caractere para inteiro
        add ax, bx ;soma valor caractere
        add di, 1 ;incrementa posição
        mov bh, 0
        mov bl, ds:[di] ;próximo caractere
        jmp R1 ;loop
        R2:
        pop cx ;desempilha sinal
        imul cx ;mult. sinal

        mov bx, ds:[EXPRESSION.end]
        add bx, bx
        
        add bx, IDENTIFIER.end
        mov ds:[bx], ax
    }
    senao se tabela.get(IDENTIFIER.lex).tipo = caractere entao {
        mov al, ds:[contador_global_endereco + 2] ; tras o caractere do buffer para al
        mov bx, ds:[EXPRESSION.end]
        
        add bx, IDENTIFIER.end
        mov ds:[bx], al
    }
}
{4} {
    se tabela.get(IDENTIFIER.lex).tipo = inteiro entao {
        mov di, contador_global_endereco + 2 ;posição do string
        mov ax, 0 ;acumulador
        mov cx, 10 ;base decimal
        mov dx, 1 ;valor sinal +
        mov bh, 0
        mov bl, ds:[di] ;caractere
        cmp bx, 2Dh ;verifica sinal -
        R0 := NovoRot
        jne R0 ;se não negativo
        mov dx, -1 ;valor sinal -
        add di, 1 ;incrementa posição
        mov bl, ds:[di] ;próximo caractere
        R0:
        push dx ;empilha sinal
        mov dx, 0 ;reg. multiplicação
        R1 := NovoRot
        R1:
        cmp bx, 0dh ;verifica fim string ('\r')
        R2 := NovoRot
        je R2 ;salta se fim string
        imul cx ;mult. 10
        add bx, -48 ;converte caractere para inteiro
        add ax, bx ;soma valor caractere
        add di, 1 ;incrementa posição
        mov bh, 0
        mov bl, ds:[di] ;próximo caractere
        jmp R1 ;loop
        R2:
        pop cx ;desempilha sinal
        imul cx ;mult. sinal

        mov ds:[IDENTIFIER.end], ax
    }
    senao se tabela.get(IDENTIFIER.lex).tipo = caractere entao {
        mov al, ds:[contador_global_endereco + 2] ; tras o caractere do buffer para al
        mov ds:[IDENTIFIER.end], al
    }
    senao se tabela.get(IDENTIFIER.lex).tipo = string entao {
        mov di, contador_global_endereco + 2 ;posição do string
        mov si, IDENTIFIER.end

        RotInicio := NovoRot
        RotFim := NovoRot
        RotInicio:
            mov bl, ds:[di] ; tras o caractere do buffer para bl
            mov bh, 0
            cmp bx, 0dh ;verifica fim string ('\r')
            je RotFim
            mov ds:[si], bl
            inc di
            inc si
            jmp RotInicio

        RotFim:
            mov ds:[si], '$'
    }
}

IF_STATEMENT -> 'if' '(' EXPRESSION {1} ')' 'then' STATEMENT_OR_STATEMENTS ( 'else' {2} STATEMENT_OR_STATEMENTS {3} | lambda {4} )
{1} {
    se EXPRESSION.tipo != booleano ou EXPRESSION.tamanho > 0 entao ERRO
    RotFalso := NovoRot
    mov al, ds:[EXPRESSION.end] ; Traz o booleano da memória
    mov ah, 0 ; Limpa possível lixo em AH
    cmp ax, 0 ; Compara o valor booleano com 0
    je RotFalso
}
{2} {
    RotFim := NovoRot
    jmp RotFim
    RotFalso:
}
{3} {
    RotFim:
}
{4} {
    RotFalso:
}

FOR_STATEMENT -> 'for' '(' [COMMA_SEPARATED_STATEMENTS] ';' {1} EXPRESSION {2} ';' [COMMA_SEPARATED_STATEMENTS] ')' {3} STATEMENT_OR_STATEMENTS {4}
{1} {
    RotInicio := NovoRot
    RotIncremento := NovoRot
    RotComandos := NovoRot
    RotFim := NovoRot
    RotInicio:
}
{2} {
    se EXPRESSION.tipo != booleano ou EXPRESSION.tamanho > 0 entao ERRO
    mov al, ds:[EXPRESSION.end] ; Traz o booleano da memória
    mov ah, 0 ; Limpa possível lixo em AH
    cmp ax, 0 ; Compara o valor booleano com 0
    je RotFim
    jmp RotComandos
    RotIncremento:
}
{3} {
    jmp RotInicio
    RotComandos:
}
{4} {
    jmp RotIncremento
    RotFim:
}

ASSIGN_STATEMENT -> IDENTIFIER {1} ( ':=' EXPRESSION1 {2} | '[' {3} EXPRESSION {4} ']' ':=' EXPRESSION2 {5} )
{1} {
    se tabela.get(IDENTIFIER.lex) = null entao ERRO
}
{2} {
    se tabela.get(IDENTIFIER.lex).tipo != EXPRESSION1.tipo entao ERRO
    se IDENTIFIER.tamanho > 0 e EXPRESSION1.tipo != string entao ERRO
    se IDENTIFIER.tipo = inteiro entao {
        mov ax, ds:[EXPRESSION1.end]
        mov ds:[IDENTIFIER.end], ax
    }
    senao se IDENTIFIER.tipo = caractere entao {
        mov al, ds:[EXPRESSION1.end]
        mov ds:[IDENTIFIER.end], al
    }
    senao se IDENTIFIER.tipo = booleano entao {
        mov al, ds:[EXPRESSION1.end]
        mov ds:[IDENTIFIER.end], al
    }
    senao se IDENTIFIER.tipo = string entao {
        mov di, EXPRESSION1.end ;posição do string
        mov si, IDENTIFIER.end

        RotInicio := NovoRot
        RotFim := NovoRot
        RotInicio:
            mov bl, ds:[di] ; tras o caractere do buffer para bl
            mov bh, 0
            cmp bx, 24h ;verifica fim string ('$')
            je RotFim
            mov ds:[si], bl
            inc di
            inc si
            jmp RotInicio

        RotFim:
            mov ds:[si], '$'
    }
}
{3} {
    se tabela.get(IDENTIFIER.lex).tamanho = 0 entao ERRO
}
{4} {
    se EXPRESSION.tipo != inteiro ou EXPRESSION.tamanho > 0 entao ERRO
}
{5} {
    se tabela.get(IDENTIFIER.lex).tipo != EXPRESSION2.tipo entao ERRO
    se EXPRESSION2.tamanho > 0 entao ERRO
    mov bx, IDENTIFIER.end ; traz o endereço base do arranjo
    mov si, ds:[EXPRESSION.end] ; traz o índice para si
    se tabela.get(IDENTIFIER.lex).tipo = inteiro entao {
        add si, si
    }
    add bx, si
    se IDENTIFIER.tipo = inteiro entao {
        mov ax, ds:[EXPRESSION2.end]
        mov ds:[bx], ax
    }
    senao se IDENTIFIER.tipo = caractere entao {
        mov al, ds:[EXPRESSION2.end]
        mov ds:[bx], al
    }
    senao se IDENTIFIER.tipo = booleano entao {
        mov al, ds:[EXPRESSION2.end]
        mov ds:[bx], al
    }
}

STATEMENT_OR_STATEMENTS -> TERMINATED_STATEMENT
STATEMENT_OR_STATEMENTS -> '{' {TERMINATED_STATEMENT}* '}'

COMMA_SEPARATED_STATEMENTS -> STATEMENT {',' STATEMENT}*

STATEMENT -> WRITE_STATEMENT
STATEMENT -> WRITELN_STATEMENT
STATEMENT -> READLN_STATEMENT
STATEMENT -> IF_STATEMENT
STATEMENT -> FOR_STATEMENT
STATEMENT -> ASSIGN_STATEMENT

EXPRESSION -> RELATIONAL_EXPRESSION {1}
{1} {
    EXPRESSION.tipo = RELATIONAL_EXPRESSION.tipo
    EXPRESSION.end = RELATIONAL_EXPRESSION.end
    EXPRESSION.tamanho = RELATIONAL_EXPRESSION.tamanho
}

RELATIONAL_EXPRESSION -> ADDITIVE_EXPRESSION {1} {('=' | '<>' | '<' | '>' | '<=' | '>=') {2} ADDITIVE_EXPRESSION1 {3}}*
{1} {
    RELATIONAL_EXPRESSION.tipo = ADDITIVE_EXPRESSION.tipo
    RELATIONAL_EXPRESSION.end = ADDITIVE_EXPRESSION.end
    RELATIONAL_EXPRESSION.tamanho = ADDITIVE_EXPRESSION.tamanho
}
{2} {
    operador = guardar o operador ('=' | '<>' | '<' | '>' | '<=' | '>=') numa variavel
}
{3} {
    se operador = '=' e RELATIONAL_EXPRESSION.tamanho > 0 e nao(
        e RELATIONAL_EXPRESSION.tipo = string
        e ADDITIVE_EXPRESSION1.tipo = string
    ) entao ERRO

    se operador = '=' entao {
        se RELATIONAL_EXPRESSION.tipo != ADDITIVE_EXPRESSION1.tipo entao ERRO
        se RELATIONAL_EXPRESSION.tipo = inteiro entao {
            mov ax, ds:[RELATIONAL_EXPRESSION.end]
            mov bx, ds:[ADDITIVE_EXPRESSION1.end]
            cmp ax, bx

            RotVerdadeiro := NovoRot
            je RotVerdadeiro
            mov al, 00h
            RotFim := NovoRot
            jmp RotFim

            RotVerdadeiro:
                mov al, 01h

            RotFim:
                RELATIONAL_EXPRESSION.end = NovoTemp()
                mov ds:[RELATIONAL_EXPRESSION.end], al
        }
        senao se RELATIONAL_EXPRESSION.tipo = caractere entao {
            mov al, ds:[RELATIONAL_EXPRESSION.end]
            mov bl, ds:[ADDITIVE_EXPRESSION1.end]
            mov ah, 0
            mov bh, 0
            cmp ax, bx

            RotVerdadeiro := NovoRot
            je RotVerdadeiro
            mov al, 00h
            RotFim := NovoRot
            jmp RotFim

            RotVerdadeiro:
                mov al, 01h

            RotFim:
                RELATIONAL_EXPRESSION.end = NovoTemp()
                mov ds:[RELATIONAL_EXPRESSION.end], al
        }
        senao se RELATIONAL_EXPRESSION.tipo = booleano entao {
            mov al, ds:[RELATIONAL_EXPRESSION.end]
            mov bl, ds:[ADDITIVE_EXPRESSION1.end]
            mov ah, 0
            mov bh, 0
            cmp ax, bx

            RotVerdadeiro := NovoRot
            je RotVerdadeiro
            mov al, 00h
            RotFim := NovoRot
            jmp RotFim

            RotVerdadeiro:
                mov al, 01h

            RotFim:
                RELATIONAL_EXPRESSION.end = NovoTemp()
                mov ds:[RELATIONAL_EXPRESSION.end], al
        }
        senao se RELATIONAL_EXPRESSION.tipo = string entao {
            mov di, RELATIONAL_EXPRESSION.end
            mov si, ADDITIVE_EXPRESSION1.end
            RotInicio := NovoRot
            RotFim := NovoRot
            RotInicio:
                mov al, ds:[di] ; al = str1[i]
                mov ah, 0
                mov bx, '$'
                cmp ax, bx
                je RotFim ; sai do for caso str1[i] != '$'

                mov al, ds:[di] ; al = str1[i]
                mov ah, 0
                mov bl, ds:[si] ; bl = str2[i]
                mov bh, 0
                cmp ax, bx
                jne RotFim ; break
                inc di
                inc si
                jmp RotInicio
            
            RotFim:
            mov al, ds:[di] ; al = str1[i]
            mov ah, 0
            mov bl, ds:[si] ; bl = str2[i]
            mov bh, 0
            cmp ax, bx

            RotVerdadeiro := NovoRot
            je RotVerdadeiro
            mov al, 00h
            RotFim2 := NovoRot
            jmp RotFim2

            RotVerdadeiro:
                mov al, 01h

            RotFim2:
                RELATIONAL_EXPRESSION.end = NovoTemp()
                mov ds:[RELATIONAL_EXPRESSION.end], al
        }
    }
    senao se operador = '<>' entao {
        se RELATIONAL_EXPRESSION.tipo != ADDITIVE_EXPRESSION1.tipo entao ERRO
        se RELATIONAL_EXPRESSION.tipo = inteiro entao {
            mov ax, ds:[RELATIONAL_EXPRESSION.end]
            mov bx, ds:[ADDITIVE_EXPRESSION1.end]
            cmp ax, bx

            RotVerdadeiro := NovoRot
            je RotVerdadeiro
            mov al, 01h
            RotFim := NovoRot
            jmp RotFim

            RotVerdadeiro:
                mov al, 00h

            RotFim:
                RELATIONAL_EXPRESSION.end = NovoTemp()
                mov ds:[RELATIONAL_EXPRESSION.end], al
        }
        senao se RELATIONAL_EXPRESSION.tipo = caractere entao {
            mov al, ds:[RELATIONAL_EXPRESSION.end]
            mov bl, ds:[ADDITIVE_EXPRESSION1.end]
            mov ah, 0
            mov bh, 0
            cmp ax, bx

            RotVerdadeiro := NovoRot
            je RotVerdadeiro
            mov al, 01h
            RotFim := NovoRot
            jmp RotFim

            RotVerdadeiro:
                mov al, 00h

            RotFim:
                RELATIONAL_EXPRESSION.end = NovoTemp()
                mov ds:[RELATIONAL_EXPRESSION.end], al
        }
        senao se RELATIONAL_EXPRESSION.tipo = booleano entao {
            mov al, ds:[RELATIONAL_EXPRESSION.end]
            mov bl, ds:[ADDITIVE_EXPRESSION1.end]
            mov ah, 0
            mov bh, 0
            cmp ax, bx

            RotVerdadeiro := NovoRot
            je RotVerdadeiro
            mov al, 01h
            RotFim := NovoRot
            jmp RotFim

            RotVerdadeiro:
                mov al, 00h

            RotFim:
                RELATIONAL_EXPRESSION.end = NovoTemp()
                mov ds:[RELATIONAL_EXPRESSION.end], al
        }
    }
    senao se operador = '<' entao {
        se RELATIONAL_EXPRESSION.tipo != inteiro ou ADDITIVE_EXPRESSION1.tipo != inteiro entao ERRO
        mov ax, ds:[RELATIONAL_EXPRESSION.end]
        mov bx, ds:[ADDITIVE_EXPRESSION1.end]
        cmp ax, bx

        RotVerdadeiro := NovoRot
        jl RotVerdadeiro
        mov al, 00h
        RotFim := NovoRot
        jmp RotFim

        RotVerdadeiro:
            mov al, 01h

        RotFim:
            RELATIONAL_EXPRESSION.end = NovoTemp()
            mov ds:[RELATIONAL_EXPRESSION.end], al
    }
    senao se operador = '<=' entao {
        se RELATIONAL_EXPRESSION.tipo != inteiro ou ADDITIVE_EXPRESSION1.tipo != inteiro entao ERRO
        mov ax, ds:[RELATIONAL_EXPRESSION.end]
        mov bx, ds:[ADDITIVE_EXPRESSION1.end]
        cmp ax, bx

        RotVerdadeiro := NovoRot
        jle RotVerdadeiro
        mov al, 00h
        RotFim := NovoRot
        jmp RotFim

        RotVerdadeiro:
            mov al, 01h

        RotFim:
            RELATIONAL_EXPRESSION.end = NovoTemp()
            mov ds:[RELATIONAL_EXPRESSION.end], al
    }
    senao se operador = '>' entao {
        se RELATIONAL_EXPRESSION.tipo != inteiro ou ADDITIVE_EXPRESSION1.tipo != inteiro entao ERRO
        mov ax, ds:[RELATIONAL_EXPRESSION.end]
        mov bx, ds:[ADDITIVE_EXPRESSION1.end]
        cmp ax, bx

        RotVerdadeiro := NovoRot
        jg RotVerdadeiro
        mov al, 00h
        RotFim := NovoRot
        jmp RotFim

        RotVerdadeiro:
            mov al, 01h

        RotFim:
            RELATIONAL_EXPRESSION.end = NovoTemp()
            mov ds:[RELATIONAL_EXPRESSION.end], al
    }
    senao se operador = '>=' entao {
        se RELATIONAL_EXPRESSION.tipo != inteiro ou ADDITIVE_EXPRESSION1.tipo != inteiro entao ERRO
        mov ax, ds:[RELATIONAL_EXPRESSION.end]
        mov bx, ds:[ADDITIVE_EXPRESSION1.end]
        cmp ax, bx

        RotVerdadeiro := NovoRot
        jge RotVerdadeiro
        mov al, 00h
        RotFim := NovoRot
        jmp RotFim

        RotVerdadeiro:
            mov al, 01h

        RotFim:
            RELATIONAL_EXPRESSION.end = NovoTemp()
            mov ds:[RELATIONAL_EXPRESSION.end], al
    }
    RELATIONAL_EXPRESSION.tipo = booleano
}

ADDITIVE_EXPRESSION -> MULTIPLICATIVE_EXPRESSION {1} {('+' | '-' | 'or') {2} MULTIPLICATIVE_EXPRESSION1 {3}}*
{1} {
    ADDITIVE_EXPRESSION.tipo = MULTIPLICATIVE_EXPRESSION.tipo
    ADDITIVE_EXPRESSION.end = MULTIPLICATIVE_EXPRESSION.end
    ADDITIVE_EXPRESSION.tamanho = MULTIPLICATIVE_EXPRESSION.tamanho
}
{2} {
    operador = guardar o operador ('+' | '-' | 'or') numa variavel
}
{3} {
    se ADDITIVE_EXPRESSION.tamanho > 0 entao ERRO
    se MULTIPLICATIVE_EXPRESSION1.tamanho > 0 entao ERRO
    se operador = '+' entao {
        se ADDITIVE_EXPRESSION.tipo != inteiro ou MULTIPLICATIVE_EXPRESSION1.tipo != inteiro entao ERRO
        mov ax, ds:[ADDITIVE_EXPRESSION.end]
        mov bx, ds:[MULTIPLICATIVE_EXPRESSION1.end]
        add ax, bx
        ADDITIVE_EXPRESSION.end = NovoTemp()
        mov ds:[ADDITIVE_EXPRESSION.end], ax
    }
    senao se operador = '-' entao {
        se ADDITIVE_EXPRESSION.tipo != inteiro ou MULTIPLICATIVE_EXPRESSION1.tipo != inteiro entao ERRO
        mov ax, ds:[ADDITIVE_EXPRESSION.end]
        mov bx, ds:[MULTIPLICATIVE_EXPRESSION1.end]
        sub ax, bx
        ADDITIVE_EXPRESSION.end = NovoTemp()
        mov ds:[ADDITIVE_EXPRESSION.end], ax
    }
    senao se operador = 'or' entao {
        se ADDITIVE_EXPRESSION.tipo != booleano ou MULTIPLICATIVE_EXPRESSION1.tipo != booleano entao ERRO
        mov al, ds:[ADDITIVE_EXPRESSION.end]
        or al, ds:[MULTIPLICATIVE_EXPRESSION1.end]
        MULTIPLICATIVE_EXPRESSION.end = NovoTemp()
        mov ds:[MULTIPLICATIVE_EXPRESSION.end], al
    }
}

MULTIPLICATIVE_EXPRESSION -> UNARY_EXPRESSION {1} {('*' | '/' | '%' | 'and') {2} UNARY_EXPRESSION1 {3}}*
{1} {
    MULTIPLICATIVE_EXPRESSION.tipo = UNARY_EXPRESSION.tipo
    MULTIPLICATIVE_EXPRESSION.end = UNARY_EXPRESSION.end
    MULTIPLICATIVE_EXPRESSION.tamanho = UNARY_EXPRESSION.tamanho
}
{2} {
    operador = guardar o operador ('*' | '/' | '%' | 'and') numa variavel
}
{3} {
    se MULTIPLICATIVE_EXPRESSION.tamanho > 0 entao ERRO
    se UNARY_EXPRESSION1.tamanho > 0 entao ERRO
    se operador = '*' entao {
        se MULTIPLICATIVE_EXPRESSION.tipo != inteiro ou UNARY_EXPRESSION1.tipo != inteiro entao ERRO
        mov ax, ds:[MULTIPLICATIVE_EXPRESSION.end]
        cwd
        mov bx, ds:[UNARY_EXPRESSION1.end]
        imul bx
        MULTIPLICATIVE_EXPRESSION.end = NovoTemp()
        mov ds:[MULTIPLICATIVE_EXPRESSION.end], ax
    }
    senao se operador = '/' entao {
        se MULTIPLICATIVE_EXPRESSION.tipo != inteiro ou UNARY_EXPRESSION1.tipo != inteiro entao ERRO
        mov ax, ds:[MULTIPLICATIVE_EXPRESSION.end]
        cwd
        mov bx, ds:[UNARY_EXPRESSION1.end]
        idiv bx
        MULTIPLICATIVE_EXPRESSION.end = NovoTemp()
        mov ds:[MULTIPLICATIVE_EXPRESSION.end], ax
    }
    senao se operador = '%' entao {
        se MULTIPLICATIVE_EXPRESSION.tipo != inteiro ou UNARY_EXPRESSION1.tipo != inteiro entao ERRO
        mov ax, ds:[MULTIPLICATIVE_EXPRESSION.end]
        cwd
        mov bx, ds:[UNARY_EXPRESSION1.end]
        idiv bx
        MULTIPLICATIVE_EXPRESSION.end = NovoTemp()
        mov ds:[MULTIPLICATIVE_EXPRESSION.end], dx
    }
    senao se operador = 'and' entao {
        se MULTIPLICATIVE_EXPRESSION.tipo != booleano ou UNARY_EXPRESSION1.tipo != booleano entao ERRO
        mov al, ds:[MULTIPLICATIVE_EXPRESSION.end]
        and al, ds:[UNARY_EXPRESSION1.end]
        MULTIPLICATIVE_EXPRESSION.end = NovoTemp()
        mov ds:[MULTIPLICATIVE_EXPRESSION.end], al
    }
}

UNARY_EXPRESSION -> 'not' UNARY_EXPRESSION1 {1}
{1} {
    se UNARY_EXPRESSION1.tipo != booleano entao ERRO
    se UNARY_EXPRESSION1.tamanho > 0 entao ERRO
    UNARY_EXPRESSION.tipo = UNARY_EXPRESSION1.tipo
    UNARY_EXPRESSION.end = NovoTemp()
    UNARY_EXPRESSION.tamanho = UNARY_EXPRESSION1.tamanho
    mov ax, ds:[UNARY_EXPRESSION1.end]
    neg ax
    add ax, 1
    mov ds:[UNARY_EXPRESSION.end], al
}

UNARY_EXPRESSION -> '+' UNARY_EXPRESSION1 {1}
{1} {
    se UNARY_EXPRESSION1.tipo != inteiro entao ERRO
    se UNARY_EXPRESSION1.tamanho > 0 entao ERRO
    UNARY_EXPRESSION.tipo = UNARY_EXPRESSION1.tipo
    UNARY_EXPRESSION.end = UNARY_EXPRESSION1.end
    UNARY_EXPRESSION.tamanho = UNARY_EXPRESSION1.tamanho
}

UNARY_EXPRESSION -> '-' UNARY_EXPRESSION1 {1}
{1} {
    se UNARY_EXPRESSION1.tipo != inteiro entao ERRO
    se UNARY_EXPRESSION1.tamanho > 0 entao ERRO
    UNARY_EXPRESSION.tipo = UNARY_EXPRESSION1.tipo
    UNARY_EXPRESSION.end = NovoTemp()
    UNARY_EXPRESSION.tamanho = UNARY_EXPRESSION1.tamanho
    mov ax, ds:[UNARY_EXPRESSION1.end]
    neg ax
    mov ds:[UNARY_EXPRESSION.end], ax
}

UNARY_EXPRESSION -> PRIMARY_EXPRESSION {1}
{1} {
    UNARY_EXPRESSION.tipo = PRIMARY_EXPRESSION.tipo
    UNARY_EXPRESSION.end = PRIMARY_EXPRESSION.end
    UNARY_EXPRESSION.tamanho = PRIMARY_EXPRESSION.tamanho
}

PRIMARY_EXPRESSION -> CONST {1}
{1} {
    PRIMARY_EXPRESSION.tipo = CONST.tipo
    PRIMARY_EXPRESSION.end = NovoTemp()
    PRIMARY_EXPRESSION.tamanho = 0
    mov ax, CONST.lex
    mov DS:[PRIMARY_EXPRESSION.end], ax
}

PRIMARY_EXPRESSION -> '(' EXPRESSION {1} ')'
{1} {
    PRIMARY_EXPRESSION.tipo = EXPRESSION.tipo
    PRIMARY_EXPRESSION.end = EXPRESSION.end
    PRIMARY_EXPRESSION.tamanho = IDENTIFIER.tamanho
}

PRIMARY_EXPRESSION -> IDENTIFIER {1} ( '[' {2} EXPRESSION {3} ']' | lambda {4} )
{1} {
    se tabela.get(IDENTIFIER.lex) = null entao ERRO
    PRIMARY_EXPRESSION.tipo = IDENTIFIER.tipo
    PRIMARY_EXPRESSION.end = IDENTIFIER.end
}
{2} {
    se tabela.get(IDENTIFIER.lex).tamanho = 0 entao ERRO
    PRIMARY_EXPRESSION.tamanho = 0
}
{3} {
    se EXPRESSION.tipo != inteiro ou EXPRESSION.tamanho > 0 entao ERRO
    PRIMARY_EXPRESSION.end = NovoTemp()
    mov bx, ds:[EXPRESSION.end]
    se PRIMARY_EXPRESSION.tipo = inteiro entao {
        add bx, bx
    }
    add bx, IDENTIFIER.end
    mov bx, ds:[bx]
    mov ds:[PRIMARY_EXPRESSION.end], bx
}
{4} {
    PRIMARY_EXPRESSION.tamanho = IDENTIFIER.tamanho
}

References

About

This is a compiler for the L language, an artifical language of the Compilers discipline. Our generated assembly is compatible with the 8086 processor with registers of 16 bits.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published