Capítulo 9. Validação Semântica com Gramáticas de Atributos

Índice
9.1. Aproximação via gramáticas de atributos
9.2. S4: desenvolvimento integrado de documentos

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.

9.1. Aproximação via gramáticas de atributos

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):

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

SGMLGramáticas de Atributos
x,yZ → X Y
x & yZ → X Y | Y X
x | yZ → 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:

pros

é 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.

tab

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.

Notas

[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.