Лабораторная работа №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:
