Синтаксис модельного языка:
Структура программы: <программа>::= program var <описание> begin <оператор> {; <оператор>} end.
Синтаксис описания данных: <описание>::= <тип> <идентификатор> { , <идентификатор> }
Синтаксис идентификаторов: <буква> <непустая последовательность букв> <цифра>
Описание типов (в порядке следования: целый, действительный, логический): <тип>::= int | float | bool
Синтаксис составного оператора: <составной>::= «{» <оператор> { ; <оператор> } «}»
Синтаксис оператора присваивания: <присваивание>::= <идентификатор> ass <выражение>
Синтаксис оператора условного перехода: <условный>::=if (<выражение>): <оператор> [ else : <оператор>]
Синтаксис оператора фиксированного цикла: <фиксированного_цикла>::= for ( [<выражение>] ; [<выражение>] ; [<выражение>] ) <оператор>
Синтаксис условного оператора: <условного_цикла>::= do while <выражение> <оператор> loop
Синтаксис оператора ввода: <ввода>::= read (<идентификатор> {, <идентификатор> })
Синтаксис оператора вывода: <вывода>::= write (<выражение> {, <выражение> })
Синтаксис оформления комментариев: признак начала комментария: /*, признак конца комментария: */

Мой parser:
import java.util.Iterator;
import java.util.List;

class Parser {
private Iterator<Token> tokenIter;
private Token currentToken;

public Parser(List<Token> tokens) {
    tokenIter = tokens.iterator();
    advance();
}

private void advance() {
    if (tokenIter.hasNext()) {
        currentToken = tokenIter.next();
        if (currentToken.type == Token.TokenType.WHITESPACE || currentToken.type == Token.TokenType.COMMENT) {
            advance();
        }
    } else {
        currentToken = null;
    }
}

private void expect(Token.TokenType type, String value) {
    if (currentToken.type == Token.TokenType.SYMBOL && currentToken.value.equals(";") && tokenIter.hasNext()) {
        advance();
    } else {
        if (currentToken.type != type || !currentToken.value.equals(value)) {
            throw new RuntimeException("Unexpected token: " + currentToken);
        }
    }
    advance();
}

public void parse() {
    parseProgram();
}

private void parseProgram() {
    expect(Token.TokenType.KEYWORD, "program");
    expect(Token.TokenType.KEYWORD, "var");

    parseDescription();

    expect(Token.TokenType.KEYWORD, "begin");

    while (currentToken != null && !"end".equals(currentToken.value)) {
        parseStatement();

        if (currentToken != null && ";".equals(currentToken.value)) {
            advance();
        }
    }

    expect(Token.TokenType.KEYWORD, "end");
}

private void parseDescription() {
    parseType();
    parseIdentifier();

    while (currentToken != null && ",".equals(currentToken.value)) {
        advance();
        parseIdentifier();
    }
}

private void parseType() {
    if (currentToken.type != Token.TokenType.KEYWORD || (!"int".equals(currentToken.value) && !"float".equals(currentToken.value) && !"bool".equals(currentToken.value))) {
        throw new RuntimeException("Unexpected token (expected type keyword): " + currentToken);
    }
    advance();
}

private void parseIdentifier() {
    expect(Token.TokenType.IDENTIFIER, currentToken.value);
}

private void parseStatement() {
    switch (currentToken.value) {
        case "if":
            parseIfStatement();
            break;
        case "for":
            parseForStatement();
            break;
        case "do":
            parseDoWhileStatement();
            break;
        case "read":
        case "write":
            parseReadWriteStatement();
            break;
        default:
            parseAssignment();
    }

    // Проверка символа ‘;’ после вызова разбора операторов
    if (currentToken != null && ";".equals(currentToken.value)) {
        advance();
    }
}



private void parseIfStatement() {
    advance();
    System.out.println(currentToken);
    expect(Token.TokenType.SYMBOL, "(");
    System.out.println(currentToken);
    parseExpression();
    System.out.println(currentToken);
    expect(Token.TokenType.SYMBOL, ")");
    parseStatement();

    if ("else".equals(currentToken.value)) {
        advance();
        parseStatement();
    }
}

private void parseForStatement() {
    advance();
    expect(Token.TokenType.SYMBOL, "(");

    if (!";".equals(currentToken.value)) {
        parseExpression();
    }
    expect(Token.TokenType.SYMBOL, ";");

    if (!";".equals(currentToken.value)) {
        parseExpression();
    }
    expect(Token.TokenType.SYMBOL, ";");

    if (!")".equals(currentToken.value)) {
        parseExpression();
    }
    expect(Token.TokenType.SYMBOL, ")");

    parseStatement();
}

private void parseDoWhileStatement() {
    advance();
    expect(Token.TokenType.KEYWORD, "while");
    parseExpression();
    parseStatement();
    expect(Token.TokenType.KEYWORD, "loop");
}

private void parseReadWriteStatement() {
    String keyword = currentToken.value;
    advance();
    expect(Token.TokenType.SYMBOL, "(");
    parseIdentifier();

    while (",".equals(currentToken.value)) {
        advance();
        parseIdentifier();
    }

    expect(Token.TokenType.SYMBOL, ")");
}

private void parseAssignment() {
    expect(Token.TokenType.SYMBOL, "ass");
    parseExpression();
}

private void parseExpression() {
    parseArithmeticExpression();

    while (currentToken != null && isComparisonOperator(currentToken.value)) {
        String comparisonOperator = currentToken.value;
        advance();
        parseArithmeticExpression();
    }
}

private void parseArithmeticExpression() {
    // Здесь добавьте код для разбора арифметических операций.
    // Для упрощения примера, просто переходим к следующему токену.
    advance();
}

private boolean isComparisonOperator(String value) {
    return value.equals("==") || value.equals("!=") || value.equals("<") || value.equals(">") || value.equals("<=") || value.equals(">=");
}

private void parseComparision() {
    parseArithmeticExpression();

    if (currentToken != null && isComparisonOperator(currentToken.value)) {
        String comparisonOperator = currentToken.value;
        advance();
        parseArithmeticExpression();
    }
}
}

Сделай так чтобы then нормально обрабатывалось