Finished SynAn without good errors

This commit is contained in:
Gašper Dobrovoljc
2025-03-21 15:28:24 +01:00
parent b1e61398a6
commit a94802b571
9 changed files with 688 additions and 173 deletions

View File

@@ -1,98 +1,205 @@
package pins25.common;
import java.util.HashMap;
/**
* Leksikalni simbol.
*
*
* @param location Lokacija simbola v izvornem programu.
* @param symbol Vrsta simbola.
* @param lexeme Znakovna predstavitev simbola.
*/
public record Token(Report.Location location, Symbol symbol, String lexeme) implements Report.Locatable {
/**
* Vrste leksikalnih simbolov.
*/
public enum Symbol {
/** Konec datoteke. */
EOF,
/** Stevilo. */
INTCONST,
/** Znak. */
CHARCONST,
/** Niz znakov. */
STRINGCONST,
/** Ime. */
IDENTIFIER,
/** Kljucna beseda {@code fun}. */
FUN,
/** Kljucna beseda {@code var}. */
VAR,
/** Kljucna beseda {@code if}. */
IF,
/** Kljucna beseda {@code then}. */
THEN,
/** Kljucna beseda {@code else}. */
ELSE,
/** Kljucna beseda {@code while}. */
WHILE,
/** Kljucna beseda {@code do}. */
DO,
/** Kljucna beseda {@code let}. */
LET,
/** Kljucna beseda {@code in}. */
IN,
/** Kljucna beseda {@code end}. */
END,
/** Simbol {@code =}. */
ASSIGN,
/** Simbol {@code ,}. */
COMMA,
/** Simbol {@code &&}. */
AND,
/** Simbol {@code ||}. */
OR,
/** Simbol {@code !}. */
NOT,
/** Simbol {@code ==}. */
EQU,
/** Simbol {@code !=}. */
NEQ,
/** Simbol {@code >}. */
GTH,
/** Simbol {@code <}. */
LTH,
/** Simbol {@code >=}. */
GEQ,
/** Simbol {@code <=}. */
LEQ,
/** Simbol {@code +}. */
ADD,
/** Simbol {@code -}. */
SUB,
/** Simbol {@code *}. */
MUL,
/** Simbol {@code /}. */
DIV,
/** Simbol {@code %}. */
MOD,
/** Simbol {@code ^}. */
PTR,
/** Simbol {@code (}. */
LPAREN,
/** Simbol {@code )}. */
RPAREN,
}
/**
* Vrste leksikalnih simbolov.
*/
public enum Symbol {
/**
* Konec datoteke.
*/
EOF,
/**
* Stevilo.
*/
INTCONST,
/**
* Znak.
*/
CHARCONST,
/**
* Niz znakov.
*/
STRINGCONST,
/**
* Ime.
*/
IDENTIFIER,
/**
* Kljucna beseda {@code fun}.
*/
FUN,
/**
* Kljucna beseda {@code var}.
*/
VAR,
/**
* Kljucna beseda {@code if}.
*/
IF,
/**
* Kljucna beseda {@code then}.
*/
THEN,
/**
* Kljucna beseda {@code else}.
*/
ELSE,
/**
* Kljucna beseda {@code while}.
*/
WHILE,
/**
* Kljucna beseda {@code do}.
*/
DO,
/**
* Kljucna beseda {@code let}.
*/
LET,
/**
* Kljucna beseda {@code in}.
*/
IN,
/**
* Kljucna beseda {@code end}.
*/
END,
/**
* Simbol {@code =}.
*/
ASSIGN,
/**
* Simbol {@code ,}.
*/
COMMA,
/**
* Simbol {@code &&}.
*/
AND,
/**
* Simbol {@code ||}.
*/
OR,
/**
* Simbol {@code !}.
*/
NOT,
/**
* Simbol {@code ==}.
*/
EQU,
/**
* Simbol {@code !=}.
*/
NEQ,
/**
* Simbol {@code >}.
*/
GTH,
/**
* Simbol {@code <}.
*/
LTH,
/**
* Simbol {@code >=}.
*/
GEQ,
/**
* Simbol {@code <=}.
*/
LEQ,
/**
* Simbol {@code +}.
*/
ADD,
/**
* Simbol {@code -}.
*/
SUB,
/**
* Simbol {@code *}.
*/
MUL,
/**
* Simbol {@code /}.
*/
DIV,
/**
* Simbol {@code %}.
*/
MOD,
/**
* Simbol {@code ^}.
*/
PTR,
/**
* Simbol {@code (}.
*/
LPAREN,
/**
* Simbol {@code )}.
*/
RPAREN;
@Override
public String toString() {
String lexeme = switch (symbol) {
case INTCONST -> "(" + this.lexeme + ")";
case CHARCONST -> "(" + this.lexeme + ")";
case STRINGCONST -> "(" + this.lexeme + ")";
case IDENTIFIER -> "(" + this.lexeme + ")";
default -> "";
};
return location + " " + symbol + lexeme;
}
public String prettyPrint() {
return switch (this) {
case INTCONST -> "integer constant";
case CHARCONST -> "character constant";
case STRINGCONST -> "string constant";
case IDENTIFIER -> "identifier";
case FUN -> "'fun'";
case VAR -> "'var'";
case IF -> "'if'";
case THEN -> "'then'";
case ELSE -> "'else'";
case WHILE -> "'while'";
case DO -> "'do'";
case LET -> "'let'";
case IN -> "'in'";
case END -> "'end'";
case ASSIGN -> "'='";
case COMMA -> "','";
case AND -> "'&&'";
case OR -> "'||'";
case NOT -> "'!'";
case EQU -> "'=='";
case NEQ -> "'!='";
case GTH -> "'>'";
case LTH -> "'<'";
case GEQ -> "'>='";
case LEQ -> "'<='";
case ADD -> "'+'";
case SUB -> "'-'";
case MUL -> "'*'";
case DIV -> "'/'";
case MOD -> "'%'";
case PTR -> "'^'";
case LPAREN -> "'('";
case RPAREN -> "')'";
default -> this.toString();
};
}
}
@Override
public String toString() {
String lexeme = switch (symbol) {
case INTCONST, IDENTIFIER, CHARCONST, STRINGCONST -> "(" + this.lexeme + ")";
default -> "";
};
return location + " " + symbol + lexeme;
}
}

