Sintax Graph Designer
Manual do Usuário
Versão 3.0 referente à versão 1.0 do SGD
Sumário
1. Introdução:
1.1 O SGD.
1.2 Finalização.
1.3 Definições.
2. Modo de Uso:
2.1 Utilização da barra de ferramentas.
2.2 Criação de nós.
2.3 Alteração das propriedades dos nós.
2.4 Ligação dos nós.
2.5 Utilização do menu.
2.6 Práticas de bom uso.
3. Funcionamento:
3.1 Estrutura Geral.
3.2 Definição de um nó: A Classe CCell.
3.3 Ligações de um nó: A Classe Arrow.
3.4 Funções.
3.5 Mensagens do Windows.
4. Alteração do Programa:
4.1 Estado Atual do SGD.
4.2 Comentários.
4.3 Alteração das Funções.
4.4 Criação de funções pelo usuário.
4.5 Observações.
5. Glossário
6. Bibliografia
1. Introdução
1.1 O SGD
O Sintax Graph Designer (SGD) é um sistema gráfico que permite
ao usuário desenhar grafos sintáticos do tipo ESLL(1) [Setzer 1] para o sistema
operacional Windows. Ele pode gerar um arquivo de saída contendo a declaração
de um grafo sintático em C++ em forma de um vetor, para uso de um analisador
sintático do tipo ESLL(1), conforme definido por Setzer em [Setzer 198x, 19xx];
no primeiro há uma definição informal, e no segundo uma definição formal tanto
dos grafos como do algoritmo de análise sintática e das estratégias de correção
de erros sintáticos. As gramaticas do tipo ESLL(1) são uma classe das gramáticas
LL(1) [Aho 1] com lados direitos das produções podendo conter expressões regulares,
isto é, com alternativas fatoradas, fechamentos transitivos, e símbolos opcionais
[Setzer 2].
O SGD foi criado para ser um programa Open Source, isto é, para
que fosse publicado na internet e qualquer programador pudesse-o utilizar
e alterar conforme suas necessidades.
Usaremos as seguintes notações. Acionar o mouse significa pressionar
o seu botão esquerdo. Acionar o mouse na posicão x significa colocar o cursor
do mouse na posição x e depois acioná-lo. Doubleclick é o ato de se acionar
duas vezes rapidamente o botão esquerdo do mouse. Mover o mouse significa
mover o cursor do mouse por meio de movimentos deste. Arrastar o mouse da
posição x até a posição y significa acionar o mouse na posição x e sem soltar
o botão do mouse, mover o mouse até a posição y, e só então soltar o botão
do mouse. Selecionar um nó significa acionar o botão do mouse no local onde
se encontra o nó desejado e o mesmo se aplica para selecionar uma seta. Uma
área de seleção é uma área dentro da área de trabalho na qual todos os nós
serão selecionados. Para traçar uma área de seleção, basta acionar o mouse
numa posição sem elementos da área de trabalho e arrastar o mouse até outro
ponto. Durante o arrasto será mostrado um retângulo tracejado, e a área dentro
deste retângulo é a área de seleção. Quando o botão do mouse for solto, o
retângulo delimitando a área de seleção desaparecerá e todos os nós que estavam
dentro da área de seleção nesta hora estarão selecionados.
1.2 Finalização
O programa está com as funcionalidades básicas implementadas,
permitindo o desenho confortável de grafos e a criação do arquivo necessário
para o analisador sintático com relativa facilidade. As funcionalidades implementadas
estão descritas abaixo.
1.3 Definições
Grafo sintático é um grafo orientado desconexo que representa
graficamente uma gramática; cada produção da gramática é representada por
um subgrafo, sem arestas ligando-o com outros subgrafos. Assim, um grafo sintático,
como qualquer gramática, define uma linguagem formal.
Nó é uma representação de um símbolo de uma produção da gramática.
A seqüência dos símbolos das produções é representada por arestas do grafo.
Como o grafo é orientado, denominaremos as arestas de setas, para facilidade
de compreensão e melhor aderência à simbologia gráfica. Cada nó pode ser do
tipo Cabeça, Terminal, Não-Terminal e nó Vazio. Os nós do tipo Cabeça são
a definição de um símbolo Não-Terminal e são os que começam os subgrafos que
compõem cada grafo. São representados graficamente por um hexágono. Os nós
Não-Terminais representam o uso de um símbolo não terminal, são nós Cabeça
quando se encontram dentro de outro subgrafo, eles representam os subgrafos
que já foram ou serão definidos. São representados graficamente por um retângulo.
Os nós Terminais representam nós contendo um símbolo terminal da gramática,
com as devidas informações sobre seu conteúdo. São representados graficamente
por um retângulo com cantos arredondados. E por último, os nós "Vazios" que
são nós terminais especiais com uma cadeia vazia. São representados graficamente
por um círculo. Todas essas informações devem ser disponibilizadas graficamente.
Cada nó deve armazenar o nome do símbolo gramatical que representa, o tipo
de nó, seu sucessor e sua alternativa e o nome da rotina semântica associada
ao nó.
Uma seta liga um nó origem a um nó destino para onde ela aponta.
Uma seta pode ser de dois tipos: seta sucessora e seta alternativa. A seta
sucessora de um nó n aponta para o nó com o símbolo da produção que se segue
a n, e sempre sai pelo lado direito de n. A seta alternativa de n aponta para
o nó cujo símbolo deve ser o primeiro símbolo alternativo para o atual na
produção, e sempre sai pelo lado inferior do nó origem. Note-se que, por terem
lados direitos com expressões regulares, símbolos alternativos podem ocorrer
em qualquer ponto de um lado direito. As setas sucessoras são diferenciadas
graficamente das setas alternativas por sua grossura, sendo a seta alternativa
mais grossa que a sucessora. As setas são compostas por segmentos de reta,
que são retas finitas delimitadas por pontos, e uma ponta, denotada graficamente
por um "V" no final do último segmento de reta da seta.
Após mover um nó que aponta ou é apontado por alguém, as setas
serão simplificadas automaticamente mas isso pode acarretar setas com mau
comportamento, isto é, passando por dentro de nós ou escondendo-se atrás de
outras setas. Deve-se procurar corrigir. Veja. como na seção [2.4 Ligação
entre dois nós].
A posição de um elemento gráfico pode ser definida pelo local
onde ele se encontra dentro da área de trabalho. Cada nó possui uma posição
calculada com base num ponto que fica um pouco à esquerda do seu centro. A
área de trabalho possui uma grade invisível que serve para facilitar o posicionamento
dos nós na tela de modo a deixá-los alinhados uns com os outros. Quando um
nó é criado ou movido, sua posição é calculada e ele é movido para se encaixar
dentro dessa grade.
2. Modo de Uso
Como o objetivo deste programa é desenhar grafos sintáticos
tem-se, na barra de ferramentas (segunda linha da tela), as funções mais básicas,
aquelas de uso mais freqüente, isto é, criar nós e , eliminar elementos gráficos,
desfazer e refazer mudanças. Importar e exportar grafos estão localizados
no menu, as propriedades de um nó podem ser alteradas com o acionamento do
botão direito do mouse sobre o nó desejado e a seleção de nós pode ser feita
graficamente.
2.1 Utilização da barra de ferramentas
Na barra de ferramentas, tem-se os seguintes botões, na
ordem de sua exibição, da esquerda para a direita:
[1] - Criar nó cabeça;
[2] - Criar nó terminal;
[3] - Criar nó não-terminal;
[4] - Criar nó vazio;
[5] - Criar seta sucessor;
[6] - Criar seta alternativa;
[7] - Apagar elementos gráficos;
[8] - Desfazer mudança;
[9] - Refazer mudança.
Os quatro primeiros botões (que criam nós), ao serem acionados,
permanecerão "pressionados" graficamente até que o usuário acione outro dos
seis primeiros botões [1-6], ou pressione o botão esquerdo do mouse numa posição
vazia da janela. Neste segundo caso, um nó do tipo selecionado será criado.
Os dois botões seguintes (que criam setas) [5-6], ao serem acionados, permanecerão
"pressionados" até que o usuário acione outro dos seis primeiros botões [1-6],
ou pressione o botão esquerdo do mouse num nó. Neste segundo caso, uma seta
do tipo selecionado será criada, tendo sua origem neste nó.
O sétimo botão (intitulado Delete) [7] irá apagar da janela
qualquer elemento ou grupo de elementos que estiverem selecionados (veja como
selecionar elementos gráficos nas próximas seções) no momento em que o botão
for acionado. Para desfazer alguma mudança no grafo, basta acionar o oitavo
botão [8] da barra de ferramentas, e para refazer algo que foi desfeito, basta
acionar o nono botão [9]. Só são permitidos cinco acionamentos válidos seguidos
em cada botão, ou seja, só se pode desfazer ou refazer mudanças cinco vezes
seguidas.
2.2 Criação de nós
Para se criar um nó, basta acionar o botão do nó do
tipo desejado e em seguida, pressionar o botão esquerdo do mouse com seu cursor
na posição vazia da janela onde se quer que o nó fique. Caso a posição onde
o cursor estava quando o botão esquerdo do mouse foi acionado esteja ocupada,
o nó não será criado. Todos os nós, ao serem criados, não possuem nome ou
rotina semântica associada ao nó. O usuário não pode mexer na sua posição
absoluta na tela, pois o programa irá aproximá-la para a grade pré definida.
Para criar-se mais de um nó do mesmo tipo do nó criado, basta segurar o botão
Ctrl do teclado ao pressionar o botão esquerdo do mouse na área de trabalho.
Se o usuário voltar a pressionar o botão esquerdo do mouse na área de trabalho
sem estar segurando o botão Ctrl do teclado, será criado mais um nó e o usuário
terá que voltar a acionar o botão na barra de ferramentas para criar outro.
Todo nó, ao ser criado, passa a ser o único nó selecionado do grafo.
2.3 Alteração das propriedades dos nós
Todos os nós possuem propriedades as seguintes propriedades:
posição e tamanho, até nome do símbolo gramatical que representa, tipo e rotina
semântica associada ao nó. Pode-se fazer o acesso às propriedades de um nó
quando se pressiona o botão direito do mouse sobre o nó cujas propriedades
se deseja alterar ou quando se dá doubleclick no nó. Ao fazer isso, uma nova
janela se abrirá e irá mostrar as propriedades do nó, permitindo ao usuário
alterá-las. Algumas propriedades como o nome do símbolo gramatical que representa,
tipo e nome da rotina semântica não podem ser alteradas graficamente, apenas
através do uso da janela de propriedades, outras como o tamanho e posição
podem ser alteradas sem abrir a janela de propriedades. Para mudar os valores
da janela de propriedades, basta pressionar o botão esquerdo do mouse no campo
desejado e digitar o novo valor (note-se que posição e tamanho devem ser números
inteiros (comece com valores próximos aos que aparecem assim que a janela
de propriedades é aberta para ver o que acontece).
Um nó também pode ser movido pela área de trabalho e ter
seu tamanho alterado graficamente. Para movê-lo, basta selecionar o nó desejado
e arrastar o mouse pela área de trabalho, até a posição desejada. Para alterar
seu tamanho, acione o mouse no nó e 8 quadrados pequenos aparecerão ao redor
do nó. Estes são os quadrados de tamanho e ao serem arrastados com o mouse,
irão alterar o tamanho do nó, e talvez mudar um pouco sua aparência para se
adequar às novas dimensões. Arrastando-se os quadrados em um lado horizontal
ou vertical produz-se um aumento do tamanho deste lado; arrastando-se uma
dos quadrados na diagonal, produz-se um aumento dos tamanhos dos lados do
nó correspondentes a essa diagonal.
Vários nós podem ser movimentados ou terem seus tamanhos
aumentados ou diminuídos simultaneamente, para isso basta traçar uma área
de seleção na área de trabalho que contenha os nós que se deseja alterar,
e após estarem todos selecionados basta alterar um deles que os outros terão
as mesmas alterações. Se por exemplo um dos nós selecionados for movido, todos
os selecionados serão movidos na mesma direção e o mesmo espaço que o primeiro
foi movido. O mesmo serve para alterar seu tamanho.
Outras propriedades de um nó incluem seu sucessor e alternativa,
mas isso será discutido nas próximas seções.
2.4 Ligação entre dois nós
Como foi visto, cada nó pode possuir um nó sucessor
e um nó alternativa. O nó sucessor indica qual símbolo deve ser esperado depois
do atual, e o alternativa representa qual símbolo pode ser esperado no lugar
deste. Um nó deve ser ligado ao seu sucessor por uma seta sucessora, que sempre
sai pelo lado direito do nó, enquanto que a alternativa deve ser ligada por
uma seta alternativa, que sempre sai do lado de baixo do nó. OBS: a seta pode
aparentar estar saindo pelo lado oposto do nó caso o usuário não tenha ligado
corretamente as setas. Isso significa que uma seta sucessor estaria saindo
pelo lado esquerdo do nó e uma seta alternativa estaria saindo pelo lado superior
do nó. Para ligar um nó origem m a um nó destino n, seleciona-se inicialmente
o tipo de seta desejado, acionando-se a botão correspondente. Em seguida,
aciona-se o mouse no nó n, arrasta-se o mouse traçando o caminho que se deseja,
e finalmente aciona-se o mouse sobre o nó n. Caso já exista uma seta apontando
para o nó n, pode-se acionar o mouse sobre a seta apontando para n, e o nó
destino passará a ser n. Esta facilidade impede que os grafos fiquem muito
confusos. Existem duas maneiras de traçar uma seta, utilizando o autotracer
ou manualmente.
O autotracer é uma opção especial do SGD que procura conectar
quaisquer dois pontos na área de trabalho, utilizando apenas três segmentos
de reta consecutivos, criando assim uma pequena "escada". Para cada ponto
da área de trabalho que o usuário acionar o mouse, novas três setas ligadas
serão criadas e a direção original será alterada em 90°. O usuário pode escolher
o sentido em que a seta aponta. O autotracer deve ser usado apenas para se
fazer ligações simples pois suas setas ficam complexas e desorganizadas. Ele
já está ligado assim que o programa é iniciado Para ligações mais complicadas,
o modo manual, descrito a seguir, é recomendado devido ao maior controle que
ele oferece.
O modo manual é mais restritivo que o autotracer e por
isso evita confusões. Ao iniciar a criação de uma seta, do mesmo modo descrito
no autotracer, o usuário só pode movê-la na direção inicial dela(para baixo
para seta alternativa e para a direita para seta sucessora). Cada vez que
o usuário aciona o mouse na área de trabalho, a seta traça um ângulo reto
no sentido que o usuário escolher.
Setas podem ser simplificadas. Isso significa que podemos
diminuir o número de segmentos, fundindo dois paralelos que estão ligados
por um único segmento. Para simplificar uma seta o usuário deve primeiro selecionar
a seta que deseja simplificar. Ao selecioná-la, seus quadrados de movimento
irão aparecer. O usuário deve então acionar o mouse sobre o quadrado de movimento
do segmento de reta que deseja mover e, sem soltar o botão, mover o quadrado
de movimento até um segmento de reta paralelo a este, que pertença a esta
seta. O segmento movido e o segmento de destino devem estar ligados por apenas
um segmento de reta. Enquanto o segmento estiver sendo movido, uma reta tracejada
irá aparecer para ajudar o usuário a se localizar na área de trabalho. Quando
os dois segmentos estiverem se sobrepondo, o usuário deve soltar o botão do
mouse e então os dois segmentos irão se fundir, eliminando o segmento que
havia entre eles.
Para mudar o nó apontado por uma seta basta acionar o
mouse sobre a ponta da seta que se deseja mover e, sem soltar o botão do mouse,
mover a ponta até o nó que se deseja ter como destino. Note que a seta pode
se simplificar durante este processo.
2.5 Utilização o menu
O menu principal tem quatro opções: 'File', 'Edit',
'Options' e 'About'. Cada uma delas pode ser utilizada com um acionamento
do mouse sobre seu nome, ou utilizando o teclado, ao segurar a tecla Alt e
acionar o botão do teclado correspondente a letra sublinhada no menu.
- O submenu File é o que utiliza as funções que salvam
ou abrem arquivos. Dentro dele temos:
- Open, para abrir um grafo
salvo em um arquivo;
- Save, para salvar o grafo
sendo utilizado;
- Save as, para salvar o
grafo sendo utilizado em outro arquivo ou outro diretório;
- Import, importa um grafo
de um arquivo e coloca-o no final do que está atualmente na área de trabalho,
ou seja, após a posição do nó cuja posição é a mais inferior;
- Generate graph, gera o
arquivo de saída em uma linguagem para ser lida por um analisador sintático.
Ver seção [3.4 Funções];
- Exit, sai do programa.
- O submenu Edit, com o qual se pode fazer mudanças
no grafo, com:
- Delete, apaga qualquer
objeto que esteja selecionado, corresponde ao botão desse nome;
- Undo, desfaz até cinco
mudanças no grafo consecutivas, corresponde ao botão desse nome;
- Redo, refaz até cinco
acionamentos do menu (ou botão) undo, corresponde ao botão desse nome;
- O submenu Options, no qual se pode alterar opções
do programa, com:
- Automatic tracer, liga
ou desliga o autotracer (passando ao traçado de manual de setas). Uma marca
ao seu lado indica que está ligado.
- Compilation, define se
ao gerar o código de saída, o SGD deve deixá-lo pronto para ser compilado.
- Interpretation, define
se ao gerar o código de saída, o SGD deve deixá-lo pronto para ser interpretado.
OBS: Um grafo pode gerar
código para ser compilado ou para ser interpretado, um por vez. As diferenças
entre o código compilado e interpretado estão descritas em [3.4 Funções].
- O menu Help, só possui uma opção:
- About, mostra a versão
do programa e seu programador.
2.6 Práticas de bom uso
- Sempre deixar os nós
perto de seu sucessor e alternativa.
- Sempre que possível, uma
setas sucessora deve apontar para o nó sucessor pelo lado esquerdo deste.
Uma seta alternativa deve apontar por cima do nó alternativo.
- Ao traçar uma seta, se
o nó destino já possui uma seta chegando a ele, deve-se tentar fazer com que
a primeira aponte para a segunda.
- Após ter criado uma seta,
deve-se tentar simplificá-la o máximo possível (eliminando segmentos de reta
desnecessários).
- Deve-se tomar cuidado
com nós cujo tamanho é maior que o original, pois podem cobrir outros nós
ou ficar por cima de segmentos de setas.
3. Funcionamento
3.1 Estrutura Geral
O programa é dividido em 2 classes, suas funções
e as funções do programa principal. Objetos de cada uma das classes podem
ser criados e alterados tanto no programa principal como na outra classe.
Existem duas listas ligadas para cada classe, criadas e alteradas no programa
principal através do uso das várias funções que estão disponíveis. As listas
ligadas estão divididas em dois tipos, aquelas cujos membros correspondem
a objetos cujas representações gráficas estão selecionadas e aqueles objetos
cujas representações gráficas não estão selecionadas (o motivo disso é que
as propriedades de um objeto só podem ser alteradas se este estiver selecionado,
e com duas listas temos maior controle, velocidade e visualização sobre o
que está acontecendo). Tanto os nós como as setas possuem esta divisão em
duas listas.
3.2 Definição de um nó: A Classe CCell
Esta é a classe onde cada objeto é um nó, e aqui guardamos
todas as suas propriedades: nome do símbolo gramatical que representa, nome
da rotina semântica associada ao nó, tipo, tamanho, posição, sucessor (representado
por apontador para um objeto de tipo seta) e alternativa (idem). Aqui temos
todas as funções que alteram essas propriedades.
3.3 Ligações de um nó: A Classe Arrow
Esta é a classe onde cada objeto é uma seta, cuja
finalidade é mostrar quem é o sucessor ou alternativa do nó de onde esta começa.
Como isso é feito graficamente, e as setas podem ser bem complexas (isto é,
conter muitos segmentos), temos muitas variáveis para guardar os atributos
necessários, como os pontos delimitadores de cada segmento de reta, seus quadrados
de movimento e outros. As setas possuem uma ponta para indicar para onde estão
apontando e por conseqüência conhece-se o nó destino.
3.4 Funções
No programa principal existem várias funções para
alterar as listas ligadas de setas e nós, as próprias setas e os nós, cuidar
da saída e da entrada e para tratar das mensagens do Windows. Muitas destas
funções não precisavam realmente ser funções, mas foram programadas assim
para que o programa ficasse mais modular e compreensível.
A função "MakeOutputFile()" é a função que utilizando
as informações disponíveis no grafo irá gerar a saída num arquivo chamado
"carrega.cpp" que será lido pelo analisador sintático. O arquivo está no formato
de dois vetores sendo uma para quando o arquivo for compilado e outra para
quando este for interpretado. Cada linha deste arquivo é uma célula, contendo
todas as propriedades de um nó, incluindo seu sucessor e alternativa. Neste
arquivo existe uma propriedade extra que é um identificador para o nó, e por
esse identificador podemos saber quem é o nó sucessor e o alternativa.
3.5 Mensagens do Windows
O Windows funciona por meio de mensagens. Para cada
evento que ocorre ele envia uma mensagem para o programa dizendo qual foi
o evento. Teclado e mouse, ao serem usados, enviam mensagens. As mensagens
possuem alguns parâmetros e através deles podemos saber que tipo de evento
ocorreu e a sua posição na tela.
Como neste programa não precisamos fazer nada enquanto
o usuário não provocar um evento, como por exemplo mover o mouse, acioná-lo,
etc., todas as funções são apenas chamadas após o usuário ter feito algo no
teclado ou mouse.
4. Alteração do Programa
4.1 Estado Atual do SGD
O SGD está completamente funcional, com todas as funcionalidades
básicas requeridas para se construir um grafo sintático, salvá-lo e alterá-lo
com relativa facilidade. Existem ainda diversas funcionalidades que poderiam
ser implementadas, algumas facilmente outras dificilmente.
4.2 Comentários no programa
Sempre que possível foi feito o comentário de um trecho
de código antes mesmo de criá-lo, e quem quiser alterar o programa não terá
muitos problemas em entender o código. Os comentários procuram fazer três
coisas: descrever o que um determinado trecho de código faz, descrever o porque
e ressaltar pedaços que podem ser confusos. Cada função possui um comentário
que resumi o que ela faz, localizado logo acima da mesma.
4.3 Alteração das Funções
Algumas das funções podem ser alteradas facilmente
para suprir as necessidades do programador. Por exemplo, se o analisador sintático
que será usado para ler o código gerado para um grafo e interpretá-lo usa
um formato ou uma linguagem diferente de C++, basta alterar a função "MakeOutputFile()".
O programador deve ter cuidado ao alterar uma função,
para não alterar uma parte essencial do código que não deveria ser mudada,
como por exemplo algum apontador essencial, o que pode dar problemas. Para
solucionar isso, (o que é que você quer dizer? Solucionar os problemas ou
descobrir o que pode ou não ser mudado??) veja o item seguinte.
4.4 Criação de funções pelo usuário
Para alterações um pouco mais complexas é recomendável
que se crie funções próprias. Se estas forem parecidas com alguma já existente,
sugerimos copiar o código e depois o alterá-lo. Isso deve ajudar a impedir
problemas mais sérios e deve acelerar o desenvolvimento.
4.5 Observações
- É importante observar quais variáveis
são globais e quais não são. A função "WndProc()", que recebe as mensagens
do Windows, possui algumas variáveis estáticas porque, sendo uma função, tem
suas variáveis apagadas da memória quando termina.
- Ao usar a barra de rolagem, não é
o campo de visão que muda, mas sim o que está sendo mostrado (a visão é fixa,
o mundo é que se move), por isso os valores quando se está desenhando.
5. Glossário
Área de trabalho: região da janela onde se desenha um
grafo.
Barra de Rolagem: Barras que ficam no canto direito e
inferior da janela e que podem ser usadas para deslocar o grafo para cima
e para baixo.
Doubleclick: o ato de se pressionar duas vezes rapidamente
o botão esquerdo do mouse.
Elemento de um grafo: Um nó ou uma seta mostrados na área
de trabalho.
Elemento Selecionado: Qualquer elemento gráfico que tenha
sido acionado com o botão esquerdo do mouse ou tenha acabado de ser criado.
Denotado graficamente por pequenos quadrados, circundando um nó ou nos segmentos
de reta de uma seta.
Janela: Espaço gráfico do programa. Compreende toda a
área de trabalho, o menu, a barra de ferramentas e as barras de rolagem.
Quadrados de Movimento: Pequenos quadrados que aparecem
no meio dos segmentos de reta de uma seta quando selecionados.
Quadrados de Tamanho: Pequenos quadrados que aparecem
ao redor de um nó quando selecionado.
6. Bibliografia
[Setzer 1] - "Simple sintax graphs, their parse with automatic
error recovery and an ANSI C simple sintax graph", Valdemar W. Setzer e Roberto
C. Mayer
[Setzer 2] - "A construção de um compilador" Valdemar
W. Setzer e Inês S. Homem de Melo
[Aho 1] - "Theory of Parsing, Translation and Compiling"
Alfred V. Aho, Jeffrey D. Ullman
20/12/200
Autor: Giuliano Luz Pigatti Caliari
Orientador: Valdemar W. Setzer
Este manual também está disponível
no formato Word 97 para Windows.