Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лаб. 5 ТАЯК.docx
Скачиваний:
0
Добавлен:
25.01.2026
Размер:
109.8 Кб
Скачать

Лабораторная работа №5 Разработка интерпретатора

using System;

using System.Collections.Generic;

using System.IO;

using System.Linq;

using System.Text;

namespace CBAS_Interpreter

{

// Типы токенов для CBAS

public enum TokenType

{

// Ключевые слова

PRINT, SCAN, FOR, IF, ELSE, TO, RETURN,

// Идентификаторы и литералы

IDENTIFIER, NUMBER, STRING,

// Операторы и разделители

ASSIGN, PLUS, MINUS, MULTIPLY, DIVIDE,

LT, GT, EQ, NE,

LPAREN, RPAREN, LBRACE, RBRACE,

SEMICOLON, COMMA, QUOTE,

// Специальные токены

EOF, ERROR

}

// Класс токена

public class Token

{

public TokenType Type { get; }

public string Value { get; }

public int Line { get; }

public int Column { get; }

public Token(TokenType type, string value, int line, int column)

{

Type = type;

Value = value;

Line = line;

Column = column;

}

public override string ToString()

{

return $"{Type}({Value}) at {Line}:{Column}";

}

}

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

// Разбивает исходный код на токены

public class Lexer

{

private readonly string _input;

private int _position;

private int _line;

private int _column;

private readonly List<Token> _tokens;

public Lexer(string input)

{

_input = input;

_position = 0;

_line = 1;

_column = 1;

_tokens = new List<Token>();

}

public List<Token> Tokenize()

{

_tokens.Clear();

while (_position < _input.Length)

{

char current = Peek();

If (char.IsWhiteSpace(current))

{

SkipWhitespace();

}

else if (char.IsLetter(current) || current == '_')

{

ScanIdentifierOrKeyword();

}

else if (char.IsDigit(current))

{

ScanNumber();

}

else if (current == '"')

{

ScanString();

}

else

{

ScanSymbol();

}

}

_tokens.Add(new Token(TokenType.EOF, "", _line, _column));

return _tokens;

}

private char Peek(int offset = 0)

{

return _position + offset < _input.Length ? _input[_position + offset] : '\0';

}

private char Next()

{

char current = Peek();

if (_position < _input.Length)

{

_position++;

if (current == '\n')

{

_line++;

_column = 1;

}

else

{

_column++;

}

}

return current;

}

private void SkipWhitespace()

{

while (_position < _input.Length && char.IsWhiteSpace(Peek()))

{

Next();

}

}

private void ScanIdentifierOrKeyword()

{

int start = _position;

int startLine = _line;

int startColumn = _column;

while (_position < _input.Length && (char.IsLetterOrDigit(Peek()) || Peek() == '_'))

{

Next();

}

string value = _input.Substring(start, _position - start);

TokenType type = value.ToLower() switch

{

"print" => TokenType.PRINT,

"scan" => TokenType.SCAN,

"for" => TokenType.FOR,

"if" => TokenType.IF,

"else" => TokenType.ELSE,

"to" => TokenType.TO,

"return" => TokenType.RETURN,

_ => TokenType.IDENTIFIER

};

_tokens.Add(new Token(type, value, startLine, startColumn));

}

private void ScanNumber()

{

int start = _position;

int startLine = _line;

int startColumn = _column;

while (_position < _input.Length && char.IsDigit(Peek()))

{

Next();

}

string value = _input.Substring(start, _position - start);

_tokens.Add(new Token(TokenType.NUMBER, value, startLine, startColumn));

}

private void ScanString()

{

int startLine = _line;

int startColumn = _column;

Next(); // Пропускаем открывающую кавычку

StringBuilder sb = new StringBuilder();

while (_position < _input.Length && Peek() != '"')

{

sb.Append(Next());

}

if (Peek() == '"')

{

Next(); // Пропускаем закрывающую кавычку

_tokens.Add(new Token(TokenType.STRING, sb.ToString(), startLine, startColumn));

}

else

{

_tokens.Add(new Token(TokenType.ERROR, "Незакрытая строка", startLine, startColumn));

}

}

private void ScanSymbol()

{

int startLine = _line;

int startColumn = _column;

char current = Next();

switch (current)

{

case '(':

_tokens.Add(new Token(TokenType.LPAREN, "(", startLine, startColumn));

break;

case ')':

_tokens.Add(new Token(TokenType.RPAREN, ")", startLine, startColumn));

break;

case '{':

_tokens.Add(new Token(TokenType.LBRACE, "{", startLine, startColumn));

break;

case '}':

_tokens.Add(new Token(TokenType.RBRACE, "}", startLine, startColumn));

break;

case ';':

_tokens.Add(new Token(TokenType.SEMICOLON, ";", startLine, startColumn));

break;

case ',':

_tokens.Add(new Token(TokenType.COMMA, ",", startLine, startColumn));

break;

case '=':

if (Peek() == '=')

{

Next();

_tokens.Add(new Token(TokenType.EQ, "==", startLine, startColumn));

}

else

{

_tokens.Add(new Token(TokenType.ASSIGN, "=", startLine, startColumn));

}

break;

case '+':

_tokens.Add(new Token(TokenType.PLUS, "+", startLine, startColumn));

break;

case '-':

_tokens.Add(new Token(TokenType.MINUS, "-", startLine, startColumn));

break;

case '*':

_tokens.Add(new Token(TokenType.MULTIPLY, "*", startLine, startColumn));

break;

case '/':

_tokens.Add(new Token(TokenType.DIVIDE, "/", startLine, startColumn));

break;

case '<':

_tokens.Add(new Token(TokenType.LT, "<", startLine, startColumn));

break;

case '>':

_tokens.Add(new Token(TokenType.GT, ">", startLine, startColumn));

break;

case '!':

if (Peek() == '=')

{

Next();

_tokens.Add(new Token(TokenType.NE, "!=", startLine, startColumn));

}

else

{

_tokens.Add(new Token(TokenType.ERROR, "!", startLine, startColumn));

}

break;

default:

_tokens.Add(new Token(TokenType.ERROR, current.ToString(), startLine, startColumn));

break;

}

}

}

// Ошибка интерпретатора

public class SyntaxError

{

public string Message { get; }

public int Line { get; }

public int Column { get; }

public SyntaxError(string message, int line, int column)

{

Message = message;

Line = line;

Column = column;

}

public override string ToString()

{

return $"Синтаксическая ошибка на {Line}:{Column} - {Message}";

}

}

// Синтаксический анализатор (только проверка синтаксиса)

// Проверка правильности структуры программы

public class SyntaxAnalyzer

{

private List<Token> _tokens;

private int _position;

private List<SyntaxError> _errors;

public SyntaxAnalyzer(List<Token> tokens)

{

_tokens = tokens;

_position = 0;

_errors = new List<SyntaxError>();

}

public (bool Success, List<SyntaxError> Errors) Analyze()

{

try

{

Program();

return (_errors.Count == 0, _errors);

}

catch (Exception ex)

{

_errors.Add(new SyntaxError($"Критическая ошибка анализа: {ex.Message}", 0, 0));

return (false, _errors);

}

}

private Token CurrentToken()

{

return _position < _tokens.Count ? _tokens[_position] : _tokens.Last();

}

private Token NextToken()

{

return _position < _tokens.Count ? _tokens[_position++] : _tokens.Last();

}

private bool Match(TokenType type)

{

if (CurrentToken().Type == type)

{

_position++;

return true;

}

return false;

}

private void Expect(TokenType type, string errorMessage)

{

if (!Match(type))

{

Token current = CurrentToken();

_errors.Add(new SyntaxError(errorMessage, current.Line, current.Column));

}

}

// Program → Statement*

private void Program()

{

while (CurrentToken().Type != TokenType.EOF)

{

Statement();

}

}

// Statement → Print | Scan | Assign | For | If | Block | ';'

private void Statement()

{

Token token = CurrentToken();

switch (token.Type)

{

case TokenType.PRINT:

PrintStatement();

break;

case TokenType.SCAN:

ScanStatement();

break;

case TokenType.IDENTIFIER:

AssignStatement();

break;

case TokenType.FOR:

ForStatement();

break;

case TokenType.IF:

Соседние файлы в предмете Теория алгоритмических языков и компиляторов