IfStatement();
break;
case TokenType.LBRACE:
Block();
break;
case TokenType.SEMICOLON:
_position++; // Пустой оператор
break;
default:
_errors.Add(new SyntaxError($"Неожиданный токен: {token.Value}", token.Line, token.Column));
_position++;
break;
}
}
// Block → '{' Statement* '}'
private void Block()
{
Expect(TokenType.LBRACE, "Ожидается '{'");
while (CurrentToken().Type != TokenType.RBRACE && CurrentToken().Type != TokenType.EOF)
{
Statement();
}
Expect(TokenType.RBRACE, "Ожидается '}'");
}
// Print → 'print' PrintEnd ';'
private void PrintStatement()
{
Expect(TokenType.PRINT, "Ожидается 'print'");
PrintEnd();
Expect(TokenType.SEMICOLON, "Ожидается ';' после print");
}
// PrintEnd → (String | Expression) (',' (String | Expression))*
private void PrintEnd()
{
while (true)
{
Token token = CurrentToken();
if (token.Type == TokenType.STRING)
{
_position++;
}
else if (token.Type == TokenType.IDENTIFIER || token.Type == TokenType.NUMBER || token.Type == TokenType.LPAREN)
{
Expression();
}
else
{
break;
}
if (CurrentToken().Type == TokenType.COMMA)
{
_position++;
}
else
{
break;
}
}
}
// Scan → 'scan' Identifier ';'
private void ScanStatement()
{
Expect(TokenType.SCAN, "Ожидается 'scan'");
Token idToken = CurrentToken();
if (idToken.Type != TokenType.IDENTIFIER)
{
_errors.Add(new SyntaxError("Ожидается идентификатор после scan", idToken.Line, idToken.Column));
return;
}
_position++;
Expect(TokenType.SEMICOLON, "Ожидается ';' после scan");
}
// Assign → Identifier '=' Expression ';'
private void AssignStatement()
{
Token idToken = CurrentToken();
Expect(TokenType.IDENTIFIER, "Ожидается идентификатор");
Expect(TokenType.ASSIGN, "Ожидается '='");
Expression();
Expect(TokenType.SEMICOLON, "Ожидается ';' после присваивания");
}
// For → 'for' Identifier '=' Expression 'to' Expression '{' Statement* '}'
private void ForStatement()
{
Expect(TokenType.FOR, "Ожидается 'for'");
Token idToken = CurrentToken();
Expect(TokenType.IDENTIFIER, "Ожидается идентификатор цикла");
Expect(TokenType.ASSIGN, "Ожидается '=' в цикле for");
Expression();
Expect(TokenType.TO, "Ожидается 'to'");
Expression();
Expect(TokenType.LBRACE, "Ожидается '{' после for");
// Сохраняем позицию начала тела цикла
int loopBodyStart = _position;
int braceCount = 0;
// Пропускаем тело цикла для проверки синтаксиса
while (_position < _tokens.Count &&
!(braceCount == 0 && _tokens[_position].Type == TokenType.RBRACE) &&
_tokens[_position].Type != TokenType.EOF)
{
if (_tokens[_position].Type == TokenType.LBRACE) braceCount++;
if (_tokens[_position].Type == TokenType.RBRACE) braceCount--;
_position++;
}
Expect(TokenType.RBRACE, "Ожидается '}' в конце цикла for");
}
// If → 'if' '(' BoolExpression ')' Statement
private void IfStatement()
{
Expect(TokenType.IF, "Ожидается 'if'");
Expect(TokenType.LPAREN, "Ожидается '(' после if");
BoolExpression();
Expect(TokenType.RPAREN, "Ожидается ')' после условия");
// Проверяем then-часть
Statement();
// Проверяем else-часть, если она есть
if (CurrentToken().Type == TokenType.ELSE)
{
Expect(TokenType.ELSE, "Ожидается 'else'");
Statement();
}
}
// BoolExpression → Expression Relop Expression
private void BoolExpression()
{
Expression();
Token op = CurrentToken();
if (op.Type != TokenType.LT && op.Type != TokenType.GT &&
op.Type != TokenType.EQ && op.Type != TokenType.NE)
{
_errors.Add(new SyntaxError($"Ожидается оператор сравнения, но найдено {op.Value}", op.Line, op.Column));
return;
}
_position++;
Expression();
}
// Expression → Term {('+' | '-') Term}
private void Expression()
{
Term();
while (CurrentToken().Type == TokenType.PLUS || CurrentToken().Type == TokenType.MINUS)
{
Token op = CurrentToken();
_position++;
Term();
}
}
// Term → Factor {('*' | '/') Factor}
private void Term()
{
Factor();
while (CurrentToken().Type == TokenType.MULTIPLY || CurrentToken().Type == TokenType.DIVIDE)
{
Token op = CurrentToken();
_position++;
Factor();
}
}
// Factor → Identifier | Number | '(' Expression ')'
private void Factor()
{
Token token = CurrentToken();
if (token.Type == TokenType.IDENTIFIER)
{
_position++;
}
else if (token.Type == TokenType.NUMBER)
{
_position++;
}
else if (token.Type == TokenType.LPAREN)
{
_position++;
Expression();
Expect(TokenType.RPAREN, "Ожидается ')'");
}
else
{
_errors.Add(new SyntaxError($"Ожидается число, переменная или '(', но найдено {token.Value}", token.Line, token.Column));
}
}
}
// Интерпретатор CBAS (только выполнение, без проверки ошибок)
// Выполняет программу
public class Interpreter
{
private List<Token> _tokens;
private int _position;
private Dictionary<string, int> _variables; // значения переменных
public Interpreter(List<Token> tokens)
{
_tokens = tokens;
_position = 0;
_variables = new Dictionary<string, int>();
}
public void Execute()
{
Program();
}
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)
{
if (!Match(type))
{
throw new Exception($"Ожидается {type}, но найдено {CurrentToken().Type}");
}
}
// 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:
