UNIVERSIDADE DO MINHO

 

 

 

Processamento de Linguagens I

(2º Semestre  1998/99)

 

 

 

 

 

 

 

Translator

 

 

 

 

 

Trabalho Prático

 

 

 

 

 

 

 

Fernando Alexandre Peixoto Gomes N.º 22652

Luciano Miguel Ferreira Rocha N.º 22673

Pedro Miguel de Andrade Tarrinho Nº22713

Braga

4/Junho/1999


 

Índice

Índice____________________________________________________________________________ 1

Introdução________________________________________________________________________ 2

Análise___________________________________________________________________________ 3

Análise Léxica e Sintáctica:_________________________________________________________ 3

Grove:__________________________________________________________________________ 5

Tradução:________________________________________________________________________ 7

html:______________________________________________________________________________________ 8

Latex:____________________________________________________________________________________ 11

Grove:____________________________________________________________________________________ 11

Conclusão________________________________________________________________________ 13

Anexos__________________________________________________________________________ 14

Makefile__________________________________________________________________________________ 14

translator.lex_______________________________________________________________________________ 14

translator.y________________________________________________________________________________ 15

grove.h___________________________________________________________________________________ 24

grove.c___________________________________________________________________________________ 25

grovehtml.h________________________________________________________________________________ 26

grovelatex.h________________________________________________________________________________ 26

grovehtml.c________________________________________________________________________________ 26

grovelatex.c________________________________________________________________________________ 35

list.h_____________________________________________________________________________________ 38

list.c_____________________________________________________________________________________ 38

Diagrama Genérico do Grove________________________________________________________ 40

Abertura________________________________________________________________________ 40

Corpo__________________________________________________________________________ 41

Fecho__________________________________________________________________________ 42

Diagrama do Grove Resultante do Documento Exemplo__________________________________ 43

Abertura________________________________________________________________________ 43

Corpo__________________________________________________________________________ 44

Fecho__________________________________________________________________________ 45


Introdução

 

Na primeira fase do trabalho fizemos o reconhecimento léxico e sintáctico de uma linguagem especificada pelo professor.

Para o reconhecimento léxico utilizámos a ferramenta lex, desenvolvida para esse propósito, o que facilitou bastante esse passo.

Quanto ao reconhecimento sintáctico, utilizámos a ferramenta yacc. Decidimos por essa em vez de bison devido a que primeira é uma ferramenta standard do sistema operativo UNIX®.

Na segunda fase criámos a estrutura de dados de armazenamento do documento, para posterior análise/tradução. Essa estrutura de dados, depois de construída de acordo com o documento, é chamada de grove. Descrevemos a seguir no relatório essa estrutura de dados e o código que, na análise sintáctica,  constrói o grove.

 Finalmente a partir do grove resultante, produzimos o código correspondente em HTML ou Latex. Tentamos ao máximo que o código gerado obedecesse aos tipos definidos, mas, infelizmente, a linguagem HTML não foi idealizada para documentos e, portanto, como não existiam algumas correspondências, tivemos que juntar vários tipos para que produzisse o efeito desejado.

 


Análise

 

Análise Léxica e Sintáctica:

 

Depois de analisada a gramática sugerida pelo professor, alterámo-la de acordo com algumas decisões de implementação.

Em primeiro, removemos as produções OpenTag e CloseTag, substituindo-as onde aparecem pelas suas produções, alterando Tagid pelo correspondente na produção onde foram substituídas. Isto resultou na verificação automática do emparelhamento correcto de OpenTag/CloseTag, tanto pela sua existência como pela correspondência do fecho da tag à abertura, libertando essa acção da próxima fase.

Com essa alteração conseguiu-se uma redução substancial dos conflitos shift/reduce e reduce/reduce, e removeu-se a produção Tagid.

Pelo modo de funcionamento do yacc na análise semântica, foi decidido alterar as produções que usam recursividade à direita para recursividade à esquerda, sempre que válido.

Para remoção de conflitos na produção Autor alterámo-la, assim como Email e Url para:

Autor  ‘<’ AUTOR AttrList ‘>’ Nome ‘<’ EUa

EUa    EMAIL AttrList ‘>’ TEXT ‘<’ ‘/’ EMAIL ‘>’ ‘<’ EUb ‘/’ AUTOR ‘>’

        URL AttrList ‘>’ TEXT ‘<’ ‘/’ URL ‘>’ ‘<’ ‘/’ AUTOR ‘>’

        ‘/’ AUTOR ‘>’

EUb    URL AttrList ‘>’ TEXT ‘<’ ‘/’ URL ‘>’ ‘<’

        

 

A nova gramática apresentada, corrigindo um erro existente na antiga produção Lista,  que segue o que tinhamos sugerido no relatório da primeira fase, provocou a alteração de Lista para:

Lista  ‘<’ LISTA AttrList ‘>’ ListaItem ‘<’ ‘/’ LISTA ‘>’

ListaItem   ListaItem Item

 

Outra alteração introduzida à gramática foi a introdução de um título na produção Exemplo, que a alterou para:

Exemplo : '<' EXEMPLO AttrList '>' Titulo ExemploConteudoList '<' '/' EXEMPLO '>' {

        $$ = gnew();

        $$->class = $2;

        $$->ids = $3;

        $$->sub = ginsert($5, $6);

}

 

A remoção de Tagid e a remoção de OpenTag e CloseTag tornaram possíveis a alteração de Ref e de Gráfico e a remoção de ElemVazioTag (já que existem agora identificadores tanto para Ref como para Gráfico).

Com esta gramática alterada, o esquema de reconhecimento léxico foi alterado de modo a reconhecer os tipos individuais de tags, o que complicou um bocado.

Devido à existência de espaços vazios entre tags, e devido a não os termos (des)considerado na gramática, resolvemos verificar no analisador léxico se o texto é constituído apenas por caracteres brancos, e, se tal, ignoramo-lo. Infelizmente, não foi possível definir a produção Text, que representa o texto, como uma lista de TEXT, devido a conflitos de shift/reduce. A nossa intenção era minimizar os problemas de memória do lex, já que, quando a memória deste se esgotasse armazenando o texto, fosse possível este passar o texto que já contém e passasse também o seguinte como novo texto. Teríamos então uma lista ligada de textos, que resolveria o problema.

Ainda em relação à passagem do texto encontrado ao reconhecedor sintáctico, resolvemos copiá-lo antes de o passar, com a função strdup, permitindo assim um tamanho variável do espaço reservado ao texto, limitada a memória apenas pelo SO.

Para efeitos de reportagem de erros, resolvemos ir contando a linha actual, incrementando-a pelo aparecimento de um cr/nl. Seria possível usar a variável existente para o efeito no lex, mas, devido a que não a conhecíamos, e, além disso, à sua especificidade em relação à versão do programa (flex/lex/AT&T lex/etc.), mantivemos o nosso código de contagem da linha.

Concretamente, quanto ao reconhecimento léxico, definimos dois estados exclusivos, o inicial e o Tag. O estado inicial corresponde a quando nos encontramos fora das Tags, i.e. não nos encontramos na abertura/fecho de uma parte (secção) mas sim no texto que lhe está associado. A partir do carácter menor (<) passamos para o estado Tag, já que esse carácter representa o início da tag.

O estado Tag representa o estarmos na definição de uma secção. Devido a termos alterado a gramática temos agora que reconhecer os diferentes tipos de tags. Também reconhecemos agora os ids, para uso em referências, assim como os símbolos a eles associados (igual (=) e valor). Neste estado, como os caracteres brancos são irrelevantes (excepto para separar o identificador da tag do id), ignoramo-los, não deixando antes de incrementar o número da linha caso encontremos um nl. As expressões regulares para reconhecer os tokens encontram-se apresentadas em anexo. O aparecimento de qualquer coisa inesperada tem como resultado uma mensagem de erro a identificar o que apareceu e a linha onde tal aconteceu, após a qual o reconhecedor léxico continua.

Quanto ao tratamento de erros no yacc, decidimos não fazer qualquer recuperação de erro. Aparece uma mensagem indicando o erro, a linha onde tal aconteceu e o token que apareceu, inesperado. Se tivéssemos decidido usar o bison, a mensagem de erro indicaria também o que era esperado.

A decisão de não fazer a recuperação de erros deve-se ao facto de tal complicar bastante a gramática e, por uma experiência nossa, a recuperação de erro provoca o aparecimento de mais erros, já que é por alguma razão que ocorre o erro. Se o utilizador se tivesse esquecido, por exemplo, da Abertura e, ignorando o erro, entrássemos em Abertura, aconteceria depois o erro de que CORPO é inesperado e que espera TITULO, o que pode confundir o utilizador.

Grove:

 

Devido à função do grove ser representar o documento na memória, a estrutura de dados que pensamos ser a ideal, ou então a mais simples e que cumpre os seus objectivos, é a seguinte:

struct grove {

int class;

char *text;

struct id *ids;

struct grove *sub;

struct grove *next;

}

A seguir se descrevem os diversos elementos:

·        class: Indica a classe do elemento, por exemplo: PLI-DOC, COMANDO, ABERTURA, etc, i.e. as diferentes tags que indicam os diferentes tipos de elementos existentes em documentos deste tipo.

·        text: Apontador para o texto associado ao elemento. Apenas inicializado no grove respeintante à produção Text. Apenas existe por ser necessário guardar esse texto em apenas essa produção, e não existe qualquer outro sítio na estrutura para o guardar.

·        Ids: Lista ligada de Atributos.

·        sub: Lista ligada de groves, que representam o conteúdo deste grove.

·        next: Lista ligada dos groves seguintes, representando o conteúdo de outro grove.

A estrutura que guarda os atributos contém apenas o id, o valor, e um apontador para a estrutura seguinte.

O código que constrói o grove consiste, para a grande parte dos casos, nas seguintes linhas de código:

$$ = gnew();

$$->class = $2;

$$->ids = $3;

Resumidamente, é reservada a memória para a estrutura e inicializada (gnew()); a classe deste grove é a tag (assim foi só cut&paste); e a lista de atributos é guardada.

Depois, dependendo do número de elementos que sub-constituem este grove, temos algo do género:

$$->sub = ginsert(ginsert($5, $6), $7);

Ou seja, para apenas um sub-constituinte, temos $$->sub = $5. Para mais, temos para cada um um ginsert do novo no anterior. ginsert é uma função auxiliar que percorre a lista passada como primeiro parâmetro até ao fim e aí coloca o novo (segundo parâmetro). Caso a lista seja nula a nova lista será o segundo elemento.

Algumas excepções são as listas de elementos, que se definem por apenas um ginsert do elemento à direita na lista, sem criação de uma nova estrutura na memória; os elementos que empacotam outros, i.e., que não existem por si só, mas que podem ser vários outros (ex.: Conteudo - neste caso definimos que o resultado é o elemento); e Text, em que apenas reservamos a memória, definimos a classe, e guardamos o texto no apontador reservado.

Quanto aos atributos, em relação à lista, o procedimento é similar ao caso dos groves, mas em vez de ginsert, usamos attrinsert, devido ao tipo de dados ser diferente. Em relação à criação da estrutura, reservamos a memória com uma função auxiliar semelhante à respectiva nos groves e guardamos o id ($$->id = $1) e o valor ($$->value = $3).

Temos assim, depois de construído o grove, uma representação em memória semelhante à figura apresentada em anexo. Mostramos também a representação do grove resultante do documento exemplo indicado pelo professor.

Para resolver o problema de redefinições de locais de referências e referências a locais não definidas, assim como avisar sobre definições de locais de referências nunca referenciadas, quando geramos o grove, na produção Attr (que guarda os atributos e definições de locais de referências), se estivermos a definir um local, adicionamos a definição numa lista com todas as definições, e se, por ventura, já existir uma definição igual, i.e. com o mesmo valor, então estamos perante um erro e mostramo-lo. Se, por outro lado, se tratar de uma referenciação, verificamos se essa referência se encontra definida. Se sim, alteramos essa definição na lista e indicamos que é referenciada. Caso contrário, adicionamos essa referenciação a uma outra lista.

Após a geração de todo o grove, verificamos as duas listas: para cada elemento da lista de definições, se não se encontrar referenciado, avisamos sobre o facto; e para cada elemento da outra lista que contém as referências a elementos não definidos mostramos um erro. Se for encontrado um erro, o programa aborta; no caso do aviso, a execução prossegue.

Quanto à definição “especial” de BibItem introduzida pelo professor, em que, por cada referência a um item na Bibliografia, em vez do texto link ser a definição, será a Chave do item. Para isso, sempre que é definido um local de referência numa Bibliografia, adicionamos numa lista a referência e o texto da Chave. Aquando da geração do código da linguagem pretendida, quando nos encontramos numa referência, verificamos se essa se encontra na lista criada. Se sim, é usado o texto da Chave guardado, na descrição do link.

Tradução:

A tradução começa após o reconhecimento da produção PLI-DOC (temos um documento já representado), chamando uma função, por um apontador estático. O endereço apontado é alterado conforme se deseje gerar código html, latex, ou então apenas a hierarquia do grove e fica a apontar para a respectiva função. É da responsabilidade dessa função continuar a tradução dos elementos seguintes e dos elementos seus constituintes.

Para auxiliar à travessia entre os seguintes e os constituintes, é definida uma tabela de salto, por cada tipo de linguagem, que, dada a classe do grove retorna a função que o traduz. Para simplificar o código, devido ao uso dessa tabela, são definidas as seguintes macros e funções em C:

#define SUB(g) at = g->class; if ((g)->sub) gfunc((g)->sub->class)((g)->sub)

#define NEXT(g) if ((g)->next) gfunc((g)->next->class)((g)->next)

 

static crsf gfunc(int class) {

int i;

 

if (htmlf[class - TEXT].class == class)

return htmlf[class - TEXT].f;

i = 0;

while (htmlf[i].class >= 0 && htmlf[i].class != class) ++i;

return htmlf[i].f;

}

 

gfunc é a função que calcula a função de travessia para uma dada classe.

Como exemplo do uso destes auxiliares na geração do código html apresentamos a função de tradução da Abertura:

void abertura2html(struct grove *g) {

        printf("<HEAD>\n");

set_ids(g->ids);

SUB(g);

printf("</HEAD>\n");

NEXT(g);

}

set_ids é a função que gera o código correspondente à definição de locais de referência.

html:

Nos casos mais simples e mais directos, sempre que possível, temos apenas no início da função de tradução a impressão da tag html correspondente; a impressão dos constituintes; e o fecho da tag aberta. Por vezes nem é necessário o fecho, devido à especificidade do tipo a traduzir.

Exemplo:

void para2html(struct grove *g) {

 

SUB(g);

printf("<P>\n");

set_ids(g->ids);

NEXT(g);

}

 

void lista2html(struct grove *g) {

 

set_ids(g->ids);

printf("<UL>");

SUB(g);

printf("</UL>");

NEXT(g);

}

A tradução, para cada tipo, é a seguinte:

·        Texto: Apenas o próprio texto. Qualquer tratamento dos caracteres especiais e específicos deveria ser feita aqui. Mas, devido a isso mesmo, de serem especiais e específicos, o próprio utilizador deverá tratar deles. Para não definirmos a nossa própria linguagem de definição de caracteres, e também para não optar pela do latex ou pela do html, decidimos realizar nenhum tratamento.

