From e833d2e311500a8a55c1575f866e43567cdd52cd Mon Sep 17 00:00:00 2001 From: Kyler <59854022+KylerOlsen@users.noreply.github.com> Date: Tue, 5 Mar 2024 23:51:01 -0700 Subject: [PATCH] More compiler fixes --- .gitignore | 1 + docs/ytd 12-bit computer.md | 39 +++---- examples/test2.ytd12c | 125 ++++++++++++++++++++++ pytd12dk/compiler/syntactical_analyzer.py | 104 ++++++++++++------ 4 files changed, 220 insertions(+), 49 deletions(-) diff --git a/.gitignore b/.gitignore index c880298..ea7c26f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ docs/*.pdf __pycache__ bin +.vscode diff --git a/docs/ytd 12-bit computer.md b/docs/ytd 12-bit computer.md index 7709f8d..091f82c 100644 --- a/docs/ytd 12-bit computer.md +++ b/docs/ytd 12-bit computer.md @@ -237,35 +237,36 @@ and a `literal`. #### If Statement An `if statement` begins with the `if` keyword, followed by its condition, an -`expression` enclosed in parentheses (`(` and `)`), then a list enclosed in -curly braces (`{` and `}`) of `statements`. It may then optionally be followed -by an `else block`. +`expression` enclosed in parentheses (`(` and `)`), then a single `statement` +or a list enclosed in curly braces (`{` and `}`) of `statements`. It may then +optionally be followed by an `else block`. #### Do Loop -A `do loop` begins with the `do` keyword, followed by a list enclosed in curly -braces (`{` and `}`) of `statements`. It is then followed with the `while` -keyword, then by its condition, an `expression` enclosed in parentheses -(`(` and `)`). It may then optionally be followed by another list enclosed in -curly braces (`{` and `}`) of `statements`. Finally the `do loop` may optionally -be followed by an `else block`. +A `do loop` begins with the `do` keyword, followed by a single `statement` or a +list enclosed in curly braces (`{` and `}`) of `statements`. It is then followed +with the `while` keyword, then by its condition, an `expression` enclosed in +parentheses (`(` and `)`). It may then optionally be followed by a single +`statement` or another list enclosed in curly braces (`{` and `}`) of +`statements`. Finally the `do loop` may optionally be followed by an +`else block`. #### While Loop A `while loop` begins with the `while` keyword, followed by its condition, an -`expression` enclosed in parentheses (`(` and `)`), then a list enclosed in -curly braces (`{` and `}`) of `statements`. It may then +`expression` enclosed in parentheses (`(` and `)`), then a single `statement` +or a list enclosed in curly braces (`{` and `}`) of `statements`. It may then optionally be followed by an `else block`. #### For Loop A `for loop` begins with the `for` keyword, followed by three expressions -enclosed in parentheses (`(` and `)`), separated by semicolons (`;`). The first -expression is a *pre-loop expression*, the second is its condition which is a -normal `expression`, and the last is its post-loop expression which is another -normal `expression`. It is ended with a list enclosed in curly braces -(`{` and `}`) of `statements`. It may then optionally be -followed by an `else block`. +enclosed in parentheses (`(` and `)`), separated by semicolons (`;`). The +first expression is a *pre-loop expression*, the second is its condition which +is a normal `expression`, and the last is its post-loop expression which is +another normal `expression`. It is ended with a single `statement` or a list +enclosed in curly braces (`{` and `}`) of `statements`. It may then optionally +be followed by an `else block`. ##### Pre-Loop Expression @@ -275,8 +276,8 @@ then an equal sign (`=`) followed by an `expression`. #### Else Block -An `else block` begins with the `else` keyword, followed by a list enclosed in -curly braces (`{` and `}`) of `statements`. +An `else block` begins with the `else` keyword, followed by a single +`statement` or a list enclosed in curly braces (`{` and `}`) of `statements`. #### Let Statement diff --git a/examples/test2.ytd12c b/examples/test2.ytd12c index d9431fb..4964367 100644 --- a/examples/test2.ytd12c +++ b/examples/test2.ytd12c @@ -82,6 +82,131 @@ fn test_func2() -> Point { test = '"'; test = "Hello World!"; test = "This is \"cool\"!"; + + break; + continue; + + if (test >= 10); + + if (test >= 20) + test -= 2; + test -= 3; + + if (test >= 20) + test -= 2; + else + test -= 3; + + if (test >= 30) { + test -= 4; + test -= 5; + } + + if (test >= 40) { + test -= 6; + } else { + test += 15; + } + + if (test >= 50) { + test -= 7; + } else if (test >= 60) { + test--; + } else { + test += 16; + } + + do + test += 17; + while (test); + + do + test += 18; + while (test) + test += 19; + + do + test += 20; + while (test) + else + test += 21; + + do + test += 22; + while (test) + test += 23; + else + test += 24; + + do + test += 25; + while (test) + test += 26; + else if (test == 32) + test += 27; + + do { + test += 18; + } while (test); + + do { + test += 29; + } while (test) { + test += 30; + } + + do { + test += 31; + } while (test) + else { + test += 32; + } + + do { + test += 33; + } while (test) { + test += 34; + } else { + test += 35; + } + + while (test >= 20) + test -= 2; + test -= 3; + + while (test >= 20) + test -= 2; + else + test -= 3; + + while (test >= 30) { + test -= 4; + test -= 5; + } + + while (test >= 40) { + test -= 6; + } else { + test += 15; + } + + for (i: int = 0; i < length; i++) + $(inData + i) ^= $(pass + ((i + offset) % pLength)); + + for (i: int = 0; i < length; i++) + $(inData + i) ^= $(pass + ((i + offset) % pLength)); + else + test = 16; + + for (i: int; i < length; i++) { + $(inData + i) ^= $(pass + ((i + offset) % pLength)); + } + + for (i = 0; i < length; i++) { + $(inData + i) ^= $(pass + ((i + offset) % pLength)); + } else { + test = 17; + } } fn main() -> int { diff --git a/pytd12dk/compiler/syntactical_analyzer.py b/pytd12dk/compiler/syntactical_analyzer.py index 90cf468..78a4775 100644 --- a/pytd12dk/compiler/syntactical_analyzer.py +++ b/pytd12dk/compiler/syntactical_analyzer.py @@ -142,7 +142,8 @@ type Expression = ( UnaryExpression | BinaryExpression | TernaryExpression | - FunctionCall + FunctionCall | + NoOperation ) type Statement = Expression | LetStatement | LoopStatements | NestableCodeBlock @@ -167,7 +168,7 @@ class LoopStatements(Enum): BreakStatement = "break" def tree_str(self, pre: str = "", pre_cont: str = "") -> str: - s: str = f"{pre} {self.value.upper()}\n" + s: str = f"{pre} {self.value.lower()}\n" return s @@ -276,6 +277,13 @@ _Operator_Precedence: tuple[ ) +class NoOperation: + + def tree_str(self, pre: str = "", pre_cont: str = "") -> str: + s: str = f"{pre} Nop\n" + return s + + class Identifier: _content: str @@ -533,14 +541,14 @@ class ForPreDef: _identifier: Identifier _type: DataType _pointer: bool - _assignment: Expression + _assignment: Expression | None def __init__( self, identifier: Identifier, type: DataType, pointer: bool, - assignment: Expression, + assignment: Expression | None, ): self._identifier = identifier self._type = type @@ -549,10 +557,11 @@ class ForPreDef: def tree_str(self, pre: str = "", pre_cont: str = "") -> str: s: str = f"{pre} For Loop Pre-Definition: {self._identifier}\n" - s += f"{pre_cont}├─ Type: " + if self._assignment: s += f"{pre_cont}├─ Type: " + else: s += f"{pre_cont}└─ Type: " if self._pointer: s+= "@" s += f"{self._type}\n" - s += f"{pre_cont}└─ Value: {self._assignment}\n" + if self._assignment: s += f"{pre_cont}└─ Value: {self._assignment}\n" return s @@ -579,7 +588,7 @@ class ForBlock: self._else = else_block def tree_str(self, pre: str = "", pre_cont: str = "") -> str: - s: str = f"{pre} If Statement\n" + s: str = f"{pre} For Loop\n" if self._code or self._else is not None: cond_pre = f"{pre_cont}├─" cond_pre_cont = f"{pre_cont}│ " @@ -675,12 +684,8 @@ class DoBlock: def tree_str(self, pre: str = "", pre_cont: str = "") -> str: s: str = f"{pre} Do Loop\n" if self._first_code: - if self._second_code or self._else is not None: - s += f"{pre_cont}├─ First Code\n" - code_pre = f"{pre_cont}│ " - else: - s += f"{pre_cont}└─ First Code\n" - code_pre = f"{pre_cont} " + s += f"{pre_cont}├─ First Code\n" + code_pre = f"{pre_cont}│ " for code in self._first_code[:-1]: s += code.tree_str(code_pre + "├─", code_pre + "│ ") s += self._first_code[-1].tree_str( @@ -950,7 +955,7 @@ class File: self._children = children[:] def tree_str(self) -> str: - s: str = "File\n" + s: str = " File\n" if self._children: for child in self._children[:-1]: s += child.tree_str("├─", "│ ") @@ -1353,31 +1358,59 @@ def _statement_sa(tokens: list[lexer.Token]) -> Statement: return LoopStatements(key) case 'if': condition = _expression_sa(_get_nested_group(tokens)) - code = _code_block_sa(tokens) - if tokens[0].value == 'else': - else_block = ElseBlock(_code_block_sa(tokens)) + if tokens[0].value == '{': + code = _code_block_sa(_get_nested_group(tokens, ('{','}'))) + else: + code = [_statement_sa(tokens)] + if tokens and tokens[0].value == 'else': + token = tokens.pop(0) + if tokens[0].value == '{': + else_block = ElseBlock(_code_block_sa(_get_nested_group( + tokens, ('{','}')))) + else: + else_block = ElseBlock([_statement_sa(tokens)]) else: else_block = None return IfBlock(condition, code, else_block) case 'do': - code1 = _code_block_sa(tokens) + if tokens[0].value == '{': + code1 = _code_block_sa(_get_nested_group(tokens, ('{','}'))) + else: + code1 = [_statement_sa(tokens)] token = tokens.pop(0) _assert_token(ExpectedKeyword, token, 'while') condition = _expression_sa(_get_nested_group(tokens)) if tokens[0].value == '{': - code2 = _code_block_sa(tokens) + code2 = _code_block_sa(_get_nested_group(tokens, ('{','}'))) + elif tokens[0].value != 'else': + code2 = [_statement_sa(tokens)] + if isinstance(code2[0], NoOperation): + code2 = None else: code2 = None - if tokens[0].value == 'else': - else_block = ElseBlock(_code_block_sa(tokens)) + if tokens and tokens[0].value == 'else': + token = tokens.pop(0) + if tokens[0].value == '{': + else_block = ElseBlock(_code_block_sa(_get_nested_group( + tokens, ('{','}')))) + else: + else_block = ElseBlock([_statement_sa(tokens)]) else: else_block = None return DoBlock(code1, condition, code2, else_block) case 'while': condition = _expression_sa(_get_nested_group(tokens)) - code = _code_block_sa(tokens) - if tokens[0].value == 'else': - else_block = ElseBlock(_code_block_sa(tokens)) + if tokens[0].value == '{': + code = _code_block_sa(_get_nested_group(tokens, ('{','}'))) + else: + code = [_statement_sa(tokens)] + if tokens and tokens[0].value == 'else': + token = tokens.pop(0) + if tokens[0].value == '{': + else_block = ElseBlock(_code_block_sa(_get_nested_group( + tokens, ('{','}')))) + else: + else_block = ElseBlock([_statement_sa(tokens)]) else: else_block = None return WhileBlock(condition, code, else_block) @@ -1388,9 +1421,8 @@ def _statement_sa(tokens: list[lexer.Token]) -> Statement: while token.value != ';': pre_loop_tokens.append(token) token = three_expressions.pop(0) - token = three_expressions.pop(0) if ( - type(pre_loop_tokens[0]) is lexer.Identifier and + isinstance(pre_loop_tokens[0], lexer.Identifier) and pre_loop_tokens[1].value == ':' ): identifier = Identifier(pre_loop_tokens.pop(0).value) @@ -1401,6 +1433,8 @@ def _statement_sa(tokens: list[lexer.Token]) -> Statement: token = pre_loop_tokens.pop(0) _assert_token(ExpectedPunctuation, token, '=') pre_loop_expr = _expression_sa(pre_loop_tokens) + else: + pre_loop_expr = None pre_loop = ForPreDef( identifier, data_type, @@ -1409,16 +1443,24 @@ def _statement_sa(tokens: list[lexer.Token]) -> Statement: ) else: pre_loop = _expression_sa(pre_loop_tokens) + token = three_expressions.pop(0) loop_condition_tokens: list[lexer.Token] = [] while token.value != ';': loop_condition_tokens.append(token) token = three_expressions.pop(0) - token = three_expressions.pop(0) condition = _expression_sa(loop_condition_tokens) post_loop = _expression_sa(three_expressions) - code = _code_block_sa(tokens) - if tokens[0].value == 'else': - else_block = ElseBlock(_code_block_sa(tokens)) + if tokens[0].value == '{': + code = _code_block_sa(_get_nested_group(tokens, ('{','}'))) + else: + code = [_statement_sa(tokens)] + if tokens and tokens[0].value == 'else': + token = tokens.pop(0) + if tokens[0].value == '{': + else_block = ElseBlock(_code_block_sa(_get_nested_group( + tokens, ('{','}')))) + else: + else_block = ElseBlock([_statement_sa(tokens)]) else: else_block = None return ForBlock( @@ -1434,6 +1476,8 @@ def _statement_sa(tokens: list[lexer.Token]) -> Statement: 'while', 'for', ] + [i.value for i in BuiltInConst]) + elif token.value == ';': + return NoOperation() expr_tokens: list[lexer.Token] = [token] + _get_to_symbol(tokens) return _expression_sa(expr_tokens)