Prévia do material em texto
Resumo A1 1
Resumo A1
Rafa
⚠ 2 aula de autômatos
3 tem no trabalho que ele passou
4 produto dele é tabela de token e entrada é um texto
5 mesma coisa do scanner e como identificar
6 entrada do parser é a tabela de token e a saída é a árvore
7 código intermediário
8 sem dicas
9 ver os Scripts do material do mips
10 verificar a saída do syscalls, só as básicas Double, inteiro, float e etc ⟶ são os números
11
12 como funciona o mips
Dissertiva em assembly
Vai ter tabela ascii
Vão ser 2 pontos para 8 alternativas e 3 pontos as discursivas
Eu
⚠ Aula 5
Automatos Simbolos Quintupla - Ultima aula)
JFlex JCup -
O que é Scanner -
Como é feita a sintaxe do código
Qual a entrada do scanner?
Dissertativa Assembly
Tipos de arquivo? qual a extensão dele?
Analisador sintatico
Assembly →
Baixar o Mars →
Saídas básicas do Syscall?
´MIPS e como ele funciona? JKD MV
Código feito em Assembly
TABELA ASCII
Fazer um código pequeno
Estudar a prova antiga
Modelo da prova
2pontos 8questões X
3pontos Discursiva
Erick
Resumo A1 2
⚠ Aula 2
Conteúdo do slide:
Fases da transformação:
Análise léxica
Análise sintática
Análise semântica (junta a árvore e análise sintática)
Tradução de código de máquina em assembly
Definição de compilador
Dica:
Não cai prolog
Foque nas imagens do slide.
Aula 3
Conteúdo do slide:
JFlex:
Organização dos arquivos e extensões
Como rodar os arquivos
Trabalho solicitado pelo professor
Aula 4
Conteúdo do slide:
Gramática linguística:
O que é análise léxica
Tabela de tokens (léxico) — importante para a prova
Código de scanner e declarações
Estrutura do código JFlex
Análise sintática:
Símbolo sentença
Tabela de análise sintática
Dicas:
Lexema não cai.
Algumas respostas estão nos slides de análise sintática.
Aula 5
Conteúdo do slide:
Códigos MIPS
Tabela ASCII (vai cair na prova)
Instruções do assembly no MIPS
Aula 6
Conteúdo do slide:
Instalação do JCup
Parser Cup
Aula 7
Conteúdo do slide:
Autômato finito:
Máquinas de estados
Resumo A1 3
Determinístico e não determinístico
A quíntupla (único conteúdo que cai na prova)
Aula 8
Conteúdo do slide:
Gramática de expressões:
Exercício de redução
1 O que é Análise Léxica, Análise Sintática e Análise Semântica?
Análise Léxica
É conhecido como Scanner.
Utiliza expressões regulares no conhecimento de caracteres.
As tarefas que ele pode desempenhar são:
Contar linhas de um programa;
Eliminar comentários;
Contar a quantidade de caracteres de um arquivo fonte;
Tratar os espaços.
A analise léxica : é onde o texto é quebrado em lexemas
Lexema, no sentido geral, é unidade lexical de duas faces (forma e conteúdo), ou sinal mínimo de
natureza não gramatical.
Definições importantes:
Padrão: é a forma que os lexemas de uma cadeia de caracteres podem assumir. No caso de palavras
reservadas é a sequencia de caracteres que formam a palavra reservada. Já no caso dos
identificadores são os caracteres que formam os nomes das variáveis e funções.
Token: é um par constituído de um nome e um valor de atributo, esse ultimo opcional. O nome de um
token é um símbolo que representa a unidade léxica. Por exemplo: palavras reservadas,
identificadores, números, etc.
Lexema: é uma sequencia de caracteres reconhecida por um padrão.
Análise Sintática
O Analisador sintático também conhecido como parser tem como tarefa principal determinar se o
programa de entrada representado pelo fluxo de tokens possui as sentenças válidas para a linguagem de
programação.
A analise sintática e a segunda etapa do processo de compilação e na maioria dos casos utiliza
gramáticas livres de contexto para especificar a sintaxe de uma linguagem de programação.
O analisador sintático agrupa os tokens em frases gramaticais usadas pelo compilador com o objetivo de
criar uma saída que representa a estrutura hierarquia do programa fonte.
Resumo A1 4
Análise Semântica
A Análise Semântica verifica o significado dos tokens e estruturas analisados, certificando-se de que
eles façam sentido no contexto da linguagem.
Objetivo Detectar erros relacionados ao significado lógico e ao uso correto dos elementos no programa
ou texto.
Funcionamento Durante esta fase, o programa analisa o uso de variáveis, tipos de dados e outros
elementos. Também pode incluir verificações como:
Tipos de dados compatíveis em operações ( int + string não é válido).
Uso de variáveis previamente declaradas.
Erro comum Atribuir valores de tipo errado ( int x = "texto"; ).
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
Análise Léxica Identifica tokens como int , x , = , 10 , if , etc.
Análise Sintática Confirma que a estrutura segue a gramática da linguagem (exemplo: if seguido por uma
condição válida).
Análise Semântica Verifica se x foi declarado antes de ser usado e se o tipo de dados está correto para as
operações.
2 O que é Símbolo, Sentença, Alfabeto, Linguagem e Gramática?
Símbolo: são os elementos mínimos que compõe uma linguagem. Na linguagem humana são as letras.
Pode ser uma letra, número, caractere especial, ou qualquer representação abstrata.
Exemplos: a , b , 1 , + , @ .
Sentença É um conjunto ordenado de símbolos que forma uma cadeia ou string. Na linguagem humana são
as palavras.
Na linguagem natural: “A casa é azul.ˮ
Na linguagem de programação: if (x > 0) { y = y + 1; }
Na linguagem formal: A sequência abba é uma sentença da linguagem definida pelo alfabeto {a, b} com a
regra de formar palíndromos.
Alfabeto É um conjunto de símbolos. Na linguagem humana é o conjunto de letras {a, b, c, d, ...}
Representado por Σ sigma).
Exemplo: Σa,b,c} → um alfabeto com três símbolos.
Observação: O alfabeto não inclui regras de construção, apenas os símbolos disponíveis.
Linguagem É o conjunto de sentenças, Na linguagem humana são os conjuntos de palavras {compiladores,
linguagem, ...}
Representada por L.
Exemplo: L={anbn∣n1 a linguagem de sentenças com o mesmo número de a s e b s consecutivos,
como ab , aabb , aaabbb .
Pode ser finita ou infinita.
Gramática É uma forma de representar as regras para formação de uma linguagem.
Representada por G, com quatro componentes: G=(N,T,P,S), onde:
NN Conjunto de símbolos não terminais (variáveis).
TT Conjunto de símbolos terminais (alfabeto).
PP Conjunto de produções (regras de substituição).
SS Símbolo inicial (início da derivação).
Resumo A1 5
Exemplo: Gramática para expressões aritméticas simples:
NEN={E}, T={+,∗,a,b}
PEEE∣E∗E∣a∣b}P={E→E+E∣E∗E∣a∣b}
SES=E.
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
Relação entre os conceitos:
� Símbolos pertencem a um alfabeto.
� A gramática define como combinar os símbolos para formar sentenças.
� O conjunto de todas as sentenças válidas forma a linguagem.
3 O que é um Scanner? E como identifico um código de Scanner?
Um Scanner é um componente essencial na análise léxica, utilizado para processar uma entrada (como um texto
ou código-fonte) e dividi-la em unidades menores chamadas tokens.
Função Ler e interpretar a entrada caractere por caractere, agrupando-os em tokens significativos, como
palavras-chave, operadores, números, identificadores, etc.
Uso É frequentemente implementado em compiladores, interpretadores e sistemas de análise de texto.
Exemplo de funcionamento em linguagem de programação:
Entrada: int x = 10;
Tokens gerados: int , x , = , 10 , ; .
Um código de Scanner pode ser identificado pelos seguintes aspectos:
� Estrutura Ele analisa um fluxo de caracteres ou texto, transformando-o em tokens.
� Linguagens de Programação:
Em Java, por exemplo, há uma classe chamada Scanner que realiza operações de entrada de dados.
No contexto de análise léxica, ferramentas como flex (no Unix) podem gerar scanners baseados em
expressões regulares.
4 Qual é a entrada e qual é o produto do Scanner?
Entrada do Scanner
Entrada O texto ou código-fonte a seranalisado.
Pode ser uma string, um arquivo, ou um fluxo de entrada.
Exemplos:
Código-fonte em C int a = 5; .
Texto natural: "Olá, mundo!".
Produto do Scanner
Saída Um conjunto de tokens, onde cada token representa uma unidade significativa do texto de entrada.
Tokens podem ser categorizados, por exemplo:
Palavras-chave ( int , if , return ).
Identificadores ( variavel , x ).
Literais ( 10 , "texto" ).
Operadores ( + , = ).
Delimitadores ( ; , { , } ).
Resumo:
O Scanner processa a entrada caractere por caractere e agrupa elementos em tokens.
Entrada Fluxo de caracteres (texto ou código-fonte).
Saída Lista de tokens para processamento posterior (como análise sintática).
5 O que é um Parser? Como eu identifico o código de um Parser?
Resumo A1 6
Um Parser (ou analisador sintático) é a segunda etapa em um processo de compilação ou interpretação de
linguagens. Ele analisa os tokens gerados pelo Scanner (analisador léxico) e verifica se eles seguem as regras de
sintaxe de uma linguagem formal, geralmente definidas por uma gramática formal.
Função Construir uma estrutura hierárquica (como uma árvore sintática) que representa a organização dos
tokens de acordo com a gramática.
Objetivo Garantir que a entrada seja válida em termos de sintaxe e estruturar os dados para etapas
posteriores, como a análise semântica ou geração de código.
Exemplo:
Tokens: int , x , = , 10 , ; .
Verifica que eles formam uma declaração válida de variável: int x = 10; .
Constrói uma árvore sintática para representar essa declaração.
Estrutura de um Parser
� Entrada O código trabalha com tokens produzidos por um scanner.
� Uso de Gramáticas O Parser utiliza uma gramática formal (como BNF ou EBNF para definir as regras da
linguagem.
� Algoritmos comuns:
Parsers descendentes (top-down Exemplo, Recursive Descent Parser.
Parsers ascendentes (bottom-up Exemplo, Shift-Reduce Parser.
Características no código
Implementação de funções ou estados que correspondem às regras da gramática.
Pode incluir estruturas para construir árvores sintáticas ou derivar sentenças válidas.
6 Qual é a entrada e qual é o produto do Parser?
Entrada do Parser
Entrada Uma sequência de tokens gerados pelo Scanner.
Exemplos:
Tokens de uma expressão: num , + , num .
Tokens de uma instrução: int , x , = , 10 , ; .
Produto do Parser
Saída Uma representação estruturada da entrada, geralmente em forma de:
� Árvore Sintática (Parse Tree Representa todas as derivações da gramática.
� Árvore Sintática Abstrata AST Uma versão simplificada da árvore sintática, focando nos elementos
mais relevantes.
Resumo:
Entrada do Parser Tokens (sequência léxica).
Saída do Parser Estrutura hierárquica que organiza os tokens de acordo com a gramática.
7 O que é um código intermediário? E como identifico o identifico?
O código intermediário é uma representação abstrata ou simplificada de um programa que serve como etapa
intermediária entre a análise sintática e a geração do código final (código de máquina ou bytecode). Ele é usado
em compiladores para tornar o processo de tradução mais modular, permitindo otimizações antes da geração do
código de destino.
Você pode identificar o código intermediário observando:
� Forma compacta e genérica Ele usa operações básicas como atribuições, somas e chamadas de função,
sem detalhes específicos da máquina.
Exemplo: Em vez de instruções específicas para registradores ou memória, temos algo como:
makefile
Copiar código
Resumo A1 7
t1 = a + b
t2 = t1 * c
result = t2
� Uso de variáveis temporárias O código intermediário frequentemente introduz variáveis temporárias para
armazenar resultados intermediários.
� Contexto de geração Geralmente é gerado após a análise sintática e semântica e antes da geração de
código final.
8 Quais são as entradas do Jflex e do Jcup? E quais são os tipos de arquivos?
JFlex
O JFlex é uma ferramenta para geração de analisadores léxicos Scanners) a partir de uma especificação de
expressões regulares e ações associadas.
Entrada:
Um arquivo de especificação contendo:
Definições de expressões regulares Define os padrões para identificar tokens.
Regras de ação Especifica o que fazer quando um padrão é encontrado (por exemplo, retornar tokens).
Estrutura geral Configurações e declarações da linguagem.
Formato do arquivo de entrada:
Extensão: .flex ou .jflex
Exemplo de um arquivo .flex :
jflex
Copiar código
%%
%class Lexer
%unicode
%cup
%%
[0-9]+ { return new Symbol(sym.NUM, Integer.parseInt(yytext())); }
Resumo A1 8
[a-zA-Z]+ { return new Symbol(sym.ID, yytext()); }
Neste exemplo:
Tokens como números ( [0-9]+ ) e identificadores ( [a-zA-Z]+ ) são definidos.
Ações associadas retornam tokens para o parser.
Saída:
Um arquivo Java gerado, com o código do analisador léxico.
Extensão da saída: .java
Por padrão, o arquivo terá o nome especificado com %class (no exemplo, Lexer.java ).
JCup
O JCup é uma ferramenta para geração de analisadores sintáticos Parsers) a partir de uma gramática formal,
similar ao Yacc.
Entrada:
Um arquivo de especificação contendo:
Definições de símbolos Terminais (tokens) e não terminais.
Produções Regras gramaticais definindo como os símbolos são combinados.
Ações Código associado às regras, geralmente para construir estruturas como árvores sintáticas.
Formato do arquivo de entrada:
Extensão: .cup
Exemplo de um arquivo .cup :
cup
Copiar código
import java_cup.runtime.*;
parser code {
public static void main(String[] args) throws Exception {
Lexer lexer = new Lexer(System.in);
parser p = new parser(lexer);
p.parse();
}
}
terminal String ID, NUM;
non terminal Expr;
Expr ::= Expr '+' Expr {: RESULT = RESULT1 + RESULT3; :}
| NUM {: RESULT = Integer.parseInt(RESULT1.toString()); :}
;
Saída:
Dois arquivos Java gerados:
� parser.java Contém o código do parser gerado.
� sym.java Contém as definições dos símbolos terminais (tokens).
Resumo A1 9
9 Como faz um For, um Loop ou uma Condição lógica em Assembly?
Loop
#loop laço de repetição
li $v0, 1
addi $t0, $zero, 0
addi $sp, $sp, -13
addi $t0, $zero, 44
sb $t0, 0($sp)
addi $t0, $zero, 10
sb $t0, 1($sp)
loop: move $a0, $t1
syscall
addi $v0, $zero, 4
addi $a0, $sp, 0
syscall
addi $v0, $zero, 1
addi $t1, $t1, 1
blt $t1, 10, loop
addi $t1, $zero, 0
For ????
Condição Lógica
#Multiplicação
li $v0, 1
addi $t2, $zero, 12
addi $t5, $zero, 4
mul $a0, $t2, $t5
syscall
----------------------------------
#subtração de dois valores
li $v0, 2
li $t1, 67
li $t2, 42
div $f12, $t2, $t1
syscall
----------------------------------
#Soma de dois números
li $v0,1
addi $t1, $zero , -10
addi $t2, $zero, -6
addi $t3, $zero, 23
add $t4, $t1, $t2
add $t5, $t4, $t3
Resumo A1 10
add $a0, $zero, $t5
syscall
----------------------------------
#divisão de dois números
li $v0, 1
ADDI $a1, $zero, 1024
ADDI $a2, $zero, 128
DIV $a0, $a1, $a2
syscall
----------------------------------
10 Quais são as saídas do Syscall?
Código
em $v0 Serviço Entradas Saídas
1 Imprimir inteiro $a0 = inteiro a ser impresso Nenhuma (inteiro é exibido na tela).
2 Imprimir float $f12 = float a ser impresso Nenhuma (float é exibido na tela).
3 Imprimir double $f12 = double a ser impresso Nenhuma (double é exibido na tela).
4 Imprimir string $a0 = endereço da string Nenhuma (string é exibida na tela).
5 Ler inteiro Nenhuma Saída: inteiro lido armazenado em $v0 .
6 Ler float Nenhuma Saída: float lido armazenado em $f0 .
7 Ler double Nenhuma Saída: double lido armazenado em $f0 .
8 Ler string $a0 = endereço do buffer , $a1 =
tamanho max
String lida armazenada no buffer.
9 Alocar memória $a0 = número de bytes
Saída: endereço do bloco de memória
alocado em $v0 .
10 Encerrar
programa
Nenhuma Nenhuma (programa termina).
11 Imprimir
caractere
$a0 = caractere aser impresso Nenhuma (caractere exibido na tela).
12 Ler caractere Nenhuma Saída: caractere lido armazenado em $v0 .
11 Em compiladores, onde é a JVM é solicitada para a criação de um compilador?
A JVM é solicitada durante a geração de bytecode no processo de compilação. O compilador gera código
intermediário em formato de bytecode, que é compatível com a JVM. Este bytecode é armazenado em
arquivos .class , que podem ser executados pela JVM.
Em resumo, a JVM é usada quando o compilador precisa gerar e executar bytecode para garantir que o código
esteja em conformidade com a plataforma Java.
12 Qual montador de código de máquina usamos? E como ele funciona?
O montador (assembler) converte código Assembly em código de máquina executável. Ele traduz instruções
simbólicas (como MOV , ADD ) para o formato binário que a CPU pode executar.
Montadores Comuns:
GAS GNU Assembler) Usado em sistemas Unix/Linux.
NASM Usado principalmente em sistemas x86.
MASM Usado em sistemas Windows x86.
FASM Montador rápido para sistemas x86 e x64.
Funcionamento:
� O montador lê o código em Assembly.
� Converte as instruções Assembly em código binário.
� Resolve endereços de variáveis e gera o arquivo de código de máquina (geralmente .obj ou .o ).
Resumo A1 11
� A saída é um arquivo binário que pode ser executado pela CPU.
Resumidamente, o montador traduz código Assembly em código de máquina, criando arquivos executáveis ou
objetos.