... | ... | @@ -60,109 +60,191 @@ end |
|
|
|
|
|
### Модуль синтаксического анализатора (парсера)
|
|
|
|
|
|
``` Delphi
|
|
|
unit SimpleLangParser;
|
|
|
|
|
|
interface
|
|
|
|
|
|
procedure Progr;
|
|
|
procedure Expr;
|
|
|
procedure Assign;
|
|
|
procedure StatementList;
|
|
|
procedure Statement;
|
|
|
procedure Block;
|
|
|
procedure Cycle;
|
|
|
procedure syntaxerror(message: string := '');
|
|
|
|
|
|
implementation
|
|
|
|
|
|
uses
|
|
|
SimpleLangLexer;
|
|
|
|
|
|
procedure Progr;
|
|
|
begin
|
|
|
Block
|
|
|
end;
|
|
|
|
|
|
procedure Statement;
|
|
|
begin
|
|
|
case LexKind of
|
|
|
Tok.&Begin: Block;
|
|
|
Tok.Cycle: Cycle;
|
|
|
Tok.Id: Assign;
|
|
|
else syntaxerror('Ожидался оператор');
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
procedure Block;
|
|
|
begin
|
|
|
NextLexem; // Пропуск begin
|
|
|
StatementList;
|
|
|
if LexKind=Tok.&End then
|
|
|
NextLexem
|
|
|
else syntaxerror('Ожидалось end');
|
|
|
end;
|
|
|
|
|
|
procedure Cycle;
|
|
|
begin
|
|
|
NextLexem; // Пропуск cycle
|
|
|
Expr;
|
|
|
Statement;
|
|
|
end;
|
|
|
|
|
|
procedure Assign;
|
|
|
begin
|
|
|
NextLexem; // Пропуск id
|
|
|
if LexKind = Tok.ASSIGN then
|
|
|
NextLexem
|
|
|
else syntaxerror('Ожидалось :=');
|
|
|
Expr;
|
|
|
end;
|
|
|
|
|
|
procedure StatementList;
|
|
|
begin
|
|
|
Statement;
|
|
|
while LexKind=Tok.SEMICOLON do
|
|
|
begin
|
|
|
NextLexem;
|
|
|
Statement;
|
|
|
end
|
|
|
end;
|
|
|
|
|
|
procedure Expr; // Выражение - это id или num
|
|
|
begin
|
|
|
if LexKind in [Tok.ID,Tok.INUM] then
|
|
|
NextLexem
|
|
|
else syntaxerror('Ожидалось выражение');
|
|
|
end;
|
|
|
|
|
|
procedure syntaxerror(message: string);
|
|
|
begin
|
|
|
var ss := System.IO.File.ReadLines(fname).Skip(LexRow-1).First(); // Строка row файла
|
|
|
writeln('Синтаксическая ошибка в строке ',LexRow,':');
|
|
|
writeln(ss);
|
|
|
writeln('^':LexCol-1);
|
|
|
if message<>'' then
|
|
|
writeln(message);
|
|
|
Done;
|
|
|
halt;
|
|
|
end;
|
|
|
|
|
|
end.
|
|
|
``` CSharp
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
using System.Text;
|
|
|
using SimpleLangLexer;
|
|
|
|
|
|
namespace SimpleLangParser
|
|
|
{
|
|
|
public class ParserException : System.Exception
|
|
|
{
|
|
|
public ParserException(string msg)
|
|
|
: base(msg)
|
|
|
{
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
public class Parser
|
|
|
{
|
|
|
private SimpleLangLexer.Lexer l;
|
|
|
|
|
|
public Parser(SimpleLangLexer.Lexer lexer)
|
|
|
{
|
|
|
l = lexer;
|
|
|
}
|
|
|
|
|
|
public void Progr()
|
|
|
{
|
|
|
Block();
|
|
|
}
|
|
|
|
|
|
public void Expr()
|
|
|
{
|
|
|
if (l.LexKind == Tok.ID || l.LexKind == Tok.INUM)
|
|
|
{
|
|
|
l.NextLexem();
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
SyntaxError("expression expected");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public void Assign()
|
|
|
{
|
|
|
l.NextLexem(); // пропуск id
|
|
|
if (l.LexKind == Tok.ASSIGN)
|
|
|
{
|
|
|
l.NextLexem();
|
|
|
}
|
|
|
else {
|
|
|
SyntaxError(":= expected");
|
|
|
}
|
|
|
Expr();
|
|
|
}
|
|
|
|
|
|
public void StatementList()
|
|
|
{
|
|
|
Statement();
|
|
|
while (l.LexKind == Tok.SEMICOLON)
|
|
|
{
|
|
|
l.NextLexem();
|
|
|
Statement();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public void Statement()
|
|
|
{
|
|
|
switch (l.LexKind)
|
|
|
{
|
|
|
case Tok.BEGIN:
|
|
|
{
|
|
|
Block();
|
|
|
break;
|
|
|
}
|
|
|
case Tok.CYCLE:
|
|
|
{
|
|
|
Cycle();
|
|
|
break;
|
|
|
}
|
|
|
case Tok.ID:
|
|
|
{
|
|
|
Assign();
|
|
|
break;
|
|
|
}
|
|
|
default:
|
|
|
{
|
|
|
SyntaxError("Operator expected");
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public void Block()
|
|
|
{
|
|
|
l.NextLexem(); // пропуск begin
|
|
|
StatementList();
|
|
|
if (l.LexKind == Tok.END)
|
|
|
{
|
|
|
l.NextLexem();
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
SyntaxError("end expected");
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
public void Cycle()
|
|
|
{
|
|
|
l.NextLexem(); // пропуск cycle
|
|
|
Expr();
|
|
|
Statement();
|
|
|
}
|
|
|
|
|
|
public void SyntaxError(string message)
|
|
|
{
|
|
|
var errorMessage = "Syntax error in line " + l.LexRow.ToString() + ":\n";
|
|
|
errorMessage += l.FinishCurrentLine() + "\n";
|
|
|
errorMessage += new String(' ', l.LexCol - 1) + "^\n";
|
|
|
if (message != "")
|
|
|
{
|
|
|
errorMessage += message;
|
|
|
}
|
|
|
throw new ParserException(errorMessage);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
#### Основная программа
|
|
|
|
|
|
``` Delphi
|
|
|
uses SimpleLangLexer,SimpleLangParser;
|
|
|
|
|
|
begin
|
|
|
Init('progr.txt');
|
|
|
Progr;
|
|
|
if LexKind=Tok.EOF then
|
|
|
writeln('программа распознана правильно ')
|
|
|
else syntaxerror('ожидался конец файла');
|
|
|
end.
|
|
|
``` CSharp
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
using System.Text;
|
|
|
using System.IO;
|
|
|
using SimpleLangParser;
|
|
|
using SimpleLangLexer;
|
|
|
|
|
|
namespace SimpleLangParserTest
|
|
|
{
|
|
|
class Program
|
|
|
{
|
|
|
static void Main(string[] args)
|
|
|
{
|
|
|
string fileContents = @"begin
|
|
|
a := 2;
|
|
|
cycle a
|
|
|
begin
|
|
|
b := a;
|
|
|
c := 234
|
|
|
end
|
|
|
end";
|
|
|
TextReader inputReader = new StringReader(fileContents);
|
|
|
Lexer l = new Lexer(inputReader);
|
|
|
Parser p = new Parser(l);
|
|
|
try
|
|
|
{
|
|
|
p.Progr();
|
|
|
if (l.LexKind == Tok.EOF)
|
|
|
{
|
|
|
Console.WriteLine("Program successfully recognized");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
p.SyntaxError("end of file was expected");
|
|
|
}
|
|
|
}
|
|
|
catch (ParserException e)
|
|
|
{
|
|
|
Console.WriteLine("lexer error: " + e.Message);
|
|
|
}
|
|
|
catch (LexerException le)
|
|
|
{
|
|
|
Console.WriteLine("parser error: " + le.Message);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
#### Основные задания (7 баллов)
|
... | ... | |