·        Pli_doc: É a definição do próprio documento html, portanto será <HTML> na abertura, o conteúdo, e </HTML> no fecho.

·        Comando: A definição de comando não existe em html, portanto tivemos que inventar um pouco. O que nos pareceu mais relacionado com o elemento foi o tipo de texto “teletype”, ou seja: <TT> conteúdo </TT>.

·        Abertura: A abertura contém descrições do documento, como o seu título e autores. O equivalente em html é: <HEAD> conteúdo </HEAD>.

·        Título: Este é o pior, devido a que temos diferentes títulos. Por causa disso tivemos que manter uma variável que indicasse a classe do elemento anterior, para saber onde estamos. Os diferentes títulos são:

·        Documento: <TITLE> conteúdo </TITLE>. Como nos pareceu que também seria bom ter o título visível no documento, pusemos também: <H1 align=”center”> conteúdo </H1>.

·        Capítulo: <H2 align=”center”> número do capítulo - conteúdo </H2>. Para saber o número do capítulo vamos incrementando uma variável definida para o efeito.

·        Secção: Temos que guardar qual o número da secção em que nos encontramos, assim como o nível da secção. Para isso, guardamos num array o número das secções, sendo a posição o nível da secção. O tratamento do array é feito nas Secções. O código gerado é: <H3 align=”left”> número da secção.número da sub-secção.... conteúdo </H3>.

·        Figura: Aqui teremos que percorrer o conteúdo duas vezes, uma após percorrer os próximos, devido ao aparecimento da definição do local da figura antes do texto descritivo da figura. O código gerado é: <IMG ALT=” conteúdo “ SRC=” próximos “><BR> número da figura. conteúdo.

·        Exemplo: <strong> conteúdo </strong>.

·        Caso contrário: <H3> conteúdo </H3>.

·        Data: Não existindo o tipo date ou semelhante em html, produzimos: <META name="Data" content=" conteúdo “>, para fornecer informações aos motores de pesquisa, e também $Data: conteúdo $, para se visualizar na página.

·        Autor: Para indicar que se trata de informações sobre o autor, o conteúdo é posto entre o elemento ADDRESS, visto nos ter parecido ser esse o que se aproximava mais ao pretendido.

·        Nome: <strong> conteúdo </strong>, para enfatizar.

·        EMail: <a href=”mailto: conteúdo “> conteúdo </a>.

·        URL: igual a EMail, mas, em vez de mailto: temos http://, se o protocolo não estiver definido (pelo menos assim queríamos, mas não o fizemos a tempo do relatório).

·        Resumo: Devido à inexistência de qualquer elemento semelhante a Resumo em html, definimos um header, seguido do conteúdo: <H2>Resumo</H2>.

·        Corpo: Para separar da Abertura, introduzimos duas linhas horizontais inicias: <HR><HR><BODY> conteúdo </BODY>. Não temos a certeza se pôr o Fecho fora do body viola o padrão, mas como funcionou...

·        Capítulo: Aqui incrementamos o número do capítulo e inicializamos as secções a zero. Depois processamos o conteúdo. Para separa os capítulos, produzimos um <BR> no fim do capítulo.

·        Parágrafo: <P>.

·        Lista: <UL> conteúdo </UL>, se for não numerada, ou então <OL> conteúdo </OL>.

·        Item: <LI>.

·        Realçado: <B> conteúdo </B>, se bold; <I> conteúdo </I>, se italic; ou então, para o caso de small caps, por cada segmento de letras minúsculas pomos <small> seguido das letras, mas transformadas para maiúsculas, seguidas de </small>.

·        Figura: <p align=”center” ><img alt=” conteúdo. O Título encarrega-se do resto.

·        Gráfico: É procurado e mostrado o valor de LOCAL, definido nos atributos.

·        Exemplo: <hr> conteúdo <hr><h6 align=”right”>Exemplo número do exemplo </h6>. É usada uma variável para contar o exemplo onde estamos.

·        Fecho: Neste caso, para separar o Corpo do Fecho, introduzimos duas linhas horizontais <HR><HR>.

·        Agradecimentos:. Como não existem Agradecimentos em html, tivemos que usar os títulos padrão: <H2>Agradecimentos</H2>, seguido do conteúdo.

·        Bibliografia: Idem Agradecimentos, mas antes fazemos um <BR> para separar dos Agradecimentos.

·        BibItem: <DL> conteúdo </DL>.

·        Chave: <DT> conteúdo </DT>.

·        Pub: <DD><CITE> conteúdo </CITE></DD>. Decidimos usar o cite, devido a ser uma referência a documentação, o que nos pareceu mais apropriado.

·        Ref: Procuramos a que se refere e depois produzimos: <a href=”# referência “> referência </a>. Se essa referência pertence às que se referenciam itens da Bibliografia (BigItem), mostramos a chave em vez da referência.

·        CodPrograma: <PRE> conteúdo </PRE>.

·        Secção: Sempre que entramos numa secção, incrementamos o número da secção e o nível da secção e mostramos o conteúdo. Ao sair decrementamos o nível.

·        Definição de Referências: Excepto para os BibItem’s, sempre que se entra numa função, é executada a função set_ids que percorre a lista dos identificadores e cria um <a name=” valor “></a>. Portanto, definimos um local de referência, sem texto, que não influencia o resultado visual. A posição relativa da função é na grande parte das vezes irrelevante.

Latex:

Infelizmente não nos foi possível completar a parte de geração do código latex a tempo do relatório. Talvez o seja até a entrega. Ver-se-á....

Grove:

Para efeitos de depuração foi realizada uma função de travessia do grove, que mostra a classe do elemento, seguida pelo conteúdo do elemento entre ‘<’ e ‘>’ e pelos seus seguintes.

A função é a seguinte:

void pli_doc2txt(struct grove *g) {

 

printf("%s ", lower(tokname(g->class)));

if (g->sub) {

printf("< ");

pli_doc2txt(g->sub);

printf("> ");

}

if (g->class == PLI_DOC) puts("");

if (g->next) pli_doc2txt(g->next);

}

O resultado da travessia sobre o documento exemplo doc1.txt é o seguinte:

Warning: Unreferenced ID: 'Cre98', defined at line 51.

Warning: Unreferenced ID: 'Sar95', defined at line 46.

pli_doc < abertura < titulo < text > data < text > autor < nome < text > email < text > url < text > > autor < nome < text > email < text > url < text > > resumo < para < text realcado < text > text > para < text > para < text ref text > > > corpo < capitulo < titulo < text > para < text > > capitulo < titulo < text > para < text > lista < item < para < text > > item < para < text > > > > > fecho < agradecimentos < para < text > > bibliografia < bibitem < chave < text > pub < text > > bibitem < chave < text > pub < text > > > > >


Conclusão

 

 

Foi possível verificar as ajudas valiosa que nos fornecem o lex e o yacc. O lex como reconhecer léxico, permitindo-nos especificar regras para certas expressões regulares, o que, fazendo-o nós manualmente em C, seria bastante moroso.

O yacc, como reconhecedor sintáctico, e, já agora, também como analisador de gramáticas, já que identifica logo os erros e conflitos poupando-nos tempo a analisar manualmente a gramática.

Devido também à manipulação permitida pelo yacc dos valores dos tokens e das produções, torna-se bastante fácil a construção do grove, como foi demonstrado pelas poucas linhas de código e por não diferirem muito de produção para produção.

O html mostrou-se insuficiente, com poucos construtores relativos a documentos.


          Anexos

Makefile

 

CC=gcc

