From 0adbcba014580a2a7c916925e4eb31ec7cab6742 Mon Sep 17 00:00:00 2001 From: splasky Date: Sat, 5 May 2018 13:35:48 +0800 Subject: [PATCH 1/3] Generate file with file name --- shivyc/main.py | 12 +++++++++++- tests/test_all.py | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/shivyc/main.py b/shivyc/main.py index 4d72e8d..eadf6f5 100755 --- a/shivyc/main.py +++ b/shivyc/main.py @@ -33,7 +33,11 @@ def main(): if any(not obj for obj in objs): return 1 else: - if not link("out", objs): + # set the output ELF name + out = "out" + if arguments.output_name is not None: + out = arguments.output_name + if not link(out, objs): err = "linker returned non-zero status" print(CompilerError(err)) return 1 @@ -118,6 +122,12 @@ def get_arguments(): parser.add_argument("-z-reg-alloc-perf", help="display register allocator performance info", dest="show_reg_alloc_perf", action="store_true") + parser.add_argument( + "-o", + nargs="?", + metavar="file", + help="Place output into ", + dest="output_name") return parser.parse_args() diff --git a/tests/test_all.py b/tests/test_all.py index 9a4fa3e..18a11e7 100644 --- a/tests/test_all.py +++ b/tests/test_all.py @@ -46,6 +46,7 @@ class MockArguments: files = test_file_names show_reg_alloc_perf = False variables_on_stack = False + output_name = None shivyc.main.get_arguments = lambda: MockArguments() From b3f2e3f031cfb10dc4728441c171368fe690ffd1 Mon Sep 17 00:00:00 2001 From: splasky Date: Mon, 7 May 2018 21:59:46 +0800 Subject: [PATCH 2/3] Support void inside function definition --- shivyc/parser/declaration.py | 20 ++++++++++++++++---- tests/feature_tests/error_function_def.c | 7 +++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/shivyc/parser/declaration.py b/shivyc/parser/declaration.py index 87636b4..56b5696 100644 --- a/shivyc/parser/declaration.py +++ b/shivyc/parser/declaration.py @@ -252,10 +252,21 @@ def parse_parameter_list(index): if token_is(index, token_kinds.close_paren): return params, index + # argument is void and is not function declaration + if token_is(index, token_kinds.void_kw) \ + and token_is(index + 1, token_kinds.close_paren): + if token_is(index + 2, token_kinds.open_brack): + return params, index + 1 + elif token_is(index + 1, token_kinds.identifier): + err = "'void' must be the only parameter" + raise_error(err, index, ParserError.AT) + while True: # Try parsing declaration specifiers, quit if no more exist specs, index = parse_decl_specifiers(index) decl, index = parse_declarator(index) + + # New ast root params.append(decl_nodes.Root(specs, [decl])) # Expect a comma, and break if there isn't one @@ -357,8 +368,8 @@ def _find_decl_end(index): greater than the last index in this declarator. """ if (token_is(index, token_kinds.star) or - token_is(index, token_kinds.identifier) or - token_is(index, token_kinds.const_kw)): + token_is(index, token_kinds.identifier) or + token_is(index, token_kinds.const_kw)): return _find_decl_end(index + 1) elif token_is(index, token_kinds.open_paren): close = _find_pair_forward(index) @@ -392,7 +403,7 @@ def _parse_declarator_raw(start, end, is_typedef): return decl_nodes.Identifier(None) elif (start + 1 == end and - p.tokens[start].kind == token_kinds.identifier): + p.tokens[start].kind == token_kinds.identifier): p.symbols.add_symbol(p.tokens[start], is_typedef) return decl_nodes.Identifier(p.tokens[start]) @@ -402,7 +413,8 @@ def _parse_declarator_raw(start, end, is_typedef): _parse_declarator(index, end, is_typedef), const) func_decl = _try_parse_func_decl(start, end, is_typedef) - if func_decl: return func_decl + if func_decl: + return func_decl # First and last elements make a parenthesis pair elif (p.tokens[start].kind == token_kinds.open_paren and diff --git a/tests/feature_tests/error_function_def.c b/tests/feature_tests/error_function_def.c index 00cf608..606048a 100644 --- a/tests/feature_tests/error_function_def.c +++ b/tests/feature_tests/error_function_def.c @@ -58,6 +58,13 @@ const int func() { return 4; } +int func_void(void) { + return 4; +} + +// error: 'void' must be the only parameter +int func_void_void(void a,void b){} + // error: redefinition of 'a' void repeat_param(int a, int a) { } From 5e3476f8d5da914fc75f4b4d8247ef3bde5c805c Mon Sep 17 00:00:00 2001 From: splasky Date: Wed, 9 May 2018 13:44:41 +0800 Subject: [PATCH 3/3] Prohibit function parameter redefinition --- shivyc/tree/nodes.py | 10 ++++++++++ tests/feature_tests/error_declaration.c | 3 +++ 2 files changed, 13 insertions(+) diff --git a/shivyc/tree/nodes.py b/shivyc/tree/nodes.py index 434e291..532a9e3 100644 --- a/shivyc/tree/nodes.py +++ b/shivyc/tree/nodes.py @@ -600,6 +600,8 @@ def _generate_array_ctype(self, decl, prev_ctype): def _generate_func_ctype(self, decl, prev_ctype): """Generate a function ctype from a given a decl_node.""" + # save identifiers + identifiers = [] # Prohibit storage class specifiers in parameters. for param in decl.args: @@ -608,6 +610,14 @@ def _generate_func_ctype(self, decl, prev_ctype): err = "storage class specified for function parameter" raise CompilerError(err, decl_info.range) + if decl_info.identifier: + identifier = str(decl_info.identifier) + if identifier not in identifiers: + identifiers.append(str(decl_info.identifier)) + else: + err = f"redefinition of '{identifier}'" + raise CompilerError(err, decl_info.range) + # Create a new scope because if we create a new struct type inside # the function parameters, it should be local to those parameters. self.symbol_table.new_scope() diff --git a/tests/feature_tests/error_declaration.c b/tests/feature_tests/error_declaration.c index cd770ef..2c721a5 100644 --- a/tests/feature_tests/error_declaration.c +++ b/tests/feature_tests/error_declaration.c @@ -22,6 +22,9 @@ int var1; // error: redeclared 'var1' with different linkage static int var1; +// error: redefinition of 'a' +void repeat_param(int a, int a); + int main() { // error: variable of incomplete type declared void a;