From a31d3b297fbe67d0228b8a3fc20243d30a211d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Muhammed=20Yasinhan=20Ya=C5=9Far?= Date: Fri, 25 Apr 2025 07:30:55 +0300 Subject: [PATCH 1/4] better syntax errors with also column information --- Makefile | 2 +- examples/snake/snake.tile | 38 ++++++++++++------------- src/tile/AntlrToExpression.java | 27 ++++++++++-------- src/tile/AntlrToStatement.java | 37 +++++++++++++----------- src/tile/app/Log.java | 44 ++++++++++++++++------------- src/tile/app/Tile.java | 22 ++++++++++++++- src/tile/err/TileErrorListener.java | 40 ++++++++++++++++++++++++++ 7 files changed, 141 insertions(+), 69 deletions(-) create mode 100644 src/tile/err/TileErrorListener.java diff --git a/Makefile b/Makefile index eff0fed..e2e9735 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ gen: # $(MKDIR_P) build: $(MKDIR_P) - javac -cp $(ANTLR) $(PACKAGE_PATH)/*.java src/tile/*.java src/tile/app/*.java src/tile/ast/base/*.java src/tile/ast/stmt/*.java src/tile/ast/expr/*.java src/tile/ast/types/*.java src/tile/sym/*.java -d $(BUILD) + javac -cp $(ANTLR) $(PACKAGE_PATH)/*.java src/tile/*.java src/tile/app/*.java src/tile/ast/base/*.java src/tile/ast/stmt/*.java src/tile/ast/expr/*.java src/tile/ast/types/*.java src/tile/sym/*.java src/tile/err/*.java -d $(BUILD) run: java -cp "$(ANTLR)$(CLASSPATH_SEP).$(CLASSPATH_SEP)$(BUILD)" org.antlr.v4.gui.TestRig $(PACKAGE).$(LANG) $(RULE) -gui ./examples/test.tile diff --git a/examples/snake/snake.tile b/examples/snake/snake.tile index 56dda72..5e8069f 100644 --- a/examples/snake/snake.tile +++ b/examples/snake/snake.tile @@ -19,18 +19,18 @@ native func IsKeyDown(key: ci16): ci8; native func SetRandomSeed(seed: cu32): cvoid; native func GetRandomValue(min: ci32, max: ci32): ci32; +screenWidth: int = 400; +screenHeight: int = screenWidth; -func run_game(width: int, height: int): void { - - dirs: int[] = int[50]; +func run_game(): void { + prev_dirs: int[] = int[50]; posx: float[] = float[50]; posy: float[] = float[50]; + dirs: int[] = int[50]; - SetRandomSeed(4642); - snake_count: int = 1; - snake_step: int = width / 10; + snake_step: int = screenWidth / 10; snake_size: int = snake_step; cherry_posx: float = GetRandomValue(0, 10) * snake_size; @@ -46,7 +46,7 @@ func run_game(width: int, height: int): void { bool game_over = false; // Main game loop - while (WindowShouldClose() == false && game_over == false) { // ESC closes the window as well + while ((bool)WindowShouldClose() == false && game_over == false) { // ESC closes the window as well // Update game logic based on timer move_timer = move_timer + GetFrameTime(); @@ -80,16 +80,16 @@ func run_game(width: int, height: int): void { } - if (posx[i] + snake_size / 2 > width) { + if (posx[i] + snake_size / 2 > screenWidth) { posx[i] = 0; } else if (posx[i] <= -snake_size) { - posx[i] = width - snake_size; + posx[i] = screenWidth - snake_size; } - if (posy[i] + snake_size / 2 > height) { + if (posy[i] + snake_size / 2 > screenHeight) { posy[i] = 0; } else if (posy[i] <= -snake_size) { - posy[i] = height - snake_size; + posy[i] = screenHeight - snake_size; } if (posx[0] == posx[i] && posy[0] == posy[i] && i != 0) { @@ -144,13 +144,13 @@ func run_game(width: int, height: int): void { // tiled background int line_color = 0x613701FF; - for (i: int = 0; i < width;) { + for (i: int = 0; i < screenWidth;) { i = i + snake_size; - DrawLine(i, 0, i, height, line_color); + DrawLine(i, 0, i, screenHeight, line_color); } - for (i: int = 0; i < height;) { + for (i: int = 0; i < screenHeight;) { i = i + snake_size; - DrawLine(0, i, width, i, line_color); + DrawLine(0, i, screenWidth, i, line_color); } EndDrawing(); @@ -159,15 +159,15 @@ func run_game(width: int, height: int): void { } -func main(argc: int): void { - screenWidth: int = 400; - screenHeight: int = screenWidth; +func main(argc: int): void { InitWindow(screenWidth, screenHeight, "Snake Game"); SetTargetFPS(60); // Set our game to run at 60 frames-per-second - run_game(screenWidth, screenHeight); + SetRandomSeed(4642); + + run_game(); // De-Initialization CloseWindow(); diff --git a/src/tile/AntlrToExpression.java b/src/tile/AntlrToExpression.java index 1bac21d..c0a456e 100644 --- a/src/tile/AntlrToExpression.java +++ b/src/tile/AntlrToExpression.java @@ -44,7 +44,6 @@ import tile.ast.expr.RelationalExpression; import tile.ast.expr.ShiftExpression; import tile.ast.expr.UnaryExpression; -import tile.ast.stmt.ForStmt; import tile.ast.types.TypeResolver; import tile.ast.types.TypeResolver.TypeFuncCall; import tile.ast.types.TypeResolver.TypeInfoArray; @@ -112,7 +111,8 @@ else if (ctx.IDENTIFIER() != null) { tasmIdx = TasmSymbolGenerator.identifierScopeFind(identifier, varType, isGlobal); } catch (Exception e) { int line = ctx.IDENTIFIER().getSymbol().getLine(); - Log.error(line + ": variable " + "'" + identifier + "' is not defined before use!"); + int col = ctx.IDENTIFIER().getSymbol().getCharPositionInLine(); + Log.error(line + ":" + col + ": variable " + "'" + identifier + "' is not defined before use!"); } expr = new PrimaryExpression(unaryOp, identifier, varType.toString(), true, tasmIdx, 0); @@ -261,6 +261,7 @@ public Expression visitFuncCallExpression(FuncCallExpressionContext ctx) { String funcId = ctx.IDENTIFIER().getText(); TypeFuncCall type = new TypeFuncCall(); int line = ctx.IDENTIFIER().getSymbol().getLine(); + int col = ctx.IDENTIFIER().getSymbol().getCharPositionInLine(); boolean is_native = false; @@ -274,7 +275,7 @@ public Expression visitFuncCallExpression(FuncCallExpressionContext ctx) { type.result_type = Program.nativeFuncDeclSymbols.get(funcId).getReturnType(); is_native = true; } catch (Exception e) { - Log.error(line + ": function " + funcId + " is not defined before called."); + Log.error(line + ":" + col + ": function " + funcId + " is not defined before called."); } } @@ -288,7 +289,7 @@ public Expression visitFuncCallExpression(FuncCallExpressionContext ctx) { // TODO: check nativeness if (ctx.primaryExpression() == null && ctx.funcCallExpression() == null) { if (arg_size != ctx.expression().size()) { - Log.error(line + ": function call" + funcId + " doesn't match by argument count, expected " + arg_size + " but got " +ctx.expression().size()); + Log.error(line + ":" + col + ": function call" + funcId + " doesn't match by argument count, expected " + arg_size + " but got " +ctx.expression().size()); return null; } @@ -298,7 +299,7 @@ public Expression visitFuncCallExpression(FuncCallExpressionContext ctx) { } } else { if (arg_size != ctx.expression().size() + 1) { - Log.error(line + ": function call" + funcId + " doesn't match by argument count, expected " + arg_size + " but got " + (ctx.expression().size() + 1)); + Log.error(line + ":" + col + ": function call" + funcId + " doesn't match by argument count, expected " + arg_size + " but got " + (ctx.expression().size() + 1)); return null; } if (ctx.primaryExpression() != null) { @@ -345,7 +346,8 @@ public Expression visitLogicalAndExpression(LogicalAndExpressionContext ctx) { if (!lhs_type.equals("bool") || !rhs_type.equals("bool")) { int line = ctx.stop.getLine(); - Log.warning(line + ": logical expressions type should be a bool type!"); + int col = ctx.stop.getCharPositionInLine(); + Log.warning(line + ":" + col + ": logical expressions type should be a bool type!"); } TypeInfoLogicalBinop type = TypeResolver.resolveBinopLogicalType(lhs_type, rhs_type); left = new LogicalExpression(left, operator, right, type); @@ -443,10 +445,10 @@ else if (ctx.incDecOperator() != null) { String incDecOp = ctx.incDecOperator().getText(); if (ctx.primaryExpression().IDENTIFIER() != null) { if (!(type.equals("int") || type.equals("float"))) { - Log.error("'++' and '--' operators cannot go before any non-numeric type!"); + Log.error("'" + incDecOp + "' operator cannot go before any non-numeric type!"); } } else { - Log.error("'++' and '--' operators had to be used with an identifier!"); + Log.error("'" + incDecOp + " operator had to be used with an identifier!"); } } } else { @@ -470,7 +472,8 @@ public Expression visitArraySizedInitializer(ArraySizedInitializerContext ctx) { String sizeExprType = expr.getType(); if (!sizeExprType.equals("int")) { int line = ctx.primaryTypeName().getStop().getLine(); - Log.error(line + "Array sized initializer must be an 'int' type!"); + int col = ctx.primaryTypeName().getStop().getCharPositionInLine(); + Log.error(line + ":" + col + ": Array sized initializer must be an 'int' type!"); } arrSizes.add(expr); } @@ -497,7 +500,8 @@ public Expression visitArrayIndexAccessor(ArrayIndexAccessorContext ctx) { // TODO: use isGlobal!!! } catch (Exception e) { int line = ctx.IDENTIFIER().getSymbol().getLine(); - Log.error(line + ": variable " + "'" + identifier + "' is not defined before use!"); + int col = ctx.IDENTIFIER().getSymbol().getCharPositionInLine(); + Log.error(line + ":" + col + ": variable " + "'" + identifier + "' is not defined before use!"); } ctx.arrayIndexSpecifier().size(); @@ -509,7 +513,8 @@ public Expression visitArrayIndexAccessor(ArrayIndexAccessorContext ctx) { Expression expr = visit(ctx.arrayIndexSpecifier(i).expression()); if (!TypeResolver.isIntType(expr.getType())) { int line = ctx.IDENTIFIER().getSymbol().getLine(); - Log.error(line + ": Array index specifier must be 'int' type!"); + int col = ctx.IDENTIFIER().getSymbol().getCharPositionInLine(); + Log.error(line + ":" + col + ": Array index specifier must be 'int' type!"); } exprs.add(expr); } diff --git a/src/tile/AntlrToStatement.java b/src/tile/AntlrToStatement.java index ec4febf..b2271af 100644 --- a/src/tile/AntlrToStatement.java +++ b/src/tile/AntlrToStatement.java @@ -1,8 +1,6 @@ package tile; -import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Deque; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -12,7 +10,6 @@ import gen.antlr.tile.tileParser.BlockStmtContext; import gen.antlr.tile.tileParser.ExpressionStmtContext; import gen.antlr.tile.tileParser.ForStmtContext; -import gen.antlr.tile.tileParser.ForUpdateContext; import gen.antlr.tile.tileParser.FuncCallExpressionContext; import gen.antlr.tile.tileParser.FuncDefStmtContext; import gen.antlr.tile.tileParser.GlobalStatementContext; @@ -28,11 +25,7 @@ import gen.antlr.tile.tileParser.VariableStmtContext; import gen.antlr.tile.tileParser.TasmBlockContext; import gen.antlr.tile.tileParser.WhileStmtContext; -import gen.antlr.tile.tileParser.TypeDefinitionContext; -import gen.antlr.tile.tileParser.StructDefinitionContext; -import gen.antlr.tile.tileParser.FieldDefinitionContext; import gen.antlr.tile.tileParser.ForInitialContext; -import gen.antlr.tile.tileParser.TypeUnionContext; import gen.antlr.tile.tileParserBaseVisitor; import tile.app.Log; import tile.ast.base.*; @@ -40,7 +33,6 @@ import tile.ast.stmt.FunctionDefinition.FuncArg; import tile.ast.types.TypeResolver; import tile.ast.types.TypeResolver.TypeFuncCall; -import tile.ast.types.TypeResolver.TypeInfoArray; import tile.ast.types.TypeResolver.TypeInfoRetStmt; import tile.ast.types.TypeResolver.TypeInfoVariableDef; import tile.sym.TasmSymbolGenerator; @@ -102,7 +94,8 @@ public Statement visitBlockStmt(BlockStmtContext ctx) { if (blockStmt.variableSymbols.containsKey(tasmVarSym)) { int line = ((FuncDefStmtContext)parentFunc).IDENTIFIER().getSymbol().getLine(); - Log.error(line + ": variable " + "'" + varId + "' is already defined in the same scope!"); + int col = ((FuncDefStmtContext)parentFunc).IDENTIFIER().getSymbol().getCharPositionInLine(); + Log.error(line + ":" + col + ": variable " + "'" + varId + "' is already defined in the same scope!"); } blockStmt.variableSymbols.put(tasmVarSym, vd); } @@ -128,7 +121,8 @@ public Statement visitBlockStmt(BlockStmtContext ctx) { if (blockStmt.variableSymbols.containsKey(tasmVarSym)) { int line = ((FuncDefStmtContext)parentFunc).IDENTIFIER().getSymbol().getLine(); - Log.error(line + ": variable " + "'" + varId + "' is already defined in the same scope!"); + int col = ((FuncDefStmtContext)parentFunc).IDENTIFIER().getSymbol().getCharPositionInLine(); + Log.error(line + ":" + col + ": variable " + "'" + varId + "' is already defined in the same scope!"); } if (init instanceof VariableDefinition) { @@ -172,7 +166,8 @@ public Statement visitBlockStmt(BlockStmtContext ctx) { if (blockStmt.variableSymbols.containsKey(tasmVarSym)) { int line = ((FuncDefStmtContext)parentFunc).IDENTIFIER().getSymbol().getLine(); - Log.error(line + ": variable " + "'" + varId + "' is already defined in the same scope!"); + int col = ((FuncDefStmtContext)parentFunc).IDENTIFIER().getSymbol().getCharPositionInLine(); + Log.error(line + ":" + col + ": variable " + "'" + varId + "' is already defined in the same scope!"); } blockStmt.variableSymbols.put(tasmVarSym, ((Variable)stmt)); @@ -230,7 +225,8 @@ public Statement visitForStmt(ForStmtContext ctx) { if (!(((ExpressionStmt)condition).getType().equals("bool"))) { int line = ctx.KW_FOR().getSymbol().getLine(); - System.err.println("WARNING:" + line + ": for condition expression type should be a bool type!"); + int col = ctx.KW_FOR().getSymbol().getCharPositionInLine(); + Log.warning(line + ":" + col + ": for condition expression type should be a bool type!"); } AntlrToExpression exprVisitor = new AntlrToExpression(); @@ -332,7 +328,8 @@ public Statement visitIfStmt(IfStmtContext ctx) { if (!(expr.getType().equals("bool"))) { int line = ctx.KW_IF().getSymbol().getLine(); - System.err.println("WARNING:" + line + ": if condition expression type should be a bool type!"); + int col = ctx.KW_IF().getSymbol().getCharPositionInLine(); + Log.warning(line + ":" + col + ": if condition expression type should be a bool type!"); } stmt = visit(ctx.blockStmt(0)); @@ -369,7 +366,8 @@ public Statement visitReturnStmt(ReturnStmtContext ctx) { } if (parent == null) { int line = ctx.KW_RETURN().getSymbol().getLine(); - Log.error(line + ": " + "return statement cannot be used outside a function definiton!"); + int col = ctx.KW_RETURN().getSymbol().getCharPositionInLine(); + Log.error(line + ":" + col + ": return statement cannot be used outside a function definiton!"); return null; } @@ -412,7 +410,8 @@ public Statement visitWhileStmt(WhileStmtContext ctx) { if (!(expr.getType().equals("bool"))) { int line = ctx.KW_WHILE().getSymbol().getLine(); - Log.warning(line + ": while condition expression type should be a bool type!"); + int col = ctx.KW_WHILE().getSymbol().getCharPositionInLine(); + Log.warning(line + ":" + col + ": while condition expression type should be a bool type!"); } stmt = visit(ctx.blockStmt()); @@ -439,12 +438,15 @@ public Statement visitVariableAssignment(VariableAssignmentContext ctx) { // TODO: use isGlobal!!! } catch (Exception e) { int line = -1; + int col = -1; if (ctx.arrayIndexAccessorSetter() != null) { line = ctx.arrayIndexAccessorSetter().IDENTIFIER().getSymbol().getLine(); + col = ctx.arrayIndexAccessorSetter().IDENTIFIER().getSymbol().getCharPositionInLine(); } else { line = ctx.IDENTIFIER().getSymbol().getLine(); + col = ctx.IDENTIFIER().getSymbol().getCharPositionInLine(); } - Log.error(line + ": variable " + "'" + varId + "' is not defined before assignment!"); + Log.error(line + ":" + col + ": variable " + "'" + varId + "' is not defined before assignment!"); } String assignmentOperator = ctx.assignmentOperator().getText(); @@ -466,7 +468,8 @@ public Statement visitVariableAssignment(VariableAssignmentContext ctx) { Expression expr = exprVisitor.visit(ctx.arrayIndexAccessorSetter().arrayIndexSpecifier(i).expression()); if (!TypeResolver.isIntType(expr.getType())) { int line = ctx.arrayIndexAccessorSetter().IDENTIFIER().getSymbol().getLine(); - Log.error(line + ": Array index specifier setter must be 'int' type!"); + int col = ctx.arrayIndexAccessorSetter().IDENTIFIER().getSymbol().getCharPositionInLine(); + Log.error(line + ":" + col + ": Array index specifier setter must be 'int' type!"); } exprs.add(expr); } diff --git a/src/tile/app/Log.java b/src/tile/app/Log.java index 46c2aaa..921e100 100644 --- a/src/tile/app/Log.java +++ b/src/tile/app/Log.java @@ -20,38 +20,42 @@ public static void setDebugMode(boolean debugMode) { isDebugMode = debugMode; } - /** - * Prints an error message with red ERROR prefix - * @param message The error message to print - */ + // --- f-postfix methods --- + + public static String errorf(String message) { + return RED + "ERROR: " + RESET + message; + } + + public static String warningf(String message) { + return YELLOW + "WARNING: " + RESET + message; + } + + public static String debugf(String message) { + return BLUE + "DEBUG: " + RESET + message; + } + + public static String infof(String message) { + return message; + } + + // --- printing methods --- + public static void error(String message) { - System.err.println(RED + "ERROR: " + RESET + message); + System.err.println(errorf(message)); Program.setError(); } - /** - * Prints a warning message with yellow WARNING prefix - * @param message The warning message to print - */ public static void warning(String message) { - System.out.println(YELLOW + "WARNING: " + RESET + message); + System.out.println(warningf(message)); } - /** - * Prints a debug message with blue DEBUG prefix if debug mode is enabled - * @param message The debug message to print - */ public static void debug(String message) { if (isDebugMode) { - System.out.println(BLUE + "DEBUG: " + RESET + message); + System.out.println(debugf(message)); } } - /** - * Prints a regular info message without prefix - * @param message The info message to print - */ public static void info(String message) { - System.out.println(message); + System.out.println(infof(message)); } } \ No newline at end of file diff --git a/src/tile/app/Tile.java b/src/tile/app/Tile.java index 865639d..3ec22bc 100644 --- a/src/tile/app/Tile.java +++ b/src/tile/app/Tile.java @@ -7,6 +7,9 @@ import java.util.Arrays; import org.antlr.v4.runtime.tree.ParseTree; + +import tile.err.TileErrorListener; + import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; @@ -37,7 +40,24 @@ public static void main(String args[]) { Log.setDebugMode(results.debug); tileParser parser = createTileParser(results.inputFile); + + // syntax errors + TileErrorListener errorListener = new TileErrorListener(); + parser.removeErrorListeners(); + parser.addErrorListener(errorListener); + + ParseTree ast = parser.program(); + + // check for syntax errors + if (errorListener.hasErrors()) { + System.out.println("Parsing failed with the following errors:"); + for (String error : errorListener.getErrorMessages()) { + System.out.println(error); + } + System.exit(2); + } + AntlrToProgram programVisitor = new AntlrToProgram(); Program program = programVisitor.visit(ast); @@ -82,7 +102,7 @@ private static tileParser createTileParser(String filePath) { parser = new tileParser(tokens); } catch (IOException e) { Log.error(filePath + " file cannot found!"); - System.exit(2); + System.exit(3); } return parser; diff --git a/src/tile/err/TileErrorListener.java b/src/tile/err/TileErrorListener.java new file mode 100644 index 0000000..b727fd9 --- /dev/null +++ b/src/tile/err/TileErrorListener.java @@ -0,0 +1,40 @@ +package tile.err; + +import org.antlr.v4.runtime.BaseErrorListener; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; + +import tile.app.Log; + +import java.util.ArrayList; +import java.util.List; + +public class TileErrorListener extends BaseErrorListener { + private final List errorMessages = new ArrayList<>(); + private boolean hasErrors = false; + + @Override + public void syntaxError(Recognizer recognizer, + Object offendingSymbol, + int line, + int col, + String msg, + RecognitionException e) { + hasErrors = true; + String errorMessage = Log.errorf(line + ":" + col + ": Syntax Error - " + msg); + errorMessages.add(errorMessage); + } + + public boolean hasErrors() { + return hasErrors; + } + + public List getErrorMessages() { + return new ArrayList<>(errorMessages); + } + + public void clearErrors() { + errorMessages.clear(); + hasErrors = false; + } +} \ No newline at end of file From 34aa992b240e7dc4faea97753b63a43b4585dc37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Muhammed=20Yasinhan=20Ya=C5=9Far?= Date: Mon, 28 Apr 2025 14:54:47 +0300 Subject: [PATCH 2/4] array index accessor can be called when defined in global scope as well --- src/tile/AntlrToExpression.java | 8 +++++++- src/tile/ast/expr/ArrayIndexAccessor.java | 24 ++++++++++++++++++++--- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/tile/AntlrToExpression.java b/src/tile/AntlrToExpression.java index c0a456e..7026274 100644 --- a/src/tile/AntlrToExpression.java +++ b/src/tile/AntlrToExpression.java @@ -276,6 +276,7 @@ public Expression visitFuncCallExpression(FuncCallExpressionContext ctx) { is_native = true; } catch (Exception e) { Log.error(line + ":" + col + ": function " + funcId + " is not defined before called."); + return null; // FIXME: find a better way and consider func overloading as well for the future! } } @@ -523,7 +524,12 @@ public Expression visitArrayIndexAccessor(ArrayIndexAccessorContext ctx) { int reducedDim = exprs.size(); typeInfo = TypeResolver.resolveArrayIndexAccessor(varType.toString(), reducedDim); - return new ArrayIndexAccessor(typeInfo, tasmIdx, exprs); + ArrayIndexAccessor aia = new ArrayIndexAccessor(typeInfo, tasmIdx, exprs); + if (isGlobal.get() == true) { + aia.setAsGlobal(); + } + + return aia; } @Override diff --git a/src/tile/ast/expr/ArrayIndexAccessor.java b/src/tile/ast/expr/ArrayIndexAccessor.java index 05e4047..d5040a2 100644 --- a/src/tile/ast/expr/ArrayIndexAccessor.java +++ b/src/tile/ast/expr/ArrayIndexAccessor.java @@ -10,29 +10,47 @@ public class ArrayIndexAccessor implements Expression { TypeInfoArray typeInfo; private int identifierTasmIdx; List indicies; + boolean isGlobal; public ArrayIndexAccessor(TypeInfoArray typeInfo, int identifierTasmIdx, List indicies) { this.typeInfo = typeInfo; this.identifierTasmIdx = identifierTasmIdx; this.indicies = indicies; + isGlobal = false; + } + + private String genLoadCode(String generatedCode) { + if (isGlobal) { + generatedCode += " gload " + identifierTasmIdx + "\n"; + } else { + generatedCode += " load " + identifierTasmIdx + "\n"; + } + return generatedCode; } @Override public String generateTasm(String generatedCode) { - generatedCode += " load " + identifierTasmIdx + "\n"; + generatedCode = genLoadCode(generatedCode); generatedCode += " deref ; dereferance\n"; - // FIXME: + generatedCode += " derefb " + typeInfo.element_size + " ; dereferance\n"; generatedCode = indicies.get(0).generateTasm(generatedCode); generatedCode += " push " + typeInfo.element_size + "\n"; generatedCode += " mult\n"; generatedCode += " add\n"; - generatedCode += " deref ; dereferance\n"; return generatedCode; + + + // generatedCode += " derefb " + typeInfo.element_size + " ; dereferance\n"; + // generatedCode += " deref ; dereferance\n"; } @Override public String getType() { return typeInfo.type; } + + public void setAsGlobal() { + isGlobal = true; + } } From 3bc0c99aad303d5c02dc0d107d68c27eadc8b32f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Muhammed=20Yasinhan=20Ya=C5=9Far?= Date: Thu, 1 May 2025 19:06:52 +0300 Subject: [PATCH 3/4] started user defined types and || or operator is implemented --- src/tile/AntlrToExpression.java | 27 ++++++++++- src/tile/AntlrToStatement.java | 52 +++++++++------------- src/tile/ast/expr/LogicalExpression.java | 2 + src/tile/ast/stmt/TypeDefinition.java | 17 +++---- src/tile/ast/stmt/VariableDecleration.java | 4 +- tileParser.g4 | 5 +++ 6 files changed, 64 insertions(+), 43 deletions(-) diff --git a/src/tile/AntlrToExpression.java b/src/tile/AntlrToExpression.java index cc9a2a6..ad1044c 100644 --- a/src/tile/AntlrToExpression.java +++ b/src/tile/AntlrToExpression.java @@ -358,8 +358,31 @@ public Expression visitLogicalAndExpression(LogicalAndExpressionContext ctx) { @Override public Expression visitLogicalOrExpression(LogicalOrExpressionContext ctx) { - // TODO Auto-generated method stub - return super.visitLogicalOrExpression(ctx); + if (ctx.logicalAndExpression().size() == 1) { + return visit(ctx.logicalAndExpression(0)); + } + + // Otherwise, process the operator and operands. + Expression left = visit(ctx.logicalAndExpression(0)); // The first operand. + for (int i = 1; i < ctx.logicalAndExpression().size(); i++) { + // Get the operator (* or /). + String operator = ctx.getChild((i * 2) - 1).getText(); // Operators are at odd indices. + + // Visit the right operand. + Expression right = visit(ctx.logicalAndExpression(i)); + + String lhs_type = left.getType(); + String rhs_type = right.getType(); + + if (!lhs_type.equals("bool") || !rhs_type.equals("bool")) { + int line = ctx.stop.getLine(); + int col = ctx.stop.getCharPositionInLine(); + Log.warning(line + ":" + col + ": logical expressions type should be a bool type!"); + } + TypeInfoLogicalBinop type = TypeResolver.resolveBinopLogicalType(lhs_type, rhs_type); + left = new LogicalExpression(left, operator, right, type); + } + return left; } @Override diff --git a/src/tile/AntlrToStatement.java b/src/tile/AntlrToStatement.java index fd52ab9..bb1a58b 100644 --- a/src/tile/AntlrToStatement.java +++ b/src/tile/AntlrToStatement.java @@ -24,11 +24,13 @@ import gen.antlr.tile.tileParser.ProgramContext; import gen.antlr.tile.tileParser.ReturnStmtContext; import gen.antlr.tile.tileParser.SelectionStmtContext; +import gen.antlr.tile.tileParser.StructDefinitionContext; import gen.antlr.tile.tileParser.VariableAssignmentContext; import gen.antlr.tile.tileParser.VariableDeclerationContext; import gen.antlr.tile.tileParser.VariableDefinitionContext; import gen.antlr.tile.tileParser.VariableStmtContext; import gen.antlr.tile.tileParser.TasmBlockContext; +import gen.antlr.tile.tileParser.TypeDefinitionContext; import gen.antlr.tile.tileParser.WhileStmtContext; import gen.antlr.tile.tileParser.ForInitialContext; import gen.antlr.tile.tileParserBaseVisitor; @@ -263,38 +265,26 @@ else if (ctx.variableStmt() != null) { return result; } - // @Override - // public Statement visitTypeDefinition(TypeDefinitionContext ctx) { - // String name = ctx.IDENTIFIER().getText(); - - // if (ctx.structDefinition() != null) { - // TypeDefinition def = new TypeDefinition(name, TypeDefinition.Kind.STRUCT); - // List fields = new ArrayList<>(); - - // for (var fieldCtx : ctx.structDefinition().fieldDefinition()) { - // String fieldName = fieldCtx.IDENTIFIER().getText(); - // String fieldType = fieldCtx.typeName().getText(); - // fields.add(new String(fieldName, fieldType)); - // } - - // def.fields = fields; - // TypeResolver.userTypeDefs.put(name, def); - - // } else if (ctx.typeUnion() != null) { - // TypeDefinition def = new TypeDefinition(name, TypeDefinition.Kind.UNION); - - // List variants = ctx.typeUnion().IDENTIFIER() - // .stream() - // .map(ParseTree::getText) - // .toList(); - - // def.variants = variants; - // TypeResolver.userTypeDefs.put(name, def); - // } + @Override + public Statement visitTypeDefinition(TypeDefinitionContext ctx) { + String typeName = ctx.IDENTIFIER().getText(); + List fields = null; + TypeDefinition.Kind kind = null; + if (ctx.structDefinition() != null) { + fields = new ArrayList<>(); + kind = TypeDefinition.Kind.STRUCT; + for (int i = 0; i < ctx.structDefinition().fieldDefinition().size(); i++) { + String id = ctx.structDefinition().fieldDefinition(i).IDENTIFIER().getText(); + String type = ctx.structDefinition().fieldDefinition(i).typeName().getText(); + TypeDefinition.Field field = new TypeDefinition.Field(id, type); + fields.add(field); + } + } - // return new ExpressionStmt(null, false); - // return super.visitTypeDefinition(ctx); - // } + TypeDefinition td = new TypeDefinition(typeName, kind, fields); + TypeResolver.userTypeDefs.put(typeName, td); + return td; + } @Override public Statement visitFuncDefStmt(FuncDefStmtContext ctx) { diff --git a/src/tile/ast/expr/LogicalExpression.java b/src/tile/ast/expr/LogicalExpression.java index 440ad33..55d3288 100644 --- a/src/tile/ast/expr/LogicalExpression.java +++ b/src/tile/ast/expr/LogicalExpression.java @@ -28,6 +28,8 @@ public String generateTasm(String generatedCode) { if (operator.equals("&&")) { generatedCode += " and\n"; + } else if (operator.equals("||")) { + generatedCode += " or\n"; } return generatedCode; diff --git a/src/tile/ast/stmt/TypeDefinition.java b/src/tile/ast/stmt/TypeDefinition.java index 9021d3d..c795070 100644 --- a/src/tile/ast/stmt/TypeDefinition.java +++ b/src/tile/ast/stmt/TypeDefinition.java @@ -10,25 +10,26 @@ public enum Kind { UNION } - public String name; + public String typeName; public Kind kind; public static class Field { - public String name; + public String id; public String type; - public Field(String name, String type) { - this.name = name; + public Field(String id, String type) { + this.id = id; this.type = type; } } - public List fields; // for struct - public List variants; // for union + private List fields; // for struct + private List variants; // for union - public TypeDefinition(String name, Kind kind) { - this.name = name; + public TypeDefinition(String typeName, Kind kind, List fields) { + this.typeName = typeName; this.kind = kind; + this.fields = fields; } @Override diff --git a/src/tile/ast/stmt/VariableDecleration.java b/src/tile/ast/stmt/VariableDecleration.java index 6734d0b..5590395 100644 --- a/src/tile/ast/stmt/VariableDecleration.java +++ b/src/tile/ast/stmt/VariableDecleration.java @@ -37,8 +37,8 @@ public String generateTasm(String generatedCode) { // 0 for all defined types // user defined null (0) if (isGlobal) { - generatedCode += "push 0\n"; - generatedCode += "gstore " + tasmIdx + " ; " + typeInfo + " " + varId + "\n"; + // generatedCode += "push 0\n"; + // generatedCode += "gstore " + tasmIdx + " ; " + typeInfo + " " + varId + "\n"; } else { generatedCode += " push 0\n"; generatedCode += " store " + tasmIdx + " ; " + typeInfo + " " + varId + "\n"; diff --git a/tileParser.g4 b/tileParser.g4 index 406c4a2..d2565bd 100644 --- a/tileParser.g4 +++ b/tileParser.g4 @@ -87,6 +87,10 @@ objectLiteralFieldAssignment : '.' IDENTIFIER assignmentOperator expression ; +objectAccessor + : IDENTIFIER '.' IDENTIFIER + ; + unaryExpression : incDecOperator primaryExpression | primaryExpression incDecOperator @@ -233,6 +237,7 @@ variableDefinition variableAssignment : IDENTIFIER assignmentOperator expressionStmt | arrayIndexAccessorSetter assignmentOperator expressionStmt + | objectAccessor assignmentOperator expressionStmt ; loopStmt From 4a108112968d1e78a7a36c1444b67f9e39224427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Muhammed=20Yasinhan=20Ya=C5=9Far?= Date: Sat, 3 May 2025 17:54:28 +0300 Subject: [PATCH 4/4] static analyse if function returns or not --- src/tile/AntlrToStatement.java | 40 +++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/tile/AntlrToStatement.java b/src/tile/AntlrToStatement.java index bb1a58b..68e16e1 100644 --- a/src/tile/AntlrToStatement.java +++ b/src/tile/AntlrToStatement.java @@ -47,6 +47,19 @@ public class AntlrToStatement extends tileParserBaseVisitor { + public static boolean staticReturnAnalysis(BlockStmt blck) { + for (Statement stmt : blck.statements) { + if (stmt instanceof ReturnStmt) { + return true; + } else if (stmt instanceof BlockStmt) { + if (staticReturnAnalysis((BlockStmt)stmt)) { + return true; + } + } + } + return false; + } + @Override public Statement visitBlockStmt(BlockStmtContext ctx) { BlockStmt blockStmt = null; @@ -158,6 +171,20 @@ public Statement visitBlockStmt(BlockStmtContext ctx) { if (Program.parentStack.isEmpty() || !(Program.parentStack.peek() instanceof ForStmt)) { Program.blockStack.remove(Program.blockStack.size() - 1); } + + // static analysis if func returns the correct thing + if (parent instanceof FuncDefStmtContext) { + if (!(func.getReturn_type().result_type.equals("void"))) { + boolean isReturned = staticReturnAnalysis(blockStmt); + if (!isReturned) { + int line = ((FuncDefStmtContext)parentFunc).IDENTIFIER().getSymbol().getLine(); + int col = ((FuncDefStmtContext)parentFunc).IDENTIFIER().getSymbol().getCharPositionInLine(); + Log.error(line + ":" + col + ": function should return!"); + } + } + } + + return blockStmt; } @@ -182,7 +209,18 @@ public Statement visitBlockStmt(BlockStmtContext ctx) { } blockStmt.addStatement(stmt); } - + + // static analysis if func returns the correct thing + if (parent instanceof FuncDefStmtContext) { + if (!(func.getReturn_type().result_type.equals("void"))) { + boolean isReturned = staticReturnAnalysis(blockStmt); + if (!isReturned) { + int line = ((FuncDefStmtContext)parentFunc).IDENTIFIER().getSymbol().getLine(); + int col = ((FuncDefStmtContext)parentFunc).IDENTIFIER().getSymbol().getCharPositionInLine(); + Log.error(line + ":" + col + ": function should return!"); + } + } + } if (Program.parentStack.isEmpty() || !(Program.parentStack.peek() instanceof ForStmt)) { Program.blockStack.remove(Program.blockStack.size() - 1);