diff --git a/README.md b/README.md index bbec671..c15d6a2 100644 --- a/README.md +++ b/README.md @@ -19,83 +19,5 @@ and a possbility to compile Elna programs for different platforms. ## Grammar -```ebnf -digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"; -letter = "A" | "B" | … | "Z" | "a" | "b" | … | "z"; - -ident = letter { letter | digit | "_" }; -integer = digit { digit }; -float = integer "." integer; -boolean = "true" | "false"; - -literal = integer | float | boolean | "'" character "'" | """ { character } """; - -program = [ "type" type_definitions ";" ] - [ constant_part ] - { procedure_definition } - [ variable_part ] - "begin" [ statement_list ] "end" "."; - -procedure_definition = "proc" ident formal_parameter_list ";" ( block | "extern" ) ";"; - -block = [ constant_part ] - [ variable_part ] - statement; - -constant_part = "const" ident "=" integer { "," ident "=" integer } ";"; -variable_part = "var" variable_declarations ";"; - -statement = ident ":=" expression - | ident actual_parameter_list - | while_do - | if_then_else; - - -while_do = "while" condition "do" [ statement_list ] "end"; -if_then_else = "if" expression - "then" [ statement_list ] - [ else statement_list ] "end"; - -statement_list = statement {";" statement }; - -condition = "odd" expression | - expression ("="|"#"|"<"|"<="|">"|">=") expression; - -comparison_operator = "=", "<>", "<", ">", "<=", ">="; -unary_prefix = "not", "@"; - -expression = logical_operand { ("and" | "or") logical_operand }; -logical_operand = comparand { comparison_operator comparand }; -comparand = summand { ("+" | "-") summand }; -summand = factor { ("*" | "/") factor }; -factor = pointer { unary_prefix pointer }; - -pointer = literal - | designator_expression { $$ = $1; } - | "(" expression ")"; - -designator_expression = designator_expression "[" expression "]" - | designator_expression "." ident - | designator_expression "^" - | ident; - -formal_parameter_list = "(" [ variable_declarations ] ")"; - -actual_parameter_list = "(" [ expressions ] ")"; - -expressions = expression { "," expression }; - -variable_declarations = variable_declaration { ";" variable_declaration }; - -variable_declaration = ident ":" type_expression; - -type_expression = "array" integer "of" type_expression - | "pointer" "to" type_expression - | "record" field_list "end" - | "union" field_list "end" - | ident; - -field_list = field_declaration { ";" field_declaration }; - -field_declaration = ident ":" type_expression; -``` +Flex and bison grammar specifications, `lexer.ll` and `parser.yy`, can be found +in the `boot/` directory. diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index ad9ab53..193cf3e 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -25,37 +25,37 @@ namespace gcc void generic_visitor::visit(boot::call_expression *expression) { - if (auto symbol = this->symbol_map->lookup(expression->name())) - { - tree return_type = TREE_TYPE(TREE_TYPE(symbol->payload)); - tree fndecl_type = build_function_type(return_type, TYPE_ARG_TYPES(symbol->payload)); - tree printf_fn = build1(ADDR_EXPR, build_pointer_type(fndecl_type), symbol->payload); + tree symbol = this->symbol_map->lookup(expression->name()); - std::vector arguments(expression->arguments().size()); - for (std::size_t i = 0; i < expression->arguments().size(); ++i) - { - expression->arguments().at(i)->accept(this); - arguments[i] = this->current_expression; - } - tree stmt = build_call_array_loc(get_location(&expression->position()), - return_type, printf_fn, arguments.size(), arguments.data()); - - if (return_type == void_type_node) - { - append_to_statement_list(stmt, &this->current_statements); - this->current_expression = NULL_TREE; - } - else - { - this->current_expression = stmt; - } - } - else + if (symbol == NULL_TREE) { error_at(get_location(&expression->position()), "procedure '%s' not declared", expression->name().c_str()); this->current_expression = error_mark_node; + return; + } + tree return_type = TREE_TYPE(TREE_TYPE(symbol)); + tree fndecl_type = build_function_type(return_type, TYPE_ARG_TYPES(symbol)); + tree printf_fn = build1(ADDR_EXPR, build_pointer_type(fndecl_type), symbol); + + std::vector arguments(expression->arguments().size()); + for (std::size_t i = 0; i < expression->arguments().size(); ++i) + { + expression->arguments().at(i)->accept(this); + arguments[i] = this->current_expression; + } + tree stmt = build_call_array_loc(get_location(&expression->position()), + return_type, printf_fn, arguments.size(), arguments.data()); + + if (return_type == void_type_node) + { + append_to_statement_list(stmt, &this->current_statements); + this->current_expression = NULL_TREE; + } + else + { + this->current_expression = stmt; } } @@ -74,22 +74,21 @@ namespace gcc { auto body_type = build_type(expression->body()); - this->current_expression = build1(CONVERT_EXPR, - this->symbol_map->lookup("Word")->payload, TYPE_SIZE_UNIT(body_type)); + this->current_expression = build1(CONVERT_EXPR, this->symbol_map->lookup("Word"), TYPE_SIZE_UNIT(body_type)); } bool generic_visitor::is_integral_type(tree type) { gcc_assert(TYPE_P(type)); - return type == this->symbol_map->lookup("Int")->payload - || type == this->symbol_map->lookup("Word")->payload; + return type == this->symbol_map->lookup("Int") + || type == this->symbol_map->lookup("Word"); } bool generic_visitor::is_numeric_type(tree type) { return is_integral_type(type) - || type == this->symbol_map->lookup("Float")->payload; + || type == this->symbol_map->lookup("Float"); } void generic_visitor::visit(boot::program *program) @@ -130,7 +129,7 @@ namespace gcc get_identifier(argument_name.c_str()), parameter_types[i]); DECL_CONTEXT(argc_declaration_tree) = this->main_fndecl; DECL_ARG_TYPE(argc_declaration_tree) = parameter_types[i]; - this->symbol_map->enter(argument_name, boot::make_info(argc_declaration_tree)); + this->symbol_map->enter(argument_name, argc_declaration_tree); argument_chain.append(argc_declaration_tree); } DECL_ARGUMENTS(this->main_fndecl) = argument_chain.head(); @@ -171,7 +170,7 @@ namespace gcc tree declaration_type = build_function_type_array(return_type, definition->parameters.size(), parameter_types.data()); this->main_fndecl = build_fn_decl(definition->identifier().c_str(), declaration_type); - this->symbol_map->enter(definition->identifier(), boot::make_info(this->main_fndecl)); + this->symbol_map->enter(definition->identifier(), this->main_fndecl); if (definition->body() != nullptr) { @@ -193,7 +192,7 @@ namespace gcc if (definition->body() != nullptr) { - this->symbol_map->enter(parameter->identifier(), boot::make_info(declaration_tree)); + this->symbol_map->enter(parameter->identifier(), declaration_tree); } argument_chain.append(declaration_tree); } @@ -243,14 +242,14 @@ namespace gcc { auto symbol = this->symbol_map->lookup("Int"); - this->current_expression = build_int_cst(symbol->payload, literal->number()); + this->current_expression = build_int_cst(symbol, literal->number()); } void generic_visitor::visit(boot::number_literal *literal) { auto symbol = this->symbol_map->lookup("Word"); - this->current_expression = build_int_cstu(symbol->payload, literal->number()); + this->current_expression = build_int_cstu(symbol, literal->number()); } void generic_visitor::visit(boot::number_literal *literal) @@ -272,14 +271,14 @@ namespace gcc { auto symbol = this->symbol_map->lookup("Bool"); - this->current_expression = build_int_cst_type(symbol->payload, boolean->number()); + this->current_expression = build_int_cst_type(symbol, boolean->number()); } void generic_visitor::visit(boot::number_literal *character) { auto symbol = this->symbol_map->lookup("Char"); - this->current_expression = build_int_cstu(symbol->payload, character->number()); + this->current_expression = build_int_cstu(symbol, character->number()); } void generic_visitor::visit(boot::number_literal *) @@ -303,7 +302,7 @@ namespace gcc tree_code operator_code, tree left, tree right) { return build_binary_operation(is_numeric_type(TREE_TYPE(left)) || is_pointer_type(TREE_TYPE(left)), - expression, operator_code, left, right, this->symbol_map->lookup("Bool")->payload); + expression, operator_code, left, right, this->symbol_map->lookup("Bool")); } tree generic_visitor::build_logic_operation(boot::binary_expression *expression, @@ -311,15 +310,15 @@ namespace gcc { auto symbol = this->symbol_map->lookup("Bool"); - return build_binary_operation(TREE_TYPE(left) == symbol->payload, - expression, operator_code, left, right, symbol->payload); + return build_binary_operation(TREE_TYPE(left) == symbol, + expression, operator_code, left, right, symbol); } tree generic_visitor::build_equality_operation(boot::binary_expression *expression, tree_code operator_code, tree left, tree right) { return build_binary_operation(true, expression, - operator_code, left, right, this->symbol_map->lookup("Bool")->payload); + operator_code, left, right, this->symbol_map->lookup("Bool")); } void generic_visitor::visit(boot::binary_expression *expression) @@ -425,7 +424,7 @@ namespace gcc tree definition_tree = build_decl(definition_location, CONST_DECL, get_identifier(definition->identifier().c_str()), TREE_TYPE(this->current_expression)); - auto result = this->symbol_map->enter(definition->identifier(), boot::make_info(definition_tree)); + auto result = this->symbol_map->enter(definition->identifier(), definition_tree); if (result) { @@ -457,7 +456,7 @@ namespace gcc location_t definition_location = get_location(&definition->position()); tree definition_tree = build_decl(definition_location, TYPE_DECL, get_identifier(definition->identifier().c_str()), tree_type); - auto result = this->symbol_map->enter(definition->identifier(), boot::make_info(tree_type)); + auto result = this->symbol_map->enter(definition->identifier(), tree_type); if (result) { @@ -480,11 +479,11 @@ namespace gcc { if (boot::basic_type_expression *basic_type = type.is_basic()) { - auto symbol = this->symbol_map->lookup(basic_type->base_name()); + tree symbol = this->symbol_map->lookup(basic_type->base_name()); - if (symbol && TYPE_P(symbol->payload)) + if (symbol != NULL_TREE && TYPE_P(symbol)) { - return symbol->payload; + return symbol; } error_at(get_location(&basic_type->position()), "type '%s' not declared", basic_type->base_name().c_str()); @@ -590,7 +589,7 @@ namespace gcc location_t declaration_location = get_location(&declaration->position()); tree declaration_tree = build_decl(declaration_location, VAR_DECL, get_identifier(declaration->identifier().c_str()), declaration_type); - bool result = this->symbol_map->enter(declaration->identifier(), boot::make_info(declaration_tree)); + bool result = this->symbol_map->enter(declaration->identifier(), declaration_tree); if (!result) { @@ -618,7 +617,7 @@ namespace gcc { auto symbol = this->symbol_map->lookup(expression->name()); - if (!symbol) + if (symbol == NULL_TREE) { error_at(get_location(&expression->position()), "variable '%s' not declared in the current scope", @@ -626,7 +625,7 @@ namespace gcc this->current_expression = error_mark_node; return; } - this->current_expression = symbol->payload; + this->current_expression = symbol; } void generic_visitor::visit(boot::array_access_expression *expression) @@ -699,20 +698,23 @@ namespace gcc this->current_expression = error_mark_node; return; } - if (TREE_TYPE(this->current_expression) != TREE_TYPE(lvalue)) + if (TREE_TYPE(this->current_expression) == TREE_TYPE(lvalue) + || (is_pointer_type(TREE_TYPE(lvalue)) && this->current_expression == null_pointer_node)) + { + tree assignment = build2_loc(statement_location, MODIFY_EXPR, + void_type_node, lvalue, this->current_expression); + + append_to_statement_list(assignment, &this->current_statements); + this->current_expression = NULL_TREE; + } + else { error_at(statement_location, "cannot assign value of type %s to variable of type %s", print_type(TREE_TYPE(this->current_expression)), print_type(TREE_TYPE(lvalue))); this->current_expression = error_mark_node; - return; } - auto assignment = build2_loc(statement_location, MODIFY_EXPR, - void_type_node, lvalue, this->current_expression); - - append_to_statement_list(assignment, &this->current_statements); - this->current_expression = NULL_TREE; } void generic_visitor::visit(boot::if_statement *statement) diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index 7bf23cc..fb162f3 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -74,13 +74,13 @@ namespace gcc std::shared_ptr> initial_table = std::make_shared>(); - initial_table->enter("Int", boot::make_info(long_integer_type_node)); - initial_table->enter("Word", boot::make_info(size_type_node)); - initial_table->enter("Bool", boot::make_info(boolean_type_node)); - initial_table->enter("Float", boot::make_info(double_type_node)); - initial_table->enter("Char", boot::make_info(unsigned_char_type_node)); - initial_table->enter("Byte", boot::make_info(make_unsigned_type(8))); - initial_table->enter("String", boot::make_info(elna_string_type_node)); + initial_table->enter("Int", long_integer_type_node); + initial_table->enter("Word", size_type_node); + initial_table->enter("Bool", boolean_type_node); + initial_table->enter("Float", double_type_node); + initial_table->enter("Char", unsigned_char_type_node); + initial_table->enter("Byte", make_unsigned_type(8)); + initial_table->enter("String", elna_string_type_node); return initial_table; } diff --git a/gcc/lang-specs.h b/gcc/lang-specs.h index 2345566..e3e0e74 100644 --- a/gcc/lang-specs.h +++ b/gcc/lang-specs.h @@ -1,6 +1,9 @@ /* gcc/gcc.cc */ {".elna", "@elna", nullptr, 0, 0}, {"@elna", - "elna1 %{!Q:-quiet} \ - %i %{!fsyntax-only:%(invoke_as)}", + "elna1 %i \ + %{!Q:-quiet} \ + %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %w%b.s}}} \ + %{fsyntax-only:-o %j} %{-param*} \ + %{!fsyntax-only:%(invoke_as)}", nullptr, 0, 0}, diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h index 14c8cff..82f3363 100644 --- a/include/elna/boot/symbol.h +++ b/include/elna/boot/symbol.h @@ -12,27 +12,6 @@ namespace elna { namespace boot { - /** - * Generic language entity information. - */ - template - class info - { - public: - T payload; - - info(T payload) - : payload(payload) - { - } - }; - - template - std::shared_ptr> make_info(T payload) - { - return std::make_shared>(info(payload)); - } - /** * Symbol table. */ @@ -40,7 +19,7 @@ namespace boot class symbol_table { public: - using symbol_ptr = std::shared_ptr>; + using symbol_ptr = T; using iterator = typename std::unordered_map::iterator; using const_iterator = typename std::unordered_map::const_iterator; diff --git a/source.elna b/source.elna index 4258e7d..a70149c 100644 --- a/source.elna +++ b/source.elna @@ -40,7 +40,8 @@ type dummy: Int end, CommandLine = record - input: pointer to Char + input: pointer to Char; + tokenize: Bool end, Literal = record value: Int @@ -76,6 +77,7 @@ proc reallocarray(ptr: pointer to Byte, n: Word, size: Word): pointer to Byte; e proc memset(ptr: pointer to Char, c: Int, n: Int): pointer to Char; extern; +proc strcmp(s1: pointer to Char, s2: pointer to Char): Int; extern; proc strncmp(s1: pointer to Char, s2: pointer to Char, n: Word): Int; extern; proc strncpy(dst: pointer to Char, src: pointer to Char, dsize: Word): pointer to Char; extern; proc strcpy(dst: pointer to Char, src: pointer to Char): pointer to Char; extern; @@ -185,7 +187,7 @@ begin input := calloc(source_size + 1, 1); if fread(input, source_size, 1, input_file) <> 1u then - input := cast(nil as pointer to Byte) + input := nil end; fclose(input_file); @@ -548,7 +550,7 @@ var token_length: Word; begin tokens_size^ := 0u; - tokens := cast(nil as pointer to Token); + tokens := nil; input_pointer := skip_spaces(input_pointer); @@ -564,7 +566,7 @@ begin input_pointer := token_end elsif is_digit(input_pointer^) then - token_end := cast(nil as pointer to Char); + token_end := nil; current_token^.value.int_value := strtol(input_pointer, @token_end, 10); if token_end^ = 'u' then @@ -731,7 +733,7 @@ var begin result := cast(calloc(1, sizeof(Program)) as pointer to Program); - result^.constants.elements := cast(nil as pointer to pointer to ConstantDefinition); + result^.constants.elements := nil; result^.constants.count := 0u; if tokens^^.kind = TOKEN_CONST then @@ -760,28 +762,34 @@ var i: Int, result: pointer to CommandLine; begin - if argc < 2 then + i := 1; + result := cast(malloc(sizeof(CommandLine)) as pointer to CommandLine); + result^.tokenize := false; + result^.input := nil; + + while i < argc do + parameter := argv + i * cast(sizeof(pointer to Char) as Int); + + if strcmp(parameter^, "--tokenize") = 0 then + result^.tokenize := true + elsif parameter^^ <> '-' then + result^.input := parameter^ + else + write_s("Fatal error: Unknown command line options:"); + + write_c(' '); + write_s(parameter^); + write_s(".\n"); + + return nil + end; + + i := i + 1 + end; + if result^.input = nil then write_s("Fatal error: no input files.\n"); return nil end; - if argc > 2 then - write_s("Fatal error: Unknown command line options:"); - - i := 2; - while i < argc do - parameter := argv + i * cast(sizeof(pointer to Char) as Int); - - write_c(' '); - write_s(parameter^); - i := i + 1 - end; - write_s(".\n"); - return nil - end; - - parameter := argv + cast(sizeof(pointer to Char) as Int); - result := cast(malloc(sizeof(CommandLine)) as pointer to CommandLine); - result^.input := parameter^; return result end; @@ -805,7 +813,9 @@ begin end; tokens := tokenize(input, @tokens_size); - print_tokens(tokens, tokens_size); + if command_line^.tokenize then + print_tokens(tokens, tokens_size) + end; parse_program(@tokens, @tokens_size); return 0