Вы находитесь на странице: 1из 10

Definição de uma Gramática Livre

Capítulo 3: Gramáticas Livres de


de Contexto:
Contexto e Análise Sintática • Um alfabeto ou conjunto básico de símbolos (como
Material Base – Keneth Louden expressões regulares, agora somente símbolos são
terminais, não caracteres), incluindo ε. (Terminais)
• Um conjunto de nomes para estruturas
Conceitos abstratos de Análise (declarações, expressões, definições). (não
Sintática -- Cap. 4 e 5 serão terminais)
analisados a análise sintática. O título • Um conjunto de regras gramaticais representando a
estrutura para cada nome. (Produções)
do capitulo poderia ser “Gramática
• Um símbolo inicial (o nome da estrutura mais geral -
Livre de Contexto e Sintaxe” compilation_unit em C).

Exemplo Básico : Expressão GLC´s são desenvolvida para


aritmética de inteiros representar estruturas recursivas
2 não terminais
(aninhadas)
exp → exp op exp | ( exp ) | number As conseqüências são enormes:
op → + | - | * 6 terminais
A estrutura de busca de strings não é
6 produções (3 em cada linha)
da forma como ocorre na seqüência
Em que uma GLC difere de uma GR ou de símbolos (lexemas), mas por uma
ER? árvore (parse tree – árvore sintática)
digit = 0|1|…|9 Reconhecedores não são mais finitos,
number = digit digit* mas podem ter tamanho de dados
Recursão! Regras recursivas Regras “base” arbitrários, e devem ter possibilidade
de empilhamento.
Maior Consequência: Muitos
O processo de reconhecimento é algoritmos analisadores sintáticos
mais complexo: não são eficientes
z Algoritmos podem utilizar pilhas com z Top down
diferentes caminhos. – Recursão descendente (hand choice)
z Não determinismo é mais comum e – “Preditiva” table-driven (dirigida por
tabela), “LL” (outdated)
mais difícil de ser eliminado.
z Bottom up
z Até o número de estados pode – “LR” e o seu primo “LALR” (machine-
variar conforme o algoritmo generated choice [Yacc/Bison])
(somente 2 estados necessários se – Precedência de Operadores-
pilhas for utilizada na estrutura de precedência (outdated)
“estados”.

Abstração da estrutura por meio


Primeiros assuntos estruturais!
de uma árvore sintática :
Expressão de busca de uma string exp
1
[“(34-3)*42”] por derivação:
(1) exp ⇒ exp op exp [exp → exp op exp] 4 exp 3 op 2 exp
(2) ⇒ exp op number [exp → number]
(3) ⇒ exp * number [op → * ]
(4) ⇒ ( exp ) * number [exp → ( exp )] ( 5 exp ) * number
(5) ⇒ ( exp op exp ) * number [exp → exp op exp]
(6) ⇒ (exp op number) * number [exp → number ]
(7) ⇒ (exp - number) * number [op → - ] 8 exp 7 op 6 exp
(8) ⇒ (number - number)*number [exp → number ]

number - number
A derivação mais a esquerda (top-down) corresponde a pré-
Derivações podem variar, até mesmo ordem da árvore sintática.
quando a árvore sintatica não existe: A derivação mais a direita (bottom-up) corresponde a arvore
sintática em pós-order.
Derivação mais a esquerda (Slide 8 era Analisadores Sintáticos Top-down constroem derivações da
mais direita): árvore mais a esquerda.
(1) exp ⇒ exp op exp [exp → exp op exp] (LL = varredura (Esquerda para Direita) Left-to-right das
(2) ⇒ (exp) op exp [exp → ( exp )] entradas e constrói uma derivação mais a (Leftmost)
(3) ⇒ (exp op exp) op exp [exp → exp op exp] esquerda)
(4) ⇒ (number op exp) op exp [exp → number]
Analisadores Sintáticos Bottom-up constroem derivações mais a
(5) ⇒ (number - exp) op exp [op → -]
direita em ordem reversa.
(6) ⇒ (number - number) op exp [exp → number]
(7) ⇒ (number - number) * exp [op → *] (LR = varredura (esquerda para direita) Left-to-right da cadeia
(8) ⇒ (number - number) * number [exp → number] de entrada e constrói uma derivação mais a direita
(Rightmost))

Mas o que acontece se a árvore Princípios da sintaxe dirigida à


sintática variar?[ exp op exp op
correta semântica
exp ] exp exp

A árvore sintática pode ser usada como o


exp op exp exp op exp modelo básico; conteúdo semântico pode
ser atachado para a árvore; desta forma a
exp op exp * number number - exp op exp árvore pode refletir a estrutura da
semântica eventual (sintaxe da base
number - number number * number semântica pode ser o melhor termo)
A gramática é ambígua, por quê precisamos
tomar cuidado? Semântica!
Origens da Ambiguidade: Lidando com ambigüidade
z Associatividade e precedência de z Regra para tirar ambigüidade
operadores z Mudanças na gramática (mas não na
z Sequenciamento linguagem!)
z Extensão de uma sub estrutura z Podem ser removidas todas as
(encadeamento de else) ambigüidades?
z Recursão “Obscura” (não usual) – Backtracking pode ajudar, mas o custo
– exp → exp exp é alto.

Exemplo: aritmética de inteiros Repetição e Recursão


z Recursão a esquerda: A → A x | y
exp → exp addop term | term – yxx:
A

addop → + | - A x

term → term mulop factor | factor A x

y
mulop → *
z Recursão a direita: A → x A | y
factor → ( exp ) | number – xxy:
A

x A
Precedência “cascata”
x A
y
Repetição & Recursão, cont. Árvores Sintáticas Abstratas
z Algumas vezes temos que tomar cuidado
z Representar a estrutura essencial da árvore
com o caminho que a operação segue:
somente
operador de associatividade
z Omissão de parênteses, cascatas, e
z Algumas vezes não é necessário:
“descuidos” com associatividade repetitiva
seqüências de declarações e expressões
z Corresponde a árvore interna atual
z Análise sintática permite escolher um
produzida pelo analisador sintático
maneira
z Uso de listas de irmãos para não se
z A árvore pode remover estas informações.
preocupar com repetições: s1 --- s2 --- s3

Exemplos simples [ (34-3)*42 ] Estrutura de Dados


typedef enum {Plus,Minus,Times} OpKind;
* typedef enum {OpK,ConstK} ExpKind;
typedef struct streenode
{ ExpKind kind;
- 42 OpKind op;
struct streenode *lchild,*rchild;
int val;
} STreeNode;
34 3
typedef STreeNode *SyntaxTree;
ou (usando um union): OU (C++ mas não ISO 99 C):
typedef enum {Plus,Minus,Times} OpKind; typedef enum {Plus,Minus,Times} OpKind;
typedef enum {OpK,ConstK} ExpKind; typedef enum {OpK,ConstK} ExpKind;
typedef struct streenode typedef struct streenode
{ ExpKind kind; { ExpKind kind;
struct streenode *lchild,*rchild; struct streenode *lchild,*rchild;
union { union {
OpKind op; OpKind op;
int val; } attribute; int val; }; // anonymous union
} STreeNode; } STreeNode;
typedef STreeNode *SyntaxTree; typedef STreeNode *SyntaxTree;

Exemplos de sequências Exemplo de ambigüidade “Obscura”


z stmt-seq → stmt ; stmt-seq | stmt Tentativa incorreta de soma/subtração
um ou mais stmts separados por um ; de unários:
z stmt-seq → stmt ; stmt-seq | ε
zero ou mais stmts terminados por um ; exp → exp addop term | term | - exp
z stmt-seq → stmt-seq ; stmt | stmt addop → + | -
um ou mais stmts separados por um ; term → term mulop factor | factor
z stmt-seq → stmt-seq ; stmt | ε mulop → *
zero ou mais stmts precedidos por um ; factor → ( exp ) | number
Exemplo de ambiguidade, continuação Lidando com ambiguidade else
z Melhor: (somente um depois do inicio de
um exp) exp → exp addop term | term | - term statement → if-stmt | other
z Ou talvez : (muitos depois do primeiro if-stmt → if ( exp ) statement
termo)
| if ( exp )statement else statement
term → - term | term1
term1 → term1 mulop factor | factor exp → 0 | 1
z Ou talvez: (muitos em qualquer lugar)
factor → ( exp ) | number | - factor A seguinte string tem duas árvores
sintáticas:
if(0) if(1) other else other

Árvore sintática para else: Tirando ambiguidade das regras:


Correta Um else poderia ser sempre associado com
statement statement
a próxima declaração if-statement que
if-stmt if-stmt ainda não tem uma parte else.
if ( exp ) statement else statement if ( exp ) statement (Regra muito próxima aninhada: fácil para
0 if-stmt other 0 if-stmt
os estados, mas difícil para colocar na
gramática.)
if ( exp ) statement if ( exp ) statement else statement

Note que “parênteses” podem remover a


1 other 1 other other Parênteses
ambigüidade:
if-stmt → if ( exp ) stmt end
| if ( exp )stmt else stmt end
TINY Grammar:
program → stmt-sequence
stmt-sequence → stmt-sequence ; statement | statement
TINY Syntax Tree (Parte 1)
statement → if-stmt | repeat-stmt | assign-stmt | read-stmt |
write-stmt typedef enum {StmtK,ExpK} NodeKind;
if-stmt → if exp then stmt-sequence end typedef enum
| if exp then stmt-sequence else stmt-sequence end {IfK,RepeatK,AssignK,ReadK,WriteK}
repeat-stmt → repeat stmt-sequence until exp StmtKind;
assign-stmt → identifier := exp typedef enum {OpK,ConstK,IdK} ExpKind;
read-stmt → read identifier
/* ExpType is used for type checking */
write-stmt → write exp
typedef enum {Void,Integer,Boolean}
exp → simple-exp comparison-op simple-exp | simple-exp
ExpType;
comparison-op → < | =
simple-exp → simple-exp addop term | term
addop → + | - #define MAXCHILDREN 3
term → term mulop factor | factor
mulop → * | /
factor → ( exp ) | number | identifier

TINY Syntax Tree (Parte 2) Árvore sintática de sample.tny


typedef struct treeNode read if
{ struct treeNode * child[MAXCHILDREN]; (x)

struct treeNode * sibling;


int lineno; op assign
(<) repeat write
(fact)
NodeKind nodekind;
union { StmtKind stmt; ExpKind exp;} kind; const id const assign assign op id
(0) (x) (1) (fact) (x) (=) (fact)
union { TokenType op;
int val; op op
id const
(*) (-) (x) (0)
char * name; } attr;
ExpType type; /* for type checking */ id id id const
(fact) (x) (x) (1)
} TreeNode;
Ambigüidade em C
Um gramática para ANSI C 1988 •Lidando com else
•Um ou mais:
cast_expression → unary_expression
| ( type_name ) cast_expression
http://www.lysator.liu.se/c/ANSI-C- unary_expression → postfix_expression | ...
grammar-y.html postfix_expression → primary_expression | ...
primary_expression → IDENTIFIER | CONSTANT
| STRING_LITERAL| ( expression )
type_name → … | TYPE_NAME
Exemplo:
typedef double x; int x = 1;
printf("%d\n", printf("%d\n",
(int)(x)-2); (int)(x)-2);

Removendo a ambigüidade de C Notação Extra:


z TYPE_IDs deve ser distinguido de outros z Inicial: Backus-Naur Form (BNF)
IDs na fase léxica.
– Meta símbolos são | → ε
z A árvore sintática deve construir a tabela
de símbolos (pelo menos parcialmente) z Extended BNF (EBNF):
para indicar se um ID é uma definição de – Novos meta símbolos […] e {…}
tipos (typedef) ou não.
– ε em grande parte eliminado por estes
z Analisador léxico deve consultar a tabela
de símbolos; se um ID for encontrado z Parens? Maybe yes, maybe no:
como um typedef, deve retornar TYPE_ID, – exp → exp (+ | -) term | term
senão retorna ID.
– exp → exp + term | exp - term | term
EBNF Meta símbolos: Chaves em EBNF
z Colchetes
[…] significam “opcionais” z Troca somente a repetição a
(como ? Em expressões regulares): esquerda:
– exp → term ‘|’ exp | term becomes: – exp → exp + term | term becomes:
exp → term [ ‘|’ exp ] exp → term { + term }
– if-stmt → if ( exp ) stmt z Implicação ainda com a
| if ( exp )stmt else stmt associatividade a esquerda
becomes: z Qual saída a escolher:
if-stmt → if ( exp ) stmt [ else stmt ] – exp → exp + term | exp - term | term
z Chaves {…} significam “repetição” (como * não é igual a
em ER) exp → term { + term } | term { - term }

Expressões simples em EBNF Opção de Notação Final:


Diagramas Sintáticos (de EBNF):
exp → term { addop term }
addop → + | - exp
term
term → factor { mulop factor }
mulop → * addop

factor → ( exp ) | number > ( > exp > )

factor
>

> number

Вам также может понравиться