Prof. José de
Terceiro
Siga as
Faça um compilador para a gramática dada a seguir, da linguagem NTSA (Não Tão Simples Assim). Esta linguagem suporta procedimentos e funções, declarados com a palavra-chave “proc”, e variáveis globais. O resto da linguagem é praticamente igual à linguagem do trabalho 2.
Variáveis globais e procedimentos/funções compartilham o nível léxico global. O outro nível léxico, local, contém variáveis locais e parâmetros. Dois identificadores do mesmo nível léxico não podem ser iguais. Mas um local pode ter o mesmo nome que o global, tendo precedência sobre este.
A gramática de NTSA é dada abaixo:
Program ::= GlobalVarList ProcList
GlobalVarList ::= [ VarDec { VarDec } ]
ProcList ::= ProcDec { ProcDec }
ProcDec ::= “proc”
[ Type ] Id “(“ [ ParamList ] “)”
[ VarDec { VarDec } ] ProcBody
ParamList ::= Type
Id {“,” Type Id }
ProcBody ::= “begin”
{ Command } “end”
CompositeCommand ::= “begin”
{ Command } “end”
Command ::= PrintCommand | AssignmentCommand
| WhileCommand
| ForCommand | IfCommand
| CompositeCommand
| ReturnCommand
| ProcCall
VarDec ::= Type Id
{ “,” Id } “;”
Type ::=
“integer” | “boolean”
AssignmentCommand ::=
PrintCommand ::= “print” OrExpr “;”
WhileCommand ::=
“while” OrExpr
“do” Command
ForCommand ::= “for”
Id “=” OrExpr “to” OrExpr
“do” Command
IfCommand ::=
“if” OrExpr
“then” Command
[ “else” Command ]
ReturnCommand ::=
“return” OrExpr
“;”
ProcCall ::= Id “(“
[ OrExpr { “,” OrExpr } ]
“)”
OrExpr ::= AndExpr [ "or" AndExpr
]
AndExpr ::= RelExpr [ "and" RelExpr
]
RelExpr ::= AddExpr [ RelOp AddExpr ]
AddExpr ::= MultExpr { AddOp MultExpr }
MultExpr ::= SimpleExpr { MultOp SimpleExpr }
SimpleExpr ::= Number
| "true" | "false" |
| '(' OrExpr
')' | "not" SimpleExpr | AddOp SimpleExpr
| Id | getInteger
| ProcCall
RelOp ::= '<'
| '<=' | '>' | '>='| '==' | '<>'
AddOp ::= '+'|
'-'
MultOp ::= '*' |
'/' | '%'
Number ::= Digit { Digit
}
Digit ::= '0'| '1' | ... | '9'
FuncCall ::= Id “(“
[ OrExpr { “,” OrExpr } ]
“)”
Algumas
1. {
e } representam
2.
3. Number representa
4. identificadores
devem
5. qualquer
6. uma função só pode ser chamada onde se espera uma expressão. Um procedimento só pode ser chamado em uma instrução (fora de uma expressão, como usual);
7. o último procedimento/função do arquivo de entrada deve ser um procedimento sem parâmetros. Pode ter qualquer nome. É a partir deste procedimento que a execução começa;
8. o nome main não pode ser utilizado para nome de procedimentos/funções.
Agora a linguagem possui variáveis globais e procedimentos/funções. Um procedimento pode ser declarado como
proc imprime( integer
n )
begin
$$
comandos. Isto é um comentário
end
Uma função deve ter tipo de retorno:
proc integer
fatorial(integer n )
begin
if n == 0 then return 1;
else
return n*fatorial(n-1);
end
Usando variáveis locais, esta função poderia ter sido declarada como
proc integer
fatorial(integer n )
integer i, p;
begin
p = 1;
for i = 2 to n do
p =
p*i;
return p;
end
O
- um procedimento/função está sendo redeclarado ?
- ao chamar um procedimento/função, o número e tipo dos parâmetros está correto ?
- um procedimento está sendo usado como função ou vice-versa (procedimento como expressão e função como instrução) ?
- alguma variável global está sendo redeclarada ?
- alguma variável global e procedimento/função tem o mesmo nome ?
- a última subrotina é um procedimento sem parâmetros ?
Você deve entregar, impressos:
Exemplo 1.
proc printInteger(integer k)
integer i;
begin
for i = 1 to k do
print i;
end
proc boolean
test(integer n, integer i)
begin
return n/i == 0 or (n
– 1)%i == 0;
end
proc principal()
integer n, i;
boolean ok;
begin
printInteger(getInteger);
n = getInteger;
ok = true;
while i < n do
begin
if test(n, i) then
ok = false;
i = i + 1;
end
if ok then print 1; else print 0;
end
Exemplo
2.
proc integer calcDelta(integer a, integer b, integer c)
begin
return b*b – 4*a*c;
end
proc integer calcSqrt(integer square)
boolean ok;
integer
n;
begin
ok = false;
n = 1;
while not ok do
begin
if n*n == square then ok = true;
else n = n + 1;
end
end
proc principal()
integer a, b, c, delta;
begin
a = getInteger;
b = getInteger;
c = getInteger;
$$ assume que delta seja
um quadrado perfeito ou < 0
delta = calcDelta(a,
b, c);
if delta < 0 then print -1;
else
begin
if delta == 0 then print 0;
else
print 1;
$$ delta = n*n, logo, n = sqrt(delta)
n = calcSqrt(delta);
print (-b + n)/(2*a);
print (-b - n)/(2*a);
end
end