545 lines
17 KiB
Java
545 lines
17 KiB
Java
package pins25.phase;
|
|
|
|
import pins25.common.*;
|
|
|
|
import java.util.Objects;
|
|
|
|
/**
|
|
* Sintaksni analizator.
|
|
*/
|
|
public class SynAn implements AutoCloseable {
|
|
|
|
/**
|
|
* Leksikalni analizator.
|
|
*/
|
|
private final LexAn lexAn;
|
|
|
|
/**
|
|
* Ustvari nov sintaksni analizator.
|
|
*
|
|
* @param srcFileName Ime izvorne datoteke.
|
|
*/
|
|
public SynAn(final String srcFileName) {
|
|
this.lexAn = new LexAn(srcFileName);
|
|
}
|
|
|
|
@Override
|
|
public void close() {
|
|
lexAn.close();
|
|
}
|
|
|
|
/**
|
|
* Prevzame leksikalni analizator od leksikalnega analizatorja in preveri, ali
|
|
* je prave vrste.
|
|
*
|
|
* @param symbol Pričakovana vrsta leksikalnega simbola.
|
|
* @return Prevzeti leksikalni simbol.
|
|
*/
|
|
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.prettyPrint() + ".");
|
|
return token;
|
|
}
|
|
|
|
/**
|
|
* Opravi sintaksno analizo.
|
|
*/
|
|
public void parse() {
|
|
parseProgram();
|
|
|
|
if (lexAn.peekToken().symbol() != Token.Symbol.EOF)
|
|
Report.warning(lexAn.peekToken(),
|
|
"Unexpected text '" + lexAn.peekToken().lexeme() + "...' at the end of the program.");
|
|
}
|
|
|
|
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 FUN:
|
|
System.out.println("definition -> FUN IDENTIFIER LPAREN parameters RPAREN funcassign");
|
|
check(Token.Symbol.FUN);
|
|
check(Token.Symbol.IDENTIFIER);
|
|
check(Token.Symbol.LPAREN);
|
|
parseParameters();
|
|
check(Token.Symbol.RPAREN);
|
|
parseFunctionAssignment();
|
|
break;
|
|
|
|
case VAR:
|
|
System.out.println("definition -> VAR IDENTIFIER ASSIGN initializers");
|
|
check(Token.Symbol.VAR);
|
|
check(Token.Symbol.IDENTIFIER);
|
|
check(Token.Symbol.ASSIGN);
|
|
parseInitializers();
|
|
break;
|
|
|
|
default:
|
|
throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected FUN or VAR.");
|
|
}
|
|
}
|
|
|
|
private void parseFunctionAssignment() {
|
|
Token token = lexAn.peekToken();
|
|
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();
|
|
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();
|
|
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 IF:
|
|
System.out.println("statement -> if expression then statements elsestmt end");
|
|
check(Token.Symbol.IF);
|
|
parseExpression();
|
|
check(Token.Symbol.THEN);
|
|
parseStatements();
|
|
parseElseStatement();
|
|
check(Token.Symbol.END);
|
|
break;
|
|
|
|
case WHILE:
|
|
System.out.println("statement -> while expression do statements end");
|
|
check(Token.Symbol.WHILE);
|
|
parseExpression();
|
|
check(Token.Symbol.DO);
|
|
parseStatements();
|
|
check(Token.Symbol.END);
|
|
break;
|
|
|
|
case LET:
|
|
System.out.println("statement -> let definition reststmtdefs in statements end");
|
|
check(Token.Symbol.LET);
|
|
parseDefinition();
|
|
parseRestStatementDefinitions();
|
|
check(Token.Symbol.IN);
|
|
parseStatements();
|
|
check(Token.Symbol.END);
|
|
break;
|
|
|
|
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 parseRestDisjunctions() {
|
|
if (lexAn.peekToken().symbol() == Token.Symbol.OR) {
|
|
System.out.println("restdisj -> OR conjexpr restdisj");
|
|
check(Token.Symbol.OR);
|
|
parseConjunctionExpression();
|
|
parseRestDisjunctions();
|
|
}
|
|
}
|
|
|
|
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 ---
|
|
|
|
/**
|
|
* Zagon sintaksnega analizatorja kot samostojnega programa.
|
|
*
|
|
* @param cmdLineArgs Argumenti v ukazni vrstici.
|
|
*/
|
|
public static void main(final String[] cmdLineArgs) {
|
|
System.out.println("This is PINS'25 compiler (syntax analysis):");
|
|
|
|
try {
|
|
if (cmdLineArgs.length == 0)
|
|
throw new Report.Error("No source file specified in the command line.");
|
|
if (cmdLineArgs.length > 1)
|
|
Report.warning("Unused arguments in the command line.");
|
|
|
|
try (SynAn synAn = new SynAn(cmdLineArgs[0])) {
|
|
synAn.parse();
|
|
}
|
|
|
|
// Upajmo, da kdaj pridemo to te tocke.
|
|
// A zavedajmo se sledecega:
|
|
// 1. Prevod je zaradi napak v programu lahko napacen :-o
|
|
// 2. Izvorni program se zdalec ni tisto, kar je programer hotel, da bi bil ;-)
|
|
Report.info("Done.");
|
|
} catch (Report.Error error) {
|
|
// Izpis opisa napake.
|
|
System.err.println(error.getMessage());
|
|
System.exit(1);
|
|
}
|
|
}
|
|
|
|
}
|