Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка 15.02.docx
Скачиваний:
2
Добавлен:
07.05.2019
Размер:
240.61 Кб
Скачать

Нисходящие методы разбора Устранение левой рекурсии

Грамматика называется леворекурсивной, если в ней имеется нетерминал A, такой, что существует порождение для некоторой цепочки .

Вход:

A A | 

Правило устранения левой рекурсии:

A A’

A’  A’ | 

E  E + T

T  T * F | F

F  (E) | id

Устранение непосредственной левой рекурсии:

E  TE’

E’  +TE’ |

T  FT’

T’  *FT’ |

F  (E) | id

Вход: грамматика без циклов и -продукций.

Выход: эквивалентная грамматика без левой рекурсии.

Пример 11. Устранение левой рекурсии

Расположить нетерминалы в порядке A1, A2,…,An

for i:=1 to n do begin

for j:=1 to i-1 do begin

Заменить каждую продукцию вида Ai  Aj продукциями Ai 1  | 2  | … |k  где Aj  1 | 2 | … |k – все текущие Aj-продукции

end

Устранить непосредственную левую продукцию среди Ai-продукций

end

Левая факторизация

S  if E then S else S | if E then S

Т.е. если A  1 | 2 представляют собой две A-продукции и входной поток начинается с непустой строки, порождаемой , то нельзя сказать будет ли использоваться первая или вторая продукция, можно только отложить решение, проведя замену:

A  A’

A’  1 | 2

S  if E then S else S | if E then S | a

E  b

Левофакторизованная грамматика:

S  if E then ES’ | a

S’  else S | 

E  b

Метод рекурсивного спуска

Программа интерпретации арифметических выражений с грамматикой:

S  A:=E;

E  E+T | E-T | T

T  T*F | T/F | F

F  (E) | id | const

В презентации большой кусок кода….

Пример нисходящего интерпретатора

Пример 12 Простой нисходящий интерпретатор арифметических выражений

// Translator.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace SimpleTranslator

{

public class Translator

{

enum Tokens

{

Undefined, Assigment, Add, Sub, Mul, Div, RBr, LBr, Id, Constant

}

private int index = 0;

private Tokens token;

private string source;

string currentId;

private Dictionary<string, double> symbols =

new Dictionary<string, double>();

private void Match(Tokens t)

{

if (token == t)

{

Scan();

}

else

{

Error();

}

}

/// <summary>

/// Лексический анализатор

/// </summary>

private void Scan()

{

char c;

int state = 0;

currentId = string.Empty;

c = source[index];

while (c != ';')

{

c = source[index];

switch (state)

{

case 0:

{

if (c == ':')

state = 1;

if (Char.IsLetter(c))

{

token = Tokens.Id;

currentId += c;

state = 3;

}

if (c == '+') { token = Tokens.Add; index++;

return; }

if (c == '-') { token = Tokens.Sub; index++;

return; }

if (c == '*') { token = Tokens.Mul; index++;

return; }

if (c == '/') { token = Tokens.Div; index++;

return; }

if (c == ')') { token = Tokens.LBr; index++;

return; }

if (c == '(') { token = Tokens.RBr; index++;

return; }

if (Char.IsDigit(c))

{

token = Tokens.Constant;

currentId += c;

state = 7;

}

break;

}

case 1:

if (c == '=') {

token = Tokens.Assigment;

}

else

{

token = Tokens.Undefined;

}

return;

case 3:

if (!Char.IsLetterOrDigit(c)) {

symbols[currentId] = 10;

return;

}

else currentId += c;

break;

case 7:

if (!Char.IsDigit(c)) {

symbols[currentId] = Convert.ToDouble(currentId);

return; }

else currentId += c;

break;

}

++index;

}

}

private void Assigment()

{

Match(Tokens.Undefined);

Match(Tokens.Id);

Match(Tokens.Assigment);

Expression();

}

private void Expression()

{

Term();

Tokens t;

while (true)

{

switch (token)

{

case Tokens.Add:case Tokens.Sub:

t = token;

Match(token);

Term();

Emit(t, string.Empty); continue;

default:

return;

}

}

}

private void Term()

{

Tokens t;

Factor();

while (true)

{

switch (token)

{

case Tokens.Mul:case Tokens.Div:

t = token;

Match(token);

Factor();

Emit(t, string.Empty);

continue;

default:

return;

}

}

}

private void Factor()

{

switch (token)

{

case Tokens.RBr:

Match(Tokens.RBr);

Expression();

Match(Tokens.LBr);

break;

case Tokens.Constant:

Emit(token, currentId);

Match(Tokens.Constant);

break;

case Tokens.Id:

Emit(token, currentId);

Match(Tokens.Id); break;

default: Error(); break;

}

}

private void Error()

{

throw new ApplicationException("Parsing error");

}

private Stack<double> stack = new Stack<double>();

private void Emit(Tokens t, string tval)

{

switch (t)

{

case Tokens.Add: Operation((x, y) => x + y); break;

case Tokens.Sub: Operation((x, y) => x - y); break;

case Tokens.Mul: Operation((x, y) => x * y); break;

case Tokens.Div: Operation((x, y) => x / y); break;

case Tokens.Constant:

case Tokens.Id: stack.Push(symbols[tval]); break;

default:

Console.WriteLine("Token {0}, TokenVal {1}", t, tval);

break;

}

}

private void Operation(Func<double, double, double> operation)

{

double o1 = stack.Pop();

double o2 = stack.Pop();

stack.Push(operation(o1, o2));

}

public double Translate(string source)

{

token = Tokens.Undefined;

this.source = source;

Assigment();

return stack.Pop();

}

}

}

// Program.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace SimpleTranslator

{

class Program

{

static void Main(string[] args)

{

const string source = "x:=(10+20/20)*2-22;";

Console.WriteLine("{0}\n",source);

Translator tran = new Translator();

try

{

Console.WriteLine(tran.Translate(source));

}

catch (ApplicationException e)

{

Console.WriteLine(e.ToString());

}

}

}

}