CFLAGS=-O3 -ansi -pedantic -g -pipe -W

CLIBS=-lfl

LEX=flex

YACC=yacc

translator: y.tab.o grove.o grovehtml.o grovelatex.o list.o grove.h grovehtml.h grovelatex.h

      $(CC) $(CFLAGS) -o translator y.tab.o grove.o grovehtml.o grovelatex.o list.o $(CLIBS)

y.tab.o: y.tab.c lex.yy.c

      $(CC) $(CFLAGS) -c y.tab.c

y.tab.c y.tab.h: translator.y

      $(YACC) -v -d translator.y

lex.yy.c: translator.lex

      $(LEX) translator.lex

list.o: list.c list.h

      $(CC) $(CFLAGS) -c list.c

grove.o: grove.c grove.h

      $(CC) $(CFLAGS) -c grove.c

grovehtml.o: grovehtml.c grove.h grovehtml.h y.tab.h

      $(CC) $(CFLAGS) -c grovehtml.c

grovelatex.o: grovelatex.c grove.h grovelatex.h y.tab.h

      $(CC) $(CFLAGS) -c grovelatex.c

clean:

      rm -f translator *.o y.tab.c lex.yy.c y.output y.tab.h

all: clean translator

dist: clean

      rm -f pl1v3.tar.gz

      tar czf pl1v3.tar.gz *

 

 

translator.lex

 

id                [A-Z][A-Z0-9\-\.]*

valor             \"[^\"]+\"

      char *strdup(char *);

%x                Tag

      int nchr(char *, char);

      int empty(char *);

%%

\<                      BEGIN(Tag); return yylval.class ='<';

<Tag>\>                       BEGIN(INITIAL); return yylval.class = '>';

<Tag>\=                       return yylval.class = '=';

<Tag>PLI-DOC/[ \>\n]          return yylval.class = PLI_DOC;

<Tag>COMANDO/[ \>\n]          return yylval.class = COMANDO;

<Tag>ABERTURA/[ \>\n]         return yylval.class = ABERTURA;

<Tag>TITULO/[ \>\n]           return yylval.class = TITULO;

<Tag>DATA/[ \>\n]       return yylval.class = DATA;

<Tag>AUTOR/[ \>\n]            return yylval.class = AUTOR;

<Tag>NOME/[ \>\n]       return yylval.class = NOME;

<Tag>EMAIL/[ \>\n]            return yylval.class = EMAIL;

<Tag>URL/[ \>\n]        return yylval.class = URL;

<Tag>RESUMO/[ \>\n]           return yylval.class = RESUMO;

<Tag>CORPO/[ \>\n]            return yylval.class = CORPO;

<Tag>CAPITULO/[ \>\n]         return yylval.class = CAPITULO;

<Tag>PARA/[ \>\n]       return yylval.class = PARA;

<Tag>LISTA/[ \>\n]            return yylval.class = LISTA;

<Tag>ITEM/[ \>\n]       return yylval.class = ITEM;

<Tag>REALCADO/[ \>\n]         return yylval.class = REALCADO;

<Tag>FIGURA/[ \>\n]           return yylval.class = FIGURA;

<Tag>GRAFICO/[ \>\n]          return yylval.class = GRAFICO;

<Tag>EXEMPLO/[ \>\n]          return yylval.class = EXEMPLO;

<Tag>FECHO/[ \>\n]            return yylval.class = FECHO;

<Tag>AGRADECIMENTOS/[ \>\n]   return yylval.class = AGRADECIMENTOS;

<Tag>BIBLIOGRAFIA/[ \>\n]     return yylval.class = BIBLIOGRAFIA;

<Tag>BIBITEM/[ \>\n]          return yylval.class = BIBITEM;

<Tag>CHAVE/[ \>\n]            return yylval.class = CHAVE;

<Tag>PUB/[ \>\n]        return yylval.class = PUB;

<Tag>REF/[ \>\n]        return yylval.class = REF;

<Tag>CODPROGRAMA/[ \>\n]      return yylval.class = CODPROGRAMA;

<Tag>SECCAO/[ \>\n]           return yylval.class = SECCAO;

<Tag>{id}               yylval.text = strdup(yytext); return ID;

<Tag>{valor}                  yytext[yyleng - 1] = '\0'; yylval.text = strdup(yytext + 1); return VALOR;

<Tag>[ \t]+             ;

<Tag>\n                       ++nlines;

<Tag>\/                       return yylval.class = '/';

<Tag>[^ \t\n\"A-Z\/\>\=]+     fprintf(stderr, "Unrecognized token at line %d: %s\n", nlines, yytext);

[^\<]+                        nlines += nchr(yytext, '\n'); if (!empty(yytext)) { yylval.text = strdup(yytext); return TEXT; }

%%

int nchr(char *s, char c) {

      int n;

 

      n = 0;

      while (*s) {

            if (*s == c) ++n;

            ++s;

      }

      return n;

}

 

int empty(char *s) {

      int is;

 

      is = 1;

      while (*s && is) {

            is = (*s == ' ' || *s == '\t' || *s == '\n');

            ++s;

      }

      return is;

}

 

 

translator.y

 

%token ID VALOR TEXT PLI_DOC COMANDO ABERTURA TITULO DATA AUTOR NOME EMAIL URL RESUMO CORPO CAPITULO PARA LISTA ITEM REALCADO FIGURA GRAFICO EXEMPLO FECHO AGRADECIMENTOS BIBLIOGRAFIA BIBITEM CHAVE PUB REF CODPROGRAMA SECCAO

%{

      /* #define YYERROR_VERBOSE -- only bison */

      int nlines = 1;

      #include "grove.h"

      #include "grovehtml.h"

      #include "grovelatex.h"

      #include "list.h"

      #include <string.h>

 

      void parse(struct grove *);

      void chkargs(int, char **);

      crsf start;

      list *refs = NULL, *unrefs = NULL;

      struct id *rftrans = NULL;

%}

%start PLIdoc

%union {

      struct id *attr;

      struct grove *grv;

      int class;

      char *text; }

%type <text> TEXT ID VALOR

%type <attr> AttrList Attr

%type <class> PLI_DOC COMANDO ABERTURA TITULO DATA AUTOR NOME EMAIL URL RESUMO CORPO CAPITULO PARA LISTA ITEM REALCADO FIGURA GRAFICO EXEMPLO FECHO AGRADECIMENTOS BIBLIOGRAFIA BIBITEM CHAVE PUB REF CODPROGRAMA SECCAO '<' '>' '=' '/'

%type <grv> PLIdoc Abertura Titulo Data AutorList Autor EUa EUb Nome Resumo Corpo Fecho Agradecimentos Bibliografia BibItemList BibItem Chave Pub CapList Capitulo ConteudoList Conteudo Seccao ParaList Para ParaConteudoList ParaConteudo Comando Realcado Ref Figura Grafico CodPrograma Lista ListaItem Item Exemplo ExemploConteudoList ExemploConteudo Text

%%

PLIdoc      : '<' PLI_DOC AttrList '>' Abertura Corpo Fecho '<' '/' PLI_DOC '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = ginsert(ginsert($5, $6), $7);

{

      int ex = 0;

      list *l;

 

      if (unrefs) {

            l = unrefs;

            while (l) {

                  fprintf(stderr, "Error: Undefined Reference: '%s' at line %d.\n", l->value, l->line);

                  l = l->next;

            }

            ex = 1;

      }

      l = refs;

      while (l) {

            if (!l->used) {

                  fprintf(stderr, "Warning: Unreferenced ID: '%s', defined at line %d.\n", l->value, l->line);

            }

            l = l->next;

      }

      if (ex) exit(1);

}

      start($$);

}

      ;

