Neste capítulo apresenta-se uma solução baseada em gramáticas de atributos para o problema da definição e processamento de restrições semânticas.
Quando se analisou mais profundamente a semelhança entre o processamento de documentos estruturados e o processamento de linguagens de programação, surgiu a ideia de se utilizar uma ferramenta de geração automática de compiladores com o objectivo de gerar editores SGML específicos. Esta ideia evoluiu um pouco mais e o resultado final é o sistema S4.
O sistema S4 é um ambiente integrado para a programação de documentos. Uma das facilidades integradas no sistema é a possibilidade de definição e processamento de restrições (o problema que se tem vindo a perseguir). Mas além desta, inclui outras como a integração de uma sintaxe mais ligeira que o DSSSL para a especificação de estilos. O produto final pode resumir-se dizendo que é um gerador de editores estruturados baseados em SGML com possibilidade de definir e processar restrições semânticas e com a possibilidade de acoplar uma especificação de estilo que fará com que o editor gerado produza automaticamente vistas do documento com o conteúdo transformado, ou formatado.
Nas próximas secções e após uma introdução teórica que suporta a abordagem seguida, apresentar-se-á o sistema S4 e serão discutidos os vários pormenores da sua implementação.
As operações que normalmente se fazem com documentos incluem: tradução, formatação do conteúdo, transformação, interpretação, acesso e recuperação de partes relevantes da informação contida no documento. Olhando para esta lista de operações, mais uma vez, o paralelismo entre o processamento de documentos e o processamento de linguagens formais emerge (ver a hipótese formulada previamente na (Secção 6.1):
para todas estas operações é necessário um primeiro passo de reconhecimento e criação de uma representação intermédia - regra geral corresponde a uma análise léxica e uma análise sintáctica; no caso dos documentos SGML são realizadas pelo parser genérico de SGML; no caso das linguagens é também realizado pelo parser específico de cada linguagem.
a interpretação corresponde a uma análise semântica que é feita após as duas primeiras.
a tradução e a formatação correspondem a travessias da representação intermédia - quer num caso quer no outro têm de ser programadas de acordo com o objectivo final pretendido.
o acesso e recuperação de partes correspondem a travessias da representação intermédia com filtragem de componentes - no caso dos documentos SGML correspondem à realização de uma query; nas linguagens, em termos de funcionalidade, corresponderá parcialmente à optimização do código gerado.
Nesta secção, vai-se aplicar ao processamento documental uma técnica que já se vem aplicando no processamento de algumas linguagens formais. Nesta abordagem, a semântica de um documento será representada através de uma Árvore de Sintaxe Abstracta Decorada (ASAD). Uma ASAD é formalmente especificada por uma gramática de atributos. O objectivo é demonstrar que esta aproximação tem capacidade para representar os documentos SGML com todas as restrições possíveis de expressar num DTD e que um sistema SGML tradicional automaticamente valida. Só depois se discutirá a possibilidade de acrescentar restrições semânticas extra SGML mas relacionadas com o conteúdo do documento em causa.
A notação relativa às gramáticas de atributos que irá ser usada ao longo deste capítulo, nas especificações sintácticas e semânticas dos exemplos, foi já devidamente apresentada num dos primeiros capítulos (Capítulo 2). Nas partes mais específicas e relacionadas com a implementação, é utilizada a linguagem SSL - "Synthesizer Specification Language", também introduzida numa secção do referido capítulo (Secção 2.1.2).
O primeiro passo para a construção desta representação semântica de documentos é a concepção da Gramática Independente de Contexto (GIC) que lhe servirá de base. É sempre possível derivar uma GIC sistematicamente, até mesmo automaticamente, partindo do DTD. A tabela seguinte, Tabela 9-1, apresenta um primeiro esboço de um esquema de tradução entre os dois formalismos.
Tabela 9-1. Esquema de Tradução SGML ↔ Gramáticas de Atributos
SGML | Gramáticas de Atributos |
---|---|
x,y | Z → X Y |
x & y | Z → X Y | Y X |
x | y | Z → X | Y |
x* | Z → X Z | &egr; |
x+ | Z → X Z | X |
x? | Z → X | &egr; |
A GIC que se segue foi obtida sistematicamente a partir do DTD apresentado para o tipo de documentos literate programming (Exemplo 8-1).
Exemplo 9-1. GIC derivada do DTD de Literate Programming
p1: litprog → "<litprog>" X "</litprog>" p1.1..p1.3: X → TEXTO X | prog X | def X p1.4..p1.6: | id X | sec X | tit X p1.7: | p2: prog → "<prog>" Y "</prog>" p2.1..p2.2: Y → TEXTO Y | id Y p2.3: | p3: def → "<def ident=" ID ">" prog "</def>" p4: sec → "<sec>" TEXTO "</sec>" p5: tit → "<tit>" TEXTO "</tit>" p6: id → "<id refid=" ID "></id>"
Depois de se obter a GIC, o passo seguinte consiste na associação de atributos aos símbolos da GIC e na escrita das respectivas regras de cálculo (no contexto de cada regra de derivação).
A introdução de atributos vai permitir duas coisas: por um lado, expressar as condições de contexto necessárias para restringir o conjunto de frases válidas (predicados que têm de ser verificados no contexto de algumas produções); por outro lado, transportar através dos atributos toda a restante informação não estrutural que é inferida do documento, directa ou indirectamente e que é necessária para realizar a transformação do documento. No primeiro caso, o objectivo é a definição da semântica estática e, no segundo, a definição da semântica dinâmica.
Os atributos correspondentes à semântica estática são facilmente deriváveis a partir das cláusulas ATTLIST presentes no DTD.
Considerando de novo o caso de estudo que se tem vindo a desenvolver, a derivação dos seguintes atributos (associados aos símbolos def e id) é imediata:
def: syn {ident: word} id: syn {refid: word}
Aos quais se associam as seguintes regras de cálculo:
p3: def → "<def ident=" ID ">" prog "</def>" ident(def) = lexval(ID) p6: id → "<id refid=" ID ">" refid(id) = lexval(ID)
Assumiu-se que cada símbolo terminal (no exemplo apresentado, ID e TEXTO) tem um atributo intrínseco chamado lexval (valor léxico) do tipo word.
A única restrição de contexto que é preciso especificar, para este exemplo, diz respeito à validação de atributos do tipo ID e IDREF que um parser SGML faz [1]: cada valor do tipo ID só aparece instanciado uma vez e cada valor do tipo IDREF deve corresponder a um valor do tipo ID definido algures no documento. Assim, para este caso, definiram-se as seguintes condições de contexto:
p3: def → "<def ident=" ID ">" prog "</def>" CC: not exists( ident(def), itab(def) ) p6: id → "<id refid=" ID ">" CC: exists( refid(id), itab(id) )
Para escrever estas condições de contexto, houve necessidade de associar aos símbolos def e id um atributo herdado, itab. Este atributo faz o papel de uma tabela de símbolos, que vai registando os identificadores que são definidos ao longo do documento e que é consultada sempre que um identificador é referenciado. Para manter esta tabela actualizada é ainda necessário acrescentar os seguintes atributos, cuja semântica é explicada mais à frente:
def: inh {itab: IdentTAB} syn {pros: PEleList} id: inh {itab: IdentTAB} X: inh {itab: IdentTAB} syn {stab: IdentTAB} prog: syn {pros: PEleList}
Com as seguintes regras de cálculo:
p3: def → "<def ident=" ID ">" prog "</def>" pros(def) = pros(prog) p1.3: X → def X itab(def) = itab(X0) itab(X1) = actualiza( itab(X0), ident(def), pros(def) ) stab(X0) = stab(X1) p1.4: X → id X itab(id) = itab(X0) itab(X1) = itab(X0) stab(X0) = stab(X1)
Uma das diferenças entre esta abordagem e a anterior via modelos abstractos pode ser observada quando se compara as duas especificações. Na abordagem por modelos abstractos, as especificações da construção e do processamento são feitas separadamente. Na abordagem por gramáticas de atributos, estas duas especificações estão agregadas e são especificadas em simultâneo. Veja-se, por exemplo, o invariante que tem de ser garantido na construção e processamento de objectos do tipo litprog; na primeira abordagem, era garantido por uma pré-condição no processamento e um invariante na construção; na segunda, é garantido pelas condições de contexto associadas às produções p3 e p6 respectivamente.
O desenvolvimento da gramática de atributos prosseguiria desta forma até todas as restrições semânticas estarem cobertas e todos os atributos utilizados nessas restrições estarem especificados.
Para completar o exemplo há que definir ainda os atributos pros e tab associados ao axioma da GIC, litprog:
é uma estrutura associativa onde são guardados pares com a seguinte composição: identificador→fragmento-de-programa; este atributo corresponde à função finita utilizada na abordagem anterior.
tal como os acima referidos itab e stab, é uma tabela de identificadores normal.
litprog: syn {tab: IdentTAB; pros: PEleList} X: syn {pros: PEleList}
E as respectivas regras de cálculo:
p1.2: X → prog X pros(X0) = fusão( pros(prog), pros(X1) ) p1: litprog → "<litprog>" X "</litprog>" tab(litprog) = stab(X) pros(litprog) = pros(X)
Neste momento, estão definidas as estruturas necessárias para especificar qualquer processador para este tipo de documentos via equações/funções sobre os atributos. Por exemplo, um extractor de programas poderia ser especificado da seguinte maneira:
p1: litprog → "<litprog>" X "</litprog>" getprogram( pros(litprog), tab(litprog) )
O procedimento getprogram vai percorrer as duas estruturas criadas durante o reconhecimento do documento, respectivamente pros que tem o código dos excertos de programas e tab que tem a informação sobre os identificadores, e vai combinar a informação das duas de modo a conseguir produzir um programa válido.
Com a análise deste exemplo pretende-se mostrar a capacidade deste formalismo para representar a sintaxe SGML. Pode-se, então, concluir que, não só tem capacidades para o fazer, como nos dá uma margem de manobra para criar extensões[2]. No exemplo seguido, fez-se uma conversão manual de um DTD para uma gramática mas, considerando a tabela de conversão construída (Tabela 9-1) é fácil ver que este processo é sistemático e por isso automatizável. E é este objectivo que será a linha condutora ao longo deste capítulo, automatizar o processo de modo a que as gramáticas de atributos não passem de uma mera curiosidade científica para o utilizador.
Na próxima secção (Secção 9.2) descreve-se o desenvolvimento e implementação de um sistema, S4, que irá automatizar muitas das fases do ciclo de vida dos documentos SGML.
Os conceitos fundamentais relacionados com o sistema S4 foram apresentados ao longo dos capítulos anteriores: o SGML como objectivo de edição, as gramáticas de atributos como fundamento de especificação e o Synthesizer Generator como primeira ferramenta de implementação.
[1] | Foi dito atrás que o SGML era completamente desprovido de validações semânticas, o que é verdade se o que estiver em causa for o conteúdo textual. No entanto, há algumas excepções relacionadas com as origens da norma: a integridade referencial é a mais notória. |
[2] | A linguagem de cálculo de atributos é um novo universo operacional. |