View File

@@ -38,7 +38,7 @@ public class SynAn implements AutoCloseable {
private Token check(Token.Symbol symbol) {
final Token token = lexAn.takeToken();
if (token.symbol() != symbol)
throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected " + symbol + ".");
throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected " + symbol.prettyPrint() + ".");
return token;
}
@@ -54,21 +54,26 @@ public class SynAn implements AutoCloseable {
}
private void parseProgram() {
System.out.println("program -> definition restdefs");
parseDefinition();
parseRestDefinitions();
}
private void parseRestDefinitions() {
if (lexAn.peekToken().symbol() != Token.Symbol.EOF) {
System.out.println("restdefs -> definition restdefs");
parseDefinition();
parseRestDefinitions();
} else {
System.out.println("restdefs -> ε");
}
}
private void parseDefinition() {
Token token = lexAn.peekToken();
switch (token.symbol()) {
case Token.Symbol.FUN:
case FUN:
System.out.println("definition -> FUN IDENTIFIER LPAREN parameters RPAREN funcassign");
check(Token.Symbol.FUN);
check(Token.Symbol.IDENTIFIER);
check(Token.Symbol.LPAREN);
@@ -77,7 +82,8 @@ public class SynAn implements AutoCloseable {
parseFunctionAssignment();
break;
case Token.Symbol.VAR:
case VAR:
System.out.println("definition -> VAR IDENTIFIER ASSIGN initializers");
check(Token.Symbol.VAR);
check(Token.Symbol.IDENTIFIER);
check(Token.Symbol.ASSIGN);
@@ -91,78 +97,80 @@ public class SynAn implements AutoCloseable {
private void parseFunctionAssignment() {
Token token = lexAn.peekToken();
switch (token.symbol()) {
case Token.Symbol.FUN:
case Token.Symbol.VAR:
case Token.Symbol.IN:
case Token.Symbol.EOF:
break;
case Token.Symbol.ASSIGN:
check(Token.Symbol.ASSIGN);
parseStatements();
break;
default:
throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected ASSIGN.");
if (token.symbol() == Token.Symbol.ASSIGN) {
System.out.println("funcassign -> ASSIGN statements");
check(Token.Symbol.ASSIGN);
parseStatements();
} else {
System.out.println("funcassign -> ε");
}
}
private void parseParameters() {
Token token = lexAn.peekToken();
switch (token.symbol()) {
case Token.Symbol.IDENTIFIER:
check(Token.Symbol.IDENTIFIER);
parseRestParameters();
break;
case Token.Symbol.RPAREN:
break;
default:
throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected IDENTIFIER or RPAREN.");
if (token.symbol() == Token.Symbol.IDENTIFIER) {
System.out.println("parameters -> IDENTIFIER restparams");
check(Token.Symbol.IDENTIFIER);
parseRestParameters();
} else {
System.out.println("parameters -> ε");
}
}
private void parseRestParameters() {
Token token = lexAn.peekToken();
switch (token.symbol()) {
case Token.Symbol.RPAREN:
break;
case Token.Symbol.COMMA:
check(Token.Symbol.COMMA);
check(Token.Symbol.IDENTIFIER);
parseRestParameters();
break;
default:
throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected ')' or ','.");
if (token.symbol() == Token.Symbol.COMMA) {
System.out.println("restparams -> COMMA IDENTIFIER restparams");
check(Token.Symbol.COMMA);
check(Token.Symbol.IDENTIFIER);
parseRestParameters();
} else {
System.out.println("restparams -> ε");
}
}
private void parseStatements() {
System.out.println("statements -> statement reststmts");
parseStatement();
parseRestStatements();
}
private void parseExpressionAssign() {
if (lexAn.peekToken().symbol() == Token.Symbol.ASSIGN) {
System.out.println("exprassign -> ASSIGN expression");
check(Token.Symbol.ASSIGN);
parseExpression();
} else {
System.out.println("exprassign -> ε");
}
}
private void parseElseStatement() {
if (lexAn.peekToken().symbol() == Token.Symbol.ELSE) {
System.out.println("elsestmt -> ELSE statements");
check(Token.Symbol.ELSE);
parseStatements();
} else {
System.out.println("elsestmt -> ε");
}
}
private void parseRestStatements() {
if (lexAn.peekToken().symbol() == Token.Symbol.COMMA) {
System.out.println("reststmts -> COMMA statement reststmts");
check(Token.Symbol.COMMA);
parseStatement();
parseRestStatements();
} else {
System.out.println("reststmts -> ε");
}
}
private void parseStatement() {
Token token = lexAn.peekToken();
switch (token.symbol()) {
case Token.Symbol.IDENTIFIER:
case Token.Symbol.LPAREN:
case Token.Symbol.ADD:
case Token.Symbol.SUB:
case Token.Symbol.NOT:
case Token.Symbol.PTR:
case Token.Symbol.INTCONST:
case Token.Symbol.CHARCONST:
case Token.Symbol.STRINGCONST:
parseExpression();
parseExpressionAssign();
break;
case Token.Symbol.IF:
case IF:
System.out.println("statement -> if expression then statements elsestmt end");
check(Token.Symbol.IF);
parseExpression();
check(Token.Symbol.THEN);
@@ -171,7 +179,8 @@ public class SynAn implements AutoCloseable {
check(Token.Symbol.END);
break;
case Token.Symbol.WHILE:
case WHILE:
System.out.println("statement -> while expression do statements end");
check(Token.Symbol.WHILE);
parseExpression();
check(Token.Symbol.DO);
@@ -179,7 +188,8 @@ public class SynAn implements AutoCloseable {
check(Token.Symbol.END);
break;
case Token.Symbol.LET:
case LET:
System.out.println("statement -> let definition reststmtdefs in statements end");
check(Token.Symbol.LET);
parseDefinition();
parseRestStatementDefinitions();
@@ -187,33 +197,318 @@ public class SynAn implements AutoCloseable {
parseStatements();
check(Token.Symbol.END);
break;
}
}
private void parseRestStatements() {
if (lexAn.peekToken().symbol() == Token.Symbol.COMMA) {
check(Token.Symbol.COMMA);
parseStatements();
default:
System.out.println("statement -> expression exprassign");
parseExpression();
parseExpressionAssign();
}
}
private void parseRestStatementDefinitions() {
switch (lexAn.peekToken().symbol()) {
case IN:
System.out.println("reststmtdefs -> ε");
break;
case FUN:
case VAR:
System.out.println("reststmtdefs -> definition reststmtdefs");
parseDefinition();
parseRestStatementDefinitions();
break;
}
}
private void parseInitializers() {
switch (lexAn.peekToken().symbol()) {
case INTCONST:
case CHARCONST:
case STRINGCONST:
System.out.println("initializers -> initializer restinits");
parseInitializer();
parseRestInitializers();
break;
default:
System.out.println("initializers -> ε");
break;
}
}
private void parseInitializer() {
Token token = lexAn.peekToken();
switch (token.symbol()) {
case INTCONST:
System.out.println("initializer -> INTCONST intconstmult");
check(Token.Symbol.INTCONST);
parseIntegerConstantMultiplier();
break;
case CHARCONST:
System.out.println("initializer -> CHARCONST");
check(Token.Symbol.CHARCONST);
break;
case STRINGCONST:
System.out.println("initializer -> STRINGCONST");
check(Token.Symbol.STRINGCONST);
break;
default:
throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected integer, character or string constant.");
}
}
private void parseRestInitializers() {
Token token = lexAn.peekToken();
if (token.symbol() == Token.Symbol.COMMA) {
System.out.println("restinits -> COMMA initializer restinits");
check(Token.Symbol.COMMA);
parseInitializer();
parseRestInitializers();
} else {
System.out.println("restinits -> ε");
}
}
private void parseIntegerConstantMultiplier() {
Token token = lexAn.peekToken();
if (token.symbol() == Token.Symbol.MUL) {
System.out.println("intconstmult -> MUL const");
check(Token.Symbol.MUL);
parseConstant();
} else {
System.out.println("intconstmult -> ε");
}
}
private void parseConstant() {
Token token = lexAn.peekToken();
switch (token.symbol()) {
case INTCONST:
System.out.println("const -> INTCONST");
check(Token.Symbol.INTCONST);
break;
case CHARCONST:
System.out.println("const -> CHARCONST");
check(Token.Symbol.CHARCONST);
break;
case STRINGCONST:
System.out.println("const -> STRINGCONST");
check(Token.Symbol.STRINGCONST);
break;
default:
throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected integer, character or string constant.");
}
}
private void parseExpression() {
System.out.println("expression -> conjexpr restdisj");
parseConjunctionExpression();
parseRestDisjunctions();
}
private void parseExpressionAssign() {
private void parseRestDisjunctions() {
if (lexAn.peekToken().symbol() == Token.Symbol.OR) {
System.out.println("restdisj -> OR conjexpr restdisj");
check(Token.Symbol.OR);
parseConjunctionExpression();
parseRestDisjunctions();
}
}
private void parseElseStatement() {
private void parseConjunctionExpression() {
System.out.println("conjexpr -> cmpexpr restconj");
parseComparisonExpression();
parseRestConjunctionExpressions();
}
private void parseRestConjunctionExpressions() {
if (lexAn.peekToken().symbol() == Token.Symbol.AND) {
System.out.println("restconj -> AND cmpexpr restconj");
check(Token.Symbol.AND);
parseComparisonExpression();
parseRestConjunctionExpressions();
} else {
System.out.println("restconj -> ε");
}
}
private void parseComparisonExpression() {
System.out.println("cmpexpr -> addexpr restcmp");
parseAdditionExpression();
parseRestComparisons();
}
private void parseRestComparisons() {
Token token = lexAn.peekToken();
switch (token.symbol()) {
case EQU:
case NEQ:
case LTH:
case GTH:
case LEQ:
case GEQ:
System.out.printf("restcmp -> %s addexpr\n", token.symbol());
check(token.symbol());
parseAdditionExpression();
break;
default:
System.out.println("restcmp -> ε");
break;
}
}
private void parseAdditionExpression() {
System.out.println("addexpr -> multexpr restadd");
parseMultiplicationExpression();
parseRestAdditions();
}
private void parseRestAdditions() {
Token token = lexAn.peekToken();
switch (token.symbol()) {
case ADD:
case SUB:
System.out.printf("restadd -> %s multexpr restadd\n", token.symbol());
check(token.symbol());
parseMultiplicationExpression();
parseRestAdditions();
break;
default:
System.out.println("restadd -> ε");
break;
}
}
private void parseMultiplicationExpression() {
System.out.println("multexpr -> prefixexpr restmult");
parsePrefixExpression();
parseRestMultiplicationExpressions();
}
private void parseRestMultiplicationExpressions() {
Token token = lexAn.peekToken();
switch (token.symbol()) {
case MUL:
case DIV:
case MOD:
System.out.printf("restmult -> %s prefixexpr restmult\n", token.symbol());
check(token.symbol());
parsePrefixExpression();
parseRestMultiplicationExpressions();
break;
default:
System.out.println("restmult -> ε");
break;
}
}
private void parsePrefixExpression() {
Token token = lexAn.peekToken();
switch (token.symbol()) {
case ADD:
case SUB:
case NOT:
case PTR:
System.out.printf("prefixexpr -> %s prefixexpr\n", token.symbol());
check(token.symbol());
parsePrefixExpression();
break;
default:
System.out.println("prefixexpr -> postfixexpr");
parsePostfixExpression();
break;
}
}
private void parsePostfixExpression() {
System.out.println("postfixexpr -> primary postfixop");
parsePrimary();
parsePostfixOperator();
}
private void parsePostfixOperator() {
if (lexAn.peekToken().symbol() == Token.Symbol.PTR) {
System.out.println("postfixop -> PTR postfixop");
check(Token.Symbol.PTR);
parsePostfixOperator();
} else {
System.out.println("postfixop -> ε");
}
}
private void parsePrimary() {
Token token = lexAn.peekToken();
switch (token.symbol()) {
case IDENTIFIER:
System.out.println("primary -> IDENTIFIER exprargs");
check(Token.Symbol.IDENTIFIER);
parseExpressionArguments();
break;
case LPAREN:
System.out.println("primary -> LPAREN expression RPAREN");
check(Token.Symbol.LPAREN);
parseExpression();
check(Token.Symbol.RPAREN);
break;
case INTCONST:
case CHARCONST:
case STRINGCONST:
System.out.println("primary -> const");
parseConstant();
break;
default:
throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected identifier, constant or '('.");
}
}
private void parseExpressionArguments() {
if (lexAn.peekToken().symbol() == Token.Symbol.LPAREN) {
System.out.println("exprargs -> LPAREN arguments RPAREN");
check(Token.Symbol.LPAREN);
parseArguments();
check(Token.Symbol.RPAREN);
} else {
System.out.println("exprargs -> ε");
}
}
private void parseArguments() {
Token token = lexAn.peekToken();
if (token.symbol() == Token.Symbol.RPAREN) {
System.out.println("arguments -> ε");
} else {
System.out.println("arguments -> expression restargs");
parseExpression();
parseRestArguments();
}
}
private void parseRestArguments() {
if (lexAn.peekToken().symbol() == Token.Symbol.COMMA) {
System.out.println("restargs -> COMMA restargs");
check(Token.Symbol.COMMA);
parseExpression();
parseRestArguments();
} else {
System.out.println("restargs -> ε");
}
}
// --- ZAGON ---
/**