Abertura: '<' ABERTURA AttrList '>' Titulo Data AutorList Resumo '<' '/' ABERTURA '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = ginsert(ginsert(ginsert($5, $6), $7), $8);

}

      ;

Titulo      : '<' TITULO AttrList '>' Text '<' '/' TITULO '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = $5;

}

      ;

Data  : '<' DATA AttrList '>' Text '<' '/' DATA '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = $5;

}

      ;

AutorList: AutorList Autor {

      $$ = ginsert($1, $2);

}

      | { $$ = NULL; }

      ;

Autor : '<' AUTOR AttrList '>' Nome '<' EUa {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = $5;

      $$->sub->next = $7;

}

      ;

EUa   : EMAIL AttrList '>' Text '<' '/' EMAIL '>' '<' EUb '/' AUTOR '>' {

      $$ = gnew();

      $$->class = $1;

      $$->ids = $2;

      $$->sub = $4;

      $$->next = $10;

}

      | URL AttrList '>' Text '<' '/' URL '>' '<' '/' AUTOR '>' {

      $$ = gnew();

      $$->class = $1;

      $$->ids = $2;

      $$->sub = $4;

}

      | '/' AUTOR '>' {

      $$ = NULL;

}

      ;

EUb   : URL AttrList '>' Text '<' '/' URL '>' '<' {

      $$ = gnew();

      $$->class = $1;

      $$->ids = $2;

      $$->sub = $4;

}

      | { $$ = NULL; }

      ;

Nome  : '<' NOME AttrList '>' Text '<' '/' NOME '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = $5;

}

      ;

Resumo      : '<' RESUMO AttrList '>' ParaList '<' '/' RESUMO '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = $5;

}

      ;

Corpo : '<' CORPO AttrList '>' CapList '<' '/' CORPO '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = $5;

}

      ;

Fecho : '<' FECHO AttrList '>' Agradecimentos Bibliografia '<' '/' FECHO '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = ginsert($5, $6);

}

      ;

Agradecimentos: '<' AGRADECIMENTOS AttrList '>' ParaList '<' '/' AGRADECIMENTOS '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = $5;

}

      ;

Bibliografia: '<' BIBLIOGRAFIA AttrList '>' BibItemList '<' '/' BIBLIOGRAFIA '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = $5;

}

      ;

BibItemList: BibItemList BibItem {

      $$ = ginsert($1, $2);

}

      | { $$ = NULL; }

      ;

BibItem     : '<' BIBITEM AttrList '>' Chave Pub '<' '/' BIBITEM '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = ginsert($5, $6);

{

      struct id *l, *t;

 

      l = $3;

      while (l) {

            if (strcmp(l->id, "ID") == 0) {

                  t = attrnew();

                  t->id = l->value;

                  t->value = $5->sub->text;

                  t->next = rftrans;

                  rftrans = t;

            }

            l = l->next;

      }

}

}

      ;

Chave : '<' CHAVE AttrList '>' Text '<' '/' CHAVE '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = $5;

}

      ;

Pub   : '<' PUB AttrList '>' Text '<' '/' PUB '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = $5;

}

      ;

CapList     : CapList Capitulo {

      $$ = ginsert($1, $2);

}

      | { $$ = NULL; }

      ;

Capitulo: '<' CAPITULO AttrList '>' Titulo ConteudoList '<' '/' CAPITULO '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = ginsert($5, $6);

}

      ;

ConteudoList: ConteudoList Conteudo {

      $$ = ginsert($1, $2);

}

      | { $$ = NULL; }

      ;

Conteudo: Para { $$ = $1; }

      | Seccao { $$ = $1; }

      | Exemplo { $$ = $1; }

      | Figura { $$ = $1; }

      | Lista { $$ = $1; }

      | CodPrograma { $$ = $1; }

      ;

Seccao      : '<' SECCAO AttrList '>' Titulo ConteudoList '<' '/' SECCAO '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = ginsert($5, $6);

}

      ;

ParaList: ParaList Para {

      $$ = ginsert($1, $2);

}

      | { $$ = NULL; }

      ;

Para  : '<' PARA AttrList '>' ParaConteudoList '<' '/' PARA '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = $5;

}

      ;

ParaConteudoList: ParaConteudoList ParaConteudo {

      $$ = ginsert($1, $2);

}

      | { $$ = NULL; }

      ;

ParaConteudo: Text { $$ = $1; }

      | Comando { $$ = $1; }

      | Realcado { $$ = $1; }

      | Ref { $$ = $1; }

      ;

Comando     : '<' COMANDO AttrList '>' Text '<' '/' COMANDO '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = $5;

}

      ;

Realcado: '<' REALCADO AttrList '>' Text '<' '/' REALCADO '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = $5;

}

      ;

Ref   : '<' REF AttrList '/' '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

}

      ;

Figura      : '<' FIGURA AttrList '>' Titulo Grafico '<' '/' FIGURA '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = ginsert($5, $6);

}

      ;

Grafico     : '<' GRAFICO AttrList '/' '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

}

      ;

CodPrograma: '<' CODPROGRAMA AttrList '>' Text '<' '/' CODPROGRAMA '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = $5;

}

      ;

Lista : '<' LISTA AttrList '>' ListaItem '<' '/' LISTA '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = $5;

}

      ;

ListaItem: ListaItem Item {

      $$ = ginsert($1, $2);

}

      | { $$ = NULL; }

      ;

Item  : '<' ITEM AttrList '>' ParaList '<' '/' ITEM '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = $5;

}

      ;

Exemplo     : '<' EXEMPLO AttrList '>' Titulo ExemploConteudoList '<' '/' EXEMPLO '>' {

      $$ = gnew();

      $$->class = $2;

      $$->ids = $3;

      $$->sub = ginsert($5, $6);

}

      ;

ExemploConteudoList: ExemploConteudoList ExemploConteudo {

      $$ = ginsert($1, $2);

}

      | { $$ = NULL; }

      ;

ExemploConteudo: Para { $$ = $1; }

      | Figura { $$ = $1; }

      | CodPrograma { $$ = $1; }

      ;

AttrList: AttrList Attr {

      $$ = attrinsert($1, $2);

}

      | { $$ = NULL; }

      ;

Attr  : ID '=' VALOR {

      $$ = attrnew();

      $$->id = $1;

      $$->value = $3;

      if (!strcmp($1, "ID")) {

            list *l;

 

            if ((l = lisin(refs, $3))) {

                  fprintf(stderr, "Line %d: Redifinition of ID '%s'. Previously defined at line %d.\n", nlines, $3, l->line);

                  exit(1);

            }

            refs = ladd(refs, $3, nlines);

            if (lisin(unrefs, $3)) {

                  refs->used = 1;

                  unrefs = lrem(unrefs, $3);

            }

      } else if (!strcmp($1, "IDREF")) {

            list *l;

 

            if ((l = lisin(refs, $3))) {

                  l->used = 1;

            } else {

                  if (!lisin(unrefs, $3))

                        unrefs = ladd(unrefs, $3, nlines);

            }

      }

}

 

Text: TEXT {

      $$ = gnew();

      $$->class = TEXT;

      $$->text = $1;

}

%%

#define YY_DECL int _yylex(void)

#include "lex.yy.c"

 

int tok;

 

int yylex(void) {

 

      return tok = _yylex();

}

 

int main(int argc, char *argv[]) {

 

      chkargs(argc, argv);

      yyparse();

      return 0;

}

 

