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____________________________________________________________________________ 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
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.
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.
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.
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.
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.
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-á....
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 > > > > >
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.
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 *
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;
}
%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);
}
}
#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 */
#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;
}
#ifndef
_GROVEHTML_H
#define
_GROVEHTML_H
#include
"grove.h"
void
pli_doc2html(struct grove *);
#endif /* _GROVEHTML_H */
#ifndef _GROVELATEX_H
#define _GROVELATEX_H
#include
"grove.h"
void
pli_doc2latex(struct grove *);
#endif
/* _GROVELATEX_H */
#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;
}
#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;
}
#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
#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;
}