char *tokname(int t) {

      char *res;

      static char b[40];

 

      switch (t) {

      case '<': res = "'<'";

            break;

      case '>': res = "'>'";

            break;

      case '=': res = "'='";

            break;

      case ID: res = "ID";

            break;

      case VALOR: res = "VALOR";

            break;

      case '/': res = "'/'";

            break;

      case TEXT: res = "TEXT";

            break;

      case PLI_DOC: res = "PLI_DOC";

            break;

      case COMANDO: res = "COMANDO";

            break;

      case ABERTURA: res = "ABERTURA";

            break;

      case TITULO: res = "TITULO";

            break;

      case DATA: res = "DATA";

            break;

      case AUTOR: res = "AUTOR";

            break;

      case NOME: res = "NOME";

            break;

      case EMAIL: res = "EMAIL";

            break;

      case URL: res = "URL";

            break;

      case RESUMO: res = "RESUMO";

            break;

      case CORPO: res = "CORPO";

            break;

      case CAPITULO: res = "CAPITULO";

            break;

      case PARA: res = "PARA";

            break;

      case LISTA: res = "LISTA";

            break;

      case ITEM: res = "ITEM";

            break;

      case REALCADO: res = "REALCADO";

            break;

      case FIGURA: res = "FIGURA";

            break;

      case GRAFICO: res = "GRAFICO";

            break;

      case EXEMPLO: res = "EXEMPLO";

            break;

      case FECHO: res = "FECHO";

            break;

      case AGRADECIMENTOS: res = "AGRADECIMENTOS";

            break;

      case BIBLIOGRAFIA: res = "BIBLIOGRAFIA";

            break;

      case BIBITEM: res = "BIBITEM";

            break;

      case CHAVE: res = "CHAVE";

            break;

      case PUB: res = "PUB";

            break;

      case REF: res = "REF";

            break;

      case CODPROGRAMA: res = "CODPROGRAMA";

            break;

      case SECCAO: res = "SECCAO";

            break;

      default: res = b;

             snprintf(b, 39, "unknown(%d)", t);

             b[39] = '\0';

      }

      return res;

}

 

 

int yyerror(char *s) {

 

      printf("Line %d: unexpected token '%s': %s\n", nlines, tokname(tok), s);

      return 0;

}

 

char htmlt[] = "-html";

char latext[] = "-latex";

char grovet[] = "-grove";

 

char *lower(char *s) {

      static char b[80];

      int i;

 

      i = 0;

      while (*s && i < 79) {

            b[i++] = tolower(*s);

            ++s;

      }

      b[i] = '\0';

      return b;

}

 

void pli_doc2txt(struct grove *g) {

 

      printf("%s ", lower(tokname(g->class)));

      if (g->sub) {

            printf("< ");

            pli_doc2txt(g->sub);

            printf("> ");

      }

      if (g->class == PLI_DOC) puts("");

      if (g->next) pli_doc2txt(g->next);

}

 

void chkargs(int argc, char **argv) {

 

      if (argc > 2) {

            fprintf(stderr, "Invalid use.\n%s [-latex|-html|-grove]\ndefault: -html.\n", *argv);

            exit(1);

      }

      if (argc == 1 || strstr(htmlt, argv[1]) == htmlt) {

            start = pli_doc2html;

      } else if (strstr(latext, argv[1]) == latext) {

            start = pli_doc2latex;

      } else if (strstr(grovet, argv[1]) == grovet) {

            start = pli_doc2txt;

      } else {

            fprintf(stderr, "Invalid use.\n%s [-latex|-html|-grove]\ndefault: -html.\n", *argv);

            exit(1);

      }

}

 

 

 

grove.h

 

#ifndef _GROVE_H

#define _GROVE_H

 

struct id {

      char *id;

      char *value;

      struct id *next;

};

 

struct grove {

      int class;

      char *text;

      struct id *ids;

      struct grove *sub;

      struct grove *next;

};

 

typedef void (*crsf)(struct grove *);

 

struct grove_crs {

      int class;

      crsf f;

};

 

typedef struct grove_crs trans[];

 

/* Grove general functions */

struct grove *gnew(void);

struct grove *ginsert(struct grove *g, struct grove *e);

struct id *attrnew(void);

struct id *attrinsert(struct id *, struct id *);

 

#endif /* _GROVE_H */

 

grove.c

 

#include <stdio.h>

#include <stdlib.h>

#include <strings.h>

 

#include "grove.h"

 

/* Grove general functions */

struct grove *gnew(void) {

      struct grove *n;

 

      n = calloc(1, sizeof(struct grove));

      return n;

}

 

struct grove *ginsert(struct grove *g, struct grove *e) {

      struct grove *r;

 

      if (g == NULL) r = e;

      else {

            r = g;

            while (g->next) g = g->next;

            g->next = e;

      }

      return r;

}

 

struct id *attrnew(void) {

      struct id *n;

 

      n = calloc(1, sizeof(struct id));

      return n;

}

 

struct id *attrinsert(struct id *i, struct id *e) {

      struct id *r;

 

      if (i == NULL) r = e;

      else {

            r = i;

            while (i->next) i = i->next;

            i->next = e;

      }

      return r;

}

 

 

grovehtml.h

 

#ifndef _GROVEHTML_H

#define _GROVEHTML_H

 

#include "grove.h"

 

void pli_doc2html(struct grove *);

 

#endif /* _GROVEHTML_H */

           

grovelatex.h

 

#ifndef _GROVELATEX_H

#define _GROVELATEX_H

 

#include "grove.h"

 

void pli_doc2latex(struct grove *);

 

#endif /* _GROVELATEX_H */

 

 

grovehtml.c

 

#include <stdio.h>

#include <strings.h>

#include <stdlib.h>

#include <ctype.h>

 

#include "grove.h"

#include "y.tab.h"

 

static crsf gfunc(int);

 

#define SUB(g) at = g->class; if ((g)->sub) gfunc((g)->sub->class)((g)->sub)

#define NEXT(g) if ((g)->next) gfunc((g)->next->class)((g)->next)

 

#define SECS 10

#define BOLD 'B'

#define ITAL 'I'

#define SC 'S'

 

int fig, ex, at, cap, nsec;

int sec[SECS];

char *bib_id;

extern struct id *rftrans;

 

void set_ids(struct id *list) {

 

      while (list) {

            if (strcmp(list->id, "ID") == 0) {

                  printf("<a name=\"%s\"></a>", list->value);

            }

            list = list->next;

      }

}

 

void text2html(struct grove *g) {

 

      printf("%s", g->text);

      NEXT(g);

}

 

void sctext2html(struct grove *g) {

      char *s;

      int u;

 

      if (!g) return;

      if (g->class != TEXT) {

            gfunc(g->class)(g);

            return;

      }

      if ((s = g->text)) {

            u = 1;

            while (*s) {

                  if (isupper(*s)) {

                        if (u) putchar(*s);

                        else {

                              printf("</SMALL>%c", *s);

                              u = 1;

                        }

                  } else {

                        if (u) {

                              printf("<SMALL>%c", toupper(*s));

                              u = 0;

                        } else putchar(toupper(*s));

                  }

                  ++s;

            }

      }

      sctext2html(g->next);

}

 

void pli_doc2html(struct grove *g) {

 

      printf("<HTML>\n");

      set_ids(g->ids);

      fig = ex = 0;

      SUB(g);

      printf("</HTML>\n");

      NEXT(g);

}

 

void comando2html(struct grove *g) {

 

      printf("<TT>");

      set_ids(g->ids);

      SUB(g);

      printf("</TT>\n");

      NEXT(g);

}

 

void abertura2html(struct grove *g) {

 

      printf("<HEAD>\n");

      set_ids(g->ids);

      SUB(g);

      printf("</HEAD>\n");

      NEXT(g);

}

 

void titulo2html(struct grove *g) {

 

      switch (at) {

      case ABERTURA:

            printf("<TITLE>");

            set_ids(g->ids);

            SUB(g);

            printf("</TITLE>\n");

            printf("<H1 align=\"center\">");

            SUB(g);

            printf("</H1>");

            break;

      case CAPITULO:

            printf("<H2 align=\"center\">%d - ", cap);

            set_ids(g->ids);

            SUB(g);

            printf("</H2>\n");

            break;

      case SECCAO:

            printf("<H3 align=\"left\">%d", cap);

            { int i;

              for (i = 0; i < nsec; ++i) printf(".%d", sec[i]);

            }

            printf(" - ", cap);

            set_ids(g->ids);

            SUB(g);

            printf("</H3>\n");

            break;

      case FIGURA:

            set_ids(g->ids);

            SUB(g);

            printf("\" SRC=\"");

            NEXT(g);

            printf("\"><BR>%d. ", fig);

            SUB(g);

            printf("</P><P>\n");

            return;

      case EXEMPLO:

            printf("<strong>");

            set_ids(g->ids);

            SUB(g);

            printf("</strong><P>");

            break;

      default:

            printf("<H3>");

            set_ids(g->ids);

            SUB(g);

            printf("</H3>\n");

      }

      NEXT(g);

}

 

void data2html(struct grove *g) {

 

      set_ids(g->ids);

      printf("<META name=\"Data\" content=\"");

      SUB(g);

      printf("\">");

      printf("$Data: ");

      SUB(g);

      printf(" $\n");

      NEXT(g);

}

 

void autor2html(struct grove *g) {

 

      printf("<ADDRESS>\n");

      set_ids(g->ids);

      printf("Autor: ");

      SUB(g);

      printf("</ADDRESS>\n");

      NEXT(g);

}

 

void nome2html(struct grove *g) {

 

      printf("<STRONG>");

      set_ids(g->ids);

      SUB(g);

      printf("</STRONG>");

      NEXT(g);

}

 

void email2html(struct grove *g) {

 

      set_ids(g->ids);

      printf(", <A HREF=\"mailto:");

      gfunc(g->sub->class)(g->sub);

      printf("\">");

      gfunc(g->sub->class)(g->sub);

      printf("</A>");

      NEXT(g);

}

 

void url2html(struct grove *g) {

 

      set_ids(g->ids);

      printf(", <A HREF=\"http://");

      gfunc(g->sub->class)(g->sub);

      printf("\">");

      gfunc(g->sub->class)(g->sub);

      printf("</A>");

      NEXT(g);

}

 

void resumo2html(struct grove *g) {

 

      printf("<H2>Resumo</H2>\n");

      set_ids(g->ids);

      SUB(g);

      NEXT(g);

}

 

void corpo2html(struct grove *g) {

 

      set_ids(g->ids);

      printf("<HR><HR>");

      printf("<BODY>\n");

      cap = 0;

      SUB(g);

      printf("</BODY>\n");

      NEXT(g);

}

 

void capitulo2html(struct grove *g) {

 

      bzero(sec, sizeof(int) * SECS);

      printf("<BR>\n");

      set_ids(g->ids);

      ++cap;

      nsec = 0;

      SUB(g);

      printf("<BR>\n");

      NEXT(g);

}

 

void para2html(struct grove *g) {

 

      SUB(g);

      printf("<P>\n");

      set_ids(g->ids);

      NEXT(g);

}

 

void lista2html(struct grove *g) {

char *s;

      struct id *l;

 

      s = "UL";

      l = g->ids;

      while (l && (strcmp(l->id, "TIPO") || strcmp(l->value, "NUMERADA")))

             l = l->next;

      if (l) s = "OL";

      set_ids(g->ids);

      printf("<%s>", s);

      SUB(g);

      printf("</%s>", s);

      NEXT(g);

}

 

void item2html(struct grove *g) {

 

      set_ids(g->ids);

      printf("<LI>");

      SUB(g);

      NEXT(g);

}

 

void realcado2html(struct grove *g) {

      struct id *l;

      char type = 0;

 

      set_ids(g->ids);

      l = g->ids;

      while (l) {

            if (strcmp(l->id, "ESTILO") == 0) {

                  if (type) {

                        fprintf(stderr, "Warning: Ignored Redefinition of ESTILO: '%s'.\n", l->value);

                  } else if (strcmp(l->value, "BOLD") == 0) {

                        type = BOLD;

                  } else if (strcmp(l->value, "ITALICO") == 0) {

                        type = ITAL;

                  } else if (strcmp(l->value, "SC") == 0) {

                        type = SC;

                  } else {

                        fprintf(stderr, "Warning: Unknown ESTILO '%s'. Defaulting to BOLD.\n", l->value);

                  }

            }

            l = l->next;

      }

      if (!type) type = BOLD;

      if (type == SC) {

            sctext2html(g->sub);

      } else {

            printf("<%c>", type);

            SUB(g);

            printf("</%c>", type);

      }

      NEXT(g);

}

 

void figura2html(struct grove *g) {

 

      ++fig;

      set_ids(g->ids);

      printf("<P ALIGN=\"center\"><IMG ALT=\"");

      SUB(g);

      NEXT(g);

}

 

void grafico2html(struct grove *g) {

      struct id *l;

      char *s;

 

      set_ids(g->ids);

      s = NULL;

      l = g->ids;

      while (l) {

            if (strcmp(l->id, "LOCAL") == 0) {

                  if (s) fprintf(stderr, "Warning: LOCAL of figure redefined: '%s'.\n", l->value);

                  else s = l->value;

            }

            l = l->next;

      }

      if (!s) {

            fprintf(stderr, "Warning: No definition of LOCAL.\n");

            printf("null.gif");

      }

      fputs(s, stdout);

      NEXT(g);

}

 

void exemplo2html(struct grove *g) {

 

      printf("<hr>");

      set_ids(g->ids);

      SUB(g);

      printf("<hr>");

      printf("<H6 ALIGN=\"right\">Exemplo %d</H6>", ++ex);

      NEXT(g);

}

 

void fecho2html(struct grove *g) {

 

      printf("<HR><HR>");

      set_ids(g->ids);

      SUB(g);

      NEXT(g);

}

 

void agradecimentos2html(struct grove *g) {

 

      printf("<H2>Agradecimentos</H2>\n");

      set_ids(g->ids);

      SUB(g);

      NEXT(g);

}

 

void bibliografia2html(struct grove *g) {

 

      printf("<BR><H2>Bibliografia</H2>\n");

      set_ids(g->ids);

      SUB(g);

      NEXT(g);

}

 

void bibitem2html(struct grove *g) {

      struct id *l;

 

      bib_id = NULL;

      l = g->ids;

      while (l && !bib_id) {

            if (strcmp(l->id, "ID") == 0) {

                  bib_id = l->value;

            }

            l = l->next;

      }

      printf("<DL>");

      SUB(g);

        printf("</DL>");

      NEXT(g);

}

 

void chave2html(struct grove *g) {

 

      printf("<DT>");

      set_ids(g->ids);

      if (bib_id) {

            printf("<A NAME=\"%s\">", bib_id);

            SUB(g);

            printf("</A>");

      } else {

            SUB(g);

      }

      printf("</DT>");

      NEXT(g);

}

 

void pub2html(struct grove *g) {

 

      printf("<DD><CITE>");

      set_ids(g->ids);

      SUB(g);

      printf("</CITE></DD>");

      NEXT(g);

}

 

void ref2html(struct grove *g) {

      struct id *l;

      char *r, *n;

 

      set_ids(g->ids);

      l = g->ids;

      r = NULL;

      while (l) {

            if (strcmp(l->id, "IDREF") == 0) {

                  if (r) {

                        fprintf(stderr, "Warning: Redifiniton of reference location: '%s'. Previos: '%s'.\n", l->value, r);

                  } else {

                        r = l->value;

                  }

            }

            l = l->next;

      }

      if (!r) {

            fprintf(stderr, "Warning: Referencing nothing.\n");

      } else {

            l = rftrans;

            n = r;

            while (l && strcmp(l->id, r)) l = l->next;

            if (l) n = l->value;

            printf("<a href=\"#%s\">%s</a>", r, n);

      }

      NEXT(g);

}

 

void codprograma2html(struct grove *g) {

 

      printf("<PRE>\n");

      set_ids(g->ids);

      SUB(g);

      printf("</PRE>\n");

      NEXT(g);

}

 

void seccao2html(struct grove *g) {

      int i;

 

      set_ids(g->ids);

      sec[nsec++]++;

      for (i = nsec + 1; i < SECS; ++i) {

            sec[i] = '\0';

      }

      SUB(g);

      --nsec;

      NEXT(g);

}

 

trans htmlf = {

      { TEXT, text2html },

      { PLI_DOC, pli_doc2html },

      { COMANDO, comando2html },

      { ABERTURA, abertura2html },

      { TITULO, titulo2html },

      { DATA, data2html },

      { AUTOR, autor2html },

      { NOME, nome2html },

      { EMAIL, email2html },

      { URL, url2html },

      { RESUMO, resumo2html },

      { CORPO, corpo2html },

      { CAPITULO, capitulo2html },

      { PARA, para2html },

      { LISTA, lista2html },

      { ITEM, item2html },

      { REALCADO, realcado2html },

      { FIGURA, figura2html },

      { GRAFICO, grafico2html },

      { EXEMPLO, exemplo2html },

      { FECHO, fecho2html },

      { AGRADECIMENTOS, agradecimentos2html },

      { BIBLIOGRAFIA, bibliografia2html },

      { BIBITEM, bibitem2html },

      { CHAVE, chave2html },

      { PUB, pub2html },

      { REF, ref2html },

      { CODPROGRAMA, codprograma2html },

      { SECCAO, seccao2html },

      { -1, NULL }

};

 

static crsf gfunc(int class) {

      int i;

 

      if (htmlf[class - TEXT].class == class)

            return htmlf[class - TEXT].f;

      i = 0;

      while (htmlf[i].class >= 0 && htmlf[i].class != class) ++i;

      return htmlf[i].f;

}

 

 

grovelatex.c

 

#include <stdio.h>

#include <strings.h>

#include <stdlib.h>

 

#include "grove.h"

#include "y.tab.h"

 

static crsf gfunc(int);

 

#define TXT(g) ((g)->text ? (g)->text : "")

 

#define PRN(g)

 

void text2latex(struct grove *g) {

 

      PRN(g);

}

 

void pli_doc2latex(struct grove *g) {

 

      PRN(g);

      puts("");

}

 

void comando2latex(struct grove *g) {

 

      PRN(g);

}

 

void abertura2latex(struct grove *g) {

 

      PRN(g);

}

 

void titulo2latex(struct grove *g) {

 

      PRN(g);

}

 

void data2latex(struct grove *g) {

 

      PRN(g);

}

 

void autor2latex(struct grove *g) {

 

      PRN(g);

}

 

void nome2latex(struct grove *g) {

 

      PRN(g);

}

 

void email2latex(struct grove *g) {

 

      PRN(g);

}

 

void url2latex(struct grove *g) {

 

      PRN(g);

}

 

void resumo2latex(struct grove *g) {

 

      PRN(g);

}

 

void corpo2latex(struct grove *g) {

 

      PRN(g);

}

 

void capitulo2latex(struct grove *g) {

 

      PRN(g);

}

 

void para2latex(struct grove *g) {

 

      PRN(g);

}

 

void lista2latex(struct grove *g) {

 

      PRN(g);

}

 

void item2latex(struct grove *g) {

 

      PRN(g);

}

 

void realcado2latex(struct grove *g) {

 

      PRN(g);

}

 

void figura2latex(struct grove *g) {

 

      PRN(g);

}

 

void grafico2latex(struct grove *g) {

 

      PRN(g);

}

 

void exemplo2latex(struct grove *g) {

 

      PRN(g);

}

 

void fecho2latex(struct grove *g) {

 

      PRN(g);

}

 

void agradecimentos2latex(struct grove *g) {

 

      PRN(g);

}

 

void bibliografia2latex(struct grove *g) {

 

      PRN(g);

}

 

void bibitem2latex(struct grove *g) {

 

      PRN(g);

}

 

void chave2latex(struct grove *g) {

 

      PRN(g);

}

 

void pub2latex(struct grove *g) {

 

      PRN(g);

}

 

void ref2latex(struct grove *g) {

 

      PRN(g);

}

 

void codprograma2latex(struct grove *g) {

 

      PRN(g);

}

 

void seccao2latex(struct grove *g) {

 

      PRN(g);

}

 

trans latexf = {

      { TEXT, text2latex },

      { PLI_DOC, pli_doc2latex },

      { COMANDO, comando2latex },

      { ABERTURA, abertura2latex },

      { TITULO, titulo2latex },

      { DATA, data2latex },

      { AUTOR, autor2latex },

      { NOME, nome2latex },

      { EMAIL, email2latex },

      { URL, url2latex },

      { RESUMO, resumo2latex },

      { CORPO, corpo2latex },

      { CAPITULO, capitulo2latex },

      { PARA, para2latex },

      { LISTA, lista2latex },

      { ITEM, item2latex },

      { REALCADO, realcado2latex },

      { FIGURA, figura2latex },

      { GRAFICO, grafico2latex },

      { EXEMPLO, exemplo2latex },

      { FECHO, fecho2latex },

      { AGRADECIMENTOS, agradecimentos2latex },

      { BIBLIOGRAFIA, bibliografia2latex },

      { BIBITEM, bibitem2latex },

      { CHAVE, chave2latex },

      { PUB, pub2latex },

      { REF, ref2latex },

      { CODPROGRAMA, codprograma2latex },

      { SECCAO, seccao2latex }

};

 

static crsf gfunc(int class) {

      int i;

 

      if (latexf[class - TEXT].class == class)

            return latexf[class - TEXT].f;

      i = 0;

      while (latexf[i].class >= 0 && latexf[i].class != class) ++i;

      return latexf[i].f;

}

 

 

 

list.h

 

#ifndef _LIST_H

#define _LIST_H

 

typedef struct _list {

      char *value;

      int line, used;

      struct _list *next;

} list;

 

list *lisin(list *, char *);

list *ladd(list *, char *, int);

list *lrem(list *, char *);

 

#endif

 

list.c

 

#include <stdlib.h>

#include "list.h"

 

list *lisin(list *l, char *v) {

 

      while (l && strcmp(l->value, v))

            l = l->next;

      return l;

}

 

list *ladd(list *l, char *v, int line) {

      list *n;

 

      if ((n = (list *) malloc(sizeof(list)))) {

            n->used = 0;

            n->value = v;

            n->line = line;

            n->next = l;

            l = n;

      }

      return l;

}

 

list *lrem(list *l, char *v) {

      list *r, *t;

 

      if ((r = l)) {

            if (!strcmp(l->value, v)) {

                  r = l->next;

                  free(l);

            } else {

                  while (l->next && strcmp(l->next->value, v))

                        l = l->next;

                  if (l->next) {

                        t = l->next;

                        l->next = t->next;

                        free(t);

                  }

            }

      }

      return r;

}

 


        Diagrama Genérico do Grove

            Abertura

           
            Corpo

           
            Fecho


Diagrama do Grove Resultante do Documento Exemplo

            Abertura

           
            Corpo

           
            Fecho