diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ad72d2..0353a06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,24 +5,24 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS 1) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_CXX_STANDARD 17) -find_package(Boost CONFIG COMPONENTS process program_options REQUIRED) +# find_package(Boost CONFIG COMPONENTS process program_options REQUIRED) find_package(FLEX REQUIRED) find_package(BISON REQUIRED) -include_directories(${Boost_INCLUDE_DIR}) +# include_directories(${Boost_INCLUDE_DIR}) -FLEX_TARGET(lexer source/lexer.ll ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp) -BISON_TARGET(parser source/parser.yy ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp) +FLEX_TARGET(lexer source/lexer.ll ${CMAKE_CURRENT_BINARY_DIR}/lexer.cc) +BISON_TARGET(parser source/parser.yy ${CMAKE_CURRENT_BINARY_DIR}/parser.cc) add_flex_bison_dependency(lexer parser) -add_executable(elna cli/main.cpp - source/ast.cpp include/elna/source/ast.hpp - source/types.cpp include/elna/source/types.hpp - source/driver.cpp include/elna/source/driver.hpp - source/symbol_table.cpp include/elna/source/symbol_table.hpp - source/result.cpp include/elna/source/result.hpp - source/semantic.cpp include/elna/source/semantic.hpp +add_executable(elna cli/main.cc + source/ast.cc include/elna/source/ast.h + source/types.cc include/elna/source/types.h + source/driver.cc include/elna/source/driver.h + source/symbol_table.cc include/elna/source/symbol_table.h + source/result.cc include/elna/source/result.h + source/semantic.cc include/elna/source/semantic.h ${BISON_parser_OUTPUTS} ${FLEX_lexer_OUTPUTS} ) target_include_directories(elna PRIVATE ${CMAKE_CURRENT_BINARY_DIR} include) -target_link_libraries(elna LINK_PUBLIC ${Boost_LIBRARIES}) +# target_link_libraries(elna LINK_PUBLIC ${Boost_LIBRARIES}) diff --git a/cli/main.cpp b/cli/main.cc similarity index 71% rename from cli/main.cpp rename to cli/main.cc index 6da37e7..3620cd3 100644 --- a/cli/main.cpp +++ b/cli/main.cc @@ -1,21 +1,21 @@ -#include -#include "parser.hpp" +#include +#include "elna/source/semantic.h" +#include "parser.hh" #include +constexpr std::size_t pointer_size = 4; + int main() { elna::source::driver driver{ "-" }; std::istringstream inp(R"( - const world = 5, hello = 7; - var x: int, y: boolean; + var x: Int; proc f(); begin - x := 8 end; begin - while false do inc(5) end. )"); @@ -33,6 +33,12 @@ int main() } return result; } + auto symbol_table = elna::source::add_builtin_symbols(); + elna::source::name_analysis_visitor name_analysis_visitor{ symbol_table, "-", pointer_size }; + elna::source::type_analysis_visitor type_analysis_visitor{ symbol_table, "-", pointer_size }; + + name_analysis_visitor.visit(driver.tree.get()); + for (auto& definition : driver.tree->definitions()) { if (auto const_definition = dynamic_cast(definition.get())) diff --git a/gcc/Make-lang.in b/gcc/Make-lang.in new file mode 100644 index 0000000..dbe18f8 --- /dev/null +++ b/gcc/Make-lang.in @@ -0,0 +1,99 @@ +GCCELNA_INSTALL_NAME := $(shell echo gccelna|sed '$(program_transform_name)') +GCCELNA_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo gccelna|sed '$(program_transform_name)') + +elna: elna1$(exeext) + +.PHONY: elna + +# Driver + +GCCELNA_OBJS = \ + $(GCC_OBJS) \ + elna/elna-spec.o \ + $(END) + +gccelna$(exeext): $(GCCELNA_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS) + +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \ + $(GCCELNA_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a \ + $(EXTRA_GCC_LIBS) $(LIBS) + +# The compiler proper + +elna_OBJS = \ + elna/elna1.o \ + elna/generic-visitor.o \ + elna/ast.o \ + elna/driver.o \ + elna/lexer.o \ + elna/parser.o \ + elna/result.o \ + elna/semantic.o \ + elna/symbol_table.o \ + elna/types.o \ + $(END) + +elna1$(exeext): attribs.o $(elna_OBJS) $(BACKEND) $(LIBDEPS) + +$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \ + attribs.o $(elna_OBJS) $(BACKEND) $(LIBS) $(BACKENDLIBS) + +elna.all.cross: + +elna.start.encap: gccelna$(exeext) +elna.rest.encap: + +# No elna-specific selftests. +selftest-elna: + +elna.install-common: installdirs + -rm -f $(DESTDIR)$(bindir)/$(GCCELNA_INSTALL_NAME)$(exeext) + $(INSTALL_PROGRAM) gccelna$(exeext) $(DESTDIR)$(bindir)/$(GCCELNA_INSTALL_NAME)$(exeext) + rm -f $(DESTDIR)$(bindir)/$(GCCELNA_TARGET_INSTALL_NAME)$(exeext); \ + ( cd $(DESTDIR)$(bindir) && \ + $(LN) $(GCCELNA_INSTALL_NAME)$(exeext) $(GCCELNA_TARGET_INSTALL_NAME)$(exeext) ); \ + +# Required goals, they still do nothing +elna.install-man: +elna.install-info: +elna.install-pdf: +elna.install-plugin: +elna.install-html: +elna.info: +elna.dvi: +elna.pdf: +elna.html: +elna.man: +elna.mostlyclean: +elna.clean: +elna.distclean: +elna.maintainer-clean: + +# make uninstall +elna.uninstall: + -rm -f gccelna$(exeext) elna1$(exeext) + -rm -f $(elna_OBJS) + +# Used for handling bootstrap +elna.stage1: stage1-start + -mv elna/*$(objext) stage1/elna +elna.stage2: stage2-start + -mv elna/*$(objext) stage2/elna +elna.stage3: stage3-start + -mv elna/*$(objext) stage3/elna +elna.stage4: stage4-start + -mv elna/*$(objext) stage4/elna +elna.stageprofile: stageprofile-start + -mv elna/*$(objext) stageprofile/elna +elna.stagefeedback: stagefeedback-start + -mv elna/*$(objext) stagefeedback/elna + +ELNA_INCLUDES = -I $(srcdir)/elna -I $(srcdir)/elna/generated + +CFLAGS-elna/elna1.o += $(ELNA_INCLUDES) + +elna/%.o: elna/source/%.cc + $(COMPILE) $(ELNA_INCLUDES) $< + $(POSTCOMPILE) + +elna/%.o: elna/generated/%.cc + $(COMPILE) $(ELNA_INCLUDES) $< + $(POSTCOMPILE) diff --git a/gcc/config-lang.in b/gcc/config-lang.in new file mode 100644 index 0000000..4d69a75 --- /dev/null +++ b/gcc/config-lang.in @@ -0,0 +1,13 @@ +# gcc-src/gcc/config/config-lang.in +language="elna" + +compilers="elna1\$(exeext)" + +target_libs="" + +gtfiles="\$(srcdir)/elna/elna1.cc" + +lang_requires_boot_languages=c++ + +# Do not build by default +build_by_default="no" diff --git a/gcc/elna-spec.cc b/gcc/elna-spec.cc new file mode 100644 index 0000000..d23606c --- /dev/null +++ b/gcc/elna-spec.cc @@ -0,0 +1,16 @@ +void +lang_specific_driver (struct cl_decoded_option ** /* in_decoded_options */, + unsigned int * /* in_decoded_options_count */, + int * /*in_added_libraries */) +{ +} + +/* Called before linking. Returns 0 on success and -1 on failure. */ +int +lang_specific_pre_link (void) +{ + return 0; +} + +/* Number of extra output files that lang_specific_pre_link may generate. */ +int lang_specific_extra_outfiles = 0; diff --git a/gcc/elna1.cc b/gcc/elna1.cc new file mode 100644 index 0000000..5b6c8c4 --- /dev/null +++ b/gcc/elna1.cc @@ -0,0 +1,252 @@ +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "tree.h" +#include "tree-iterator.h" +#include "gimple-expr.h" +#include "diagnostic.h" +#include "opts.h" +#include "fold-const.h" +#include "stor-layout.h" +#include "debug.h" +#include "convert.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "common/common-target.h" + +#include +#include +#include "elna/source/semantic.h" +#include "elna/gcc/generic-visitor.h" +#include "parser.hh" + +/* Language-dependent contents of a type. */ + +struct GTY (()) lang_type +{ + char dummy; +}; + +/* Language-dependent contents of a decl. */ + +struct GTY (()) lang_decl +{ + char dummy; +}; + +/* Language-dependent contents of an identifier. This must include a + tree_identifier. */ + +struct GTY (()) lang_identifier +{ + struct tree_identifier common; +}; + +/* The resulting tree type. */ + +union GTY ((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"), + chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), " + "TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN " + "(&%h.generic)) : NULL"))) lang_tree_node +{ + union tree_node GTY ((tag ("0"), desc ("tree_node_structure (&%h)"))) generic; + struct lang_identifier GTY ((tag ("1"))) identifier; +}; + +/* We don't use language_function. */ + +struct GTY (()) language_function +{ + int dummy; +}; + +/* Creates an expression whose value is that of EXPR, converted to type TYPE. + This function implements all reasonable scalar conversions. */ + +tree +convert (tree type, tree expr) +{ + return expr; +} + +/* Language hooks. */ + +static bool +elna_langhook_init (void) +{ + /* NOTE: Newer versions of GCC use only: + build_common_tree_nodes (false); + See Eugene's comment in the comments section. */ + build_common_tree_nodes (false); + + /* I don't know why this has to be done explicitly. */ + void_list_node = build_tree_list (NULL_TREE, void_type_node); + + build_common_builtin_nodes (); + + return true; +} + +constexpr std::size_t pointer_size = 4; + +static void +elna_parse_file (const char *filename) +{ + std::ifstream file{ filename, std::ios::in }; + + if (!file) + { + fatal_error (UNKNOWN_LOCATION, "cannot open filename %s: %m", filename); + } + + elna::source::driver driver{ filename }; + elna::source::lexer lexer(file); + yy::parser parser(lexer, driver); + + if (auto result = parser()) + { + for (const auto& error : driver.errors()) + { + linemap_add (line_table, LC_ENTER, 0, filename, 1); + + linemap_line_start (line_table, error->line (), 0); + auto gcc_location = linemap_position_for_column (line_table, error->column ()); + linemap_add (line_table, LC_LEAVE, 0, NULL, 0); + + error_at (gcc_location, error->what ().c_str ()); + } + return; + } + + auto symbol_table = elna::source::add_builtin_symbols(); + elna::source::name_analysis_visitor name_analysis_visitor{ symbol_table, filename, pointer_size }; + elna::source::type_analysis_visitor type_analysis_visitor{ symbol_table, filename, pointer_size }; + elna::gcc::generic_visitor generic_visitor; + + name_analysis_visitor.visit(driver.tree.get()); + type_analysis_visitor.visit(driver.tree.get()); + generic_visitor.visit(driver.tree.get()); +} + +static void +elna_langhook_parse_file (void) +{ + for (int i = 0; i < num_in_fnames; i++) + { + elna_parse_file (in_fnames[i]); + } +} + +static tree +elna_langhook_type_for_mode (enum machine_mode mode, int unsignedp) +{ + if (mode == TYPE_MODE (float_type_node)) + return float_type_node; + + if (mode == TYPE_MODE (double_type_node)) + return double_type_node; + + if (mode == TYPE_MODE (intQI_type_node)) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + if (mode == TYPE_MODE (intHI_type_node)) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + if (mode == TYPE_MODE (intSI_type_node)) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + if (mode == TYPE_MODE (intDI_type_node)) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + if (mode == TYPE_MODE (intTI_type_node)) + return unsignedp ? unsigned_intTI_type_node : intTI_type_node; + + if (mode == TYPE_MODE (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + + if (mode == TYPE_MODE (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + + if (mode == TYPE_MODE (long_long_integer_type_node)) + return unsignedp ? long_long_unsigned_type_node + : long_long_integer_type_node; + + if (COMPLEX_MODE_P (mode)) + { + if (mode == TYPE_MODE (complex_float_type_node)) + return complex_float_type_node; + if (mode == TYPE_MODE (complex_double_type_node)) + return complex_double_type_node; + if (mode == TYPE_MODE (complex_long_double_type_node)) + return complex_long_double_type_node; + if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp) + return complex_integer_type_node; + } + + /* gcc_unreachable */ + return NULL; +} + +static tree +elna_langhook_type_for_size (unsigned int bits ATTRIBUTE_UNUSED, + int unsignedp ATTRIBUTE_UNUSED) +{ + gcc_unreachable (); + return NULL; +} + +/* Record a builtin function. We just ignore builtin functions. */ + +static tree +elna_langhook_builtin_function (tree decl) +{ + return decl; +} + +static bool +elna_langhook_global_bindings_p (void) +{ + gcc_unreachable (); + return true; +} + +static tree +elna_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED) +{ + gcc_unreachable (); +} + +static tree +elna_langhook_getdecls (void) +{ + return NULL; +} + +#undef LANG_HOOKS_NAME +#define LANG_HOOKS_NAME "Elna" + +#undef LANG_HOOKS_INIT +#define LANG_HOOKS_INIT elna_langhook_init + +#undef LANG_HOOKS_PARSE_FILE +#define LANG_HOOKS_PARSE_FILE elna_langhook_parse_file + +#undef LANG_HOOKS_TYPE_FOR_MODE +#define LANG_HOOKS_TYPE_FOR_MODE elna_langhook_type_for_mode + +#undef LANG_HOOKS_TYPE_FOR_SIZE +#define LANG_HOOKS_TYPE_FOR_SIZE elna_langhook_type_for_size + +#undef LANG_HOOKS_BUILTIN_FUNCTION +#define LANG_HOOKS_BUILTIN_FUNCTION elna_langhook_builtin_function + +#undef LANG_HOOKS_GLOBAL_BINDINGS_P +#define LANG_HOOKS_GLOBAL_BINDINGS_P elna_langhook_global_bindings_p + +#undef LANG_HOOKS_PUSHDECL +#define LANG_HOOKS_PUSHDECL elna_langhook_pushdecl + +#undef LANG_HOOKS_GETDECLS +#define LANG_HOOKS_GETDECLS elna_langhook_getdecls + +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; + +#include "gt-elna-elna1.h" +#include "gtype-elna.h" diff --git a/gcc/generic-visitor.cc b/gcc/generic-visitor.cc new file mode 100644 index 0000000..af30b86 --- /dev/null +++ b/gcc/generic-visitor.cc @@ -0,0 +1,68 @@ +#include "elna/gcc/generic-visitor.h" + +#include "input.h" +#include "cgraph.h" +#include "gimplify.h" + +namespace elna +{ +namespace gcc +{ + void generic_visitor::visit(source::call_statement *statement) + { + const char *format_integer = "%d\n"; + tree args[] = { + build_string_literal(strlen(format_integer) + 1, format_integer), + build_int_cst_type(integer_type_node, 8) + }; + tree fndecl_type_param[] = { + build_pointer_type (build_qualified_type(char_type_node, TYPE_QUAL_CONST)) /* const char* */ + }; + tree fndecl_type = build_varargs_function_type_array(integer_type_node, 1, fndecl_type_param); + + tree printf_fn_decl = build_fn_decl("printf", fndecl_type); + DECL_EXTERNAL (printf_fn_decl) = 1; + + tree printf_fn = build1(ADDR_EXPR, build_pointer_type(fndecl_type), printf_fn_decl); + + tree stmt = build_call_array(integer_type_node, printf_fn, 2, args); + + append_to_statement_list(stmt, &this->current_statements); + } + + void generic_visitor::visit(source::program *program) + { + tree main_fndecl_type_param[] = { + integer_type_node, + build_pointer_type (build_pointer_type (char_type_node)) + }; + tree main_fndecl_type = build_function_type_array(integer_type_node, 2, main_fndecl_type_param); + tree main_fndecl = build_fn_decl("main", main_fndecl_type); + tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node); + DECL_RESULT(main_fndecl) = resdecl; + tree set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(main_fndecl), + build_int_cst_type(integer_type_node, 0)); + tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result); + + this->current_statements = alloc_stmt_list(); + + empty_visitor::visit(program); + + append_to_statement_list(return_stmt, &this->current_statements); + + tree new_block = build_block(NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE); + tree bind_expr = build3(BIND_EXPR, void_type_node, NULL_TREE, this->current_statements, new_block); + + BLOCK_SUPERCONTEXT(new_block) = main_fndecl; + DECL_INITIAL(main_fndecl) = new_block; + DECL_SAVED_TREE(main_fndecl) = bind_expr; + + DECL_EXTERNAL(main_fndecl) = 0; + DECL_PRESERVE_P(main_fndecl) = 1; + + gimplify_function_tree(main_fndecl); + + cgraph_node::finalize_function(main_fndecl, true); + } +} +} diff --git a/gcc/lang-specs.h b/gcc/lang-specs.h new file mode 100644 index 0000000..624fa37 --- /dev/null +++ b/gcc/lang-specs.h @@ -0,0 +1,3 @@ +/* gcc-src/gcc/config/lang-specs.in */ +{".elna", "@elna", 0, 1, 0}, +{"@elna", "elna1 %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}", 0, 1, 0}, diff --git a/gcc/tiny1.cc b/gcc/tiny1.cc new file mode 100644 index 0000000..faa28fa --- /dev/null +++ b/gcc/tiny1.cc @@ -0,0 +1,250 @@ +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "tree.h" +#include "tree-iterator.h" +#include "gimple-expr.h" +#include "diagnostic.h" +#include "opts.h" +#include "fold-const.h" +#include "cgraph.h" +#include "gimplify.h" +#include "stor-layout.h" +#include "debug.h" +#include "convert.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "common/common-target.h" + +/* Language-dependent contents of a type. */ + +struct GTY (()) lang_type +{ + char dummy; +}; + +/* Language-dependent contents of a decl. */ + +struct GTY (()) lang_decl +{ + char dummy; +}; + +/* Language-dependent contents of an identifier. This must include a + tree_identifier. */ + +struct GTY (()) lang_identifier +{ + struct tree_identifier common; +}; + +/* The resulting tree type. */ + +union GTY ((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"), + chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), " + "TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN " + "(&%h.generic)) : NULL"))) lang_tree_node +{ + union tree_node GTY ((tag ("0"), desc ("tree_node_structure (&%h)"))) generic; + struct lang_identifier GTY ((tag ("1"))) identifier; +}; + +/* We don't use language_function. */ + +struct GTY (()) language_function +{ + int dummy; +}; + +/* Creates an expression whose value is that of EXPR, converted to type TYPE. + This function implements all reasonable scalar conversions. */ + +tree +convert (tree type, tree expr) +{ + return expr; +} + +/* Language hooks. */ + +static bool +elna_langhook_init (void) +{ + /* NOTE: Newer versions of GCC use only: + build_common_tree_nodes (false); + See Eugene's comment in the comments section. */ + build_common_tree_nodes (false); + + /* I don't know why this has to be done explicitly. */ + void_list_node = build_tree_list (NULL_TREE, void_type_node); + + build_common_builtin_nodes (); + + return true; +} + +static void +elna_parse_file (const char *filename) +{ + FILE *file = fopen (filename, "r"); + if (file == NULL) + { + fatal_error (UNKNOWN_LOCATION, "cannot open filename %s: %m", filename); + } + + tree main_fndecl_type_param[] = { + integer_type_node, + build_pointer_type (build_pointer_type (char_type_node)) + }; + tree main_fndecl_type = build_function_type_array (integer_type_node, 2, main_fndecl_type_param); + tree main_fndecl = build_fn_decl ("main", main_fndecl_type); + tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node); + DECL_RESULT (main_fndecl) = resdecl; + tree set_result + = build2 (INIT_EXPR, void_type_node, DECL_RESULT (main_fndecl), + build_int_cst_type (integer_type_node, 3)); + tree return_stmt = build1 (RETURN_EXPR, void_type_node, set_result); + + tree list = alloc_stmt_list (); + + append_to_statement_list (return_stmt, &list); + + tree new_block = build_block (NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE); + tree bind_expr = build3 (BIND_EXPR, void_type_node, NULL_TREE, list, new_block); + + BLOCK_SUPERCONTEXT (new_block) = main_fndecl; + DECL_INITIAL (main_fndecl) = new_block; + DECL_SAVED_TREE (main_fndecl) = bind_expr; + + DECL_EXTERNAL (main_fndecl) = 0; + DECL_PRESERVE_P (main_fndecl) = 1; + + gimplify_function_tree (main_fndecl); + + cgraph_node::finalize_function (main_fndecl, true); + + fclose(file); +} + +static void +elna_langhook_parse_file (void) +{ + for (int i = 0; i < num_in_fnames; i++) + { + elna_parse_file (in_fnames[i]); + } +} + +static tree +elna_langhook_type_for_mode (enum machine_mode mode, int unsignedp) +{ + if (mode == TYPE_MODE (float_type_node)) + return float_type_node; + + if (mode == TYPE_MODE (double_type_node)) + return double_type_node; + + if (mode == TYPE_MODE (intQI_type_node)) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + if (mode == TYPE_MODE (intHI_type_node)) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + if (mode == TYPE_MODE (intSI_type_node)) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + if (mode == TYPE_MODE (intDI_type_node)) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + if (mode == TYPE_MODE (intTI_type_node)) + return unsignedp ? unsigned_intTI_type_node : intTI_type_node; + + if (mode == TYPE_MODE (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + + if (mode == TYPE_MODE (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + + if (mode == TYPE_MODE (long_long_integer_type_node)) + return unsignedp ? long_long_unsigned_type_node + : long_long_integer_type_node; + + if (COMPLEX_MODE_P (mode)) + { + if (mode == TYPE_MODE (complex_float_type_node)) + return complex_float_type_node; + if (mode == TYPE_MODE (complex_double_type_node)) + return complex_double_type_node; + if (mode == TYPE_MODE (complex_long_double_type_node)) + return complex_long_double_type_node; + if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp) + return complex_integer_type_node; + } + + /* gcc_unreachable */ + return NULL; +} + +static tree +elna_langhook_type_for_size (unsigned int bits ATTRIBUTE_UNUSED, + int unsignedp ATTRIBUTE_UNUSED) +{ + gcc_unreachable (); + return NULL; +} + +/* Record a builtin function. We just ignore builtin functions. */ + +static tree +elna_langhook_builtin_function (tree decl) +{ + return decl; +} + +static bool +elna_langhook_global_bindings_p (void) +{ + gcc_unreachable (); + return true; +} + +static tree +elna_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED) +{ + gcc_unreachable (); +} + +static tree +elna_langhook_getdecls (void) +{ + return NULL; +} + +#undef LANG_HOOKS_NAME +#define LANG_HOOKS_NAME "Tiny" + +#undef LANG_HOOKS_INIT +#define LANG_HOOKS_INIT elna_langhook_init + +#undef LANG_HOOKS_PARSE_FILE +#define LANG_HOOKS_PARSE_FILE elna_langhook_parse_file + +#undef LANG_HOOKS_TYPE_FOR_MODE +#define LANG_HOOKS_TYPE_FOR_MODE elna_langhook_type_for_mode + +#undef LANG_HOOKS_TYPE_FOR_SIZE +#define LANG_HOOKS_TYPE_FOR_SIZE elna_langhook_type_for_size + +#undef LANG_HOOKS_BUILTIN_FUNCTION +#define LANG_HOOKS_BUILTIN_FUNCTION elna_langhook_builtin_function + +#undef LANG_HOOKS_GLOBAL_BINDINGS_P +#define LANG_HOOKS_GLOBAL_BINDINGS_P elna_langhook_global_bindings_p + +#undef LANG_HOOKS_PUSHDECL +#define LANG_HOOKS_PUSHDECL elna_langhook_pushdecl + +#undef LANG_HOOKS_GETDECLS +#define LANG_HOOKS_GETDECLS elna_langhook_getdecls + +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; + +#include "gt-tiny-tiny1.h" +#include "gtype-tiny.h" diff --git a/gcc/tinyspec.cc b/gcc/tinyspec.cc new file mode 100644 index 0000000..d23606c --- /dev/null +++ b/gcc/tinyspec.cc @@ -0,0 +1,16 @@ +void +lang_specific_driver (struct cl_decoded_option ** /* in_decoded_options */, + unsigned int * /* in_decoded_options_count */, + int * /*in_added_libraries */) +{ +} + +/* Called before linking. Returns 0 on success and -1 on failure. */ +int +lang_specific_pre_link (void) +{ + return 0; +} + +/* Number of extra output files that lang_specific_pre_link may generate. */ +int lang_specific_extra_outfiles = 0; diff --git a/include/elna/gcc/generic-visitor.h b/include/elna/gcc/generic-visitor.h new file mode 100644 index 0000000..4a3967c --- /dev/null +++ b/include/elna/gcc/generic-visitor.h @@ -0,0 +1,24 @@ +#pragma once + +#include "elna/source/ast.h" + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "tree-iterator.h" + +namespace elna +{ +namespace gcc +{ + class generic_visitor final : public source::empty_visitor + { + tree current_statements{ NULL_TREE }; + + public: + void visit(source::program *program) override; + void visit(source::call_statement *statement) override; + }; +} +} diff --git a/include/elna/source/ast.hpp b/include/elna/source/ast.h similarity index 99% rename from include/elna/source/ast.hpp rename to include/elna/source/ast.h index c58effb..fd713fd 100644 --- a/include/elna/source/ast.hpp +++ b/include/elna/source/ast.h @@ -1,10 +1,12 @@ #pragma once #include -#include "elna/source/result.hpp" -#include "elna/source/types.hpp" +#include "elna/source/result.h" +#include "elna/source/types.h" -namespace elna::source +namespace elna +{ +namespace source { enum class binary_operator { @@ -481,3 +483,4 @@ namespace elna::source unary_operator operation() const noexcept; }; } +} diff --git a/include/elna/source/driver.hpp b/include/elna/source/driver.h similarity index 92% rename from include/elna/source/driver.hpp rename to include/elna/source/driver.h index e91938f..6596815 100644 --- a/include/elna/source/driver.hpp +++ b/include/elna/source/driver.h @@ -1,10 +1,12 @@ #pragma once #include -#include "elna/source/ast.hpp" +#include "elna/source/ast.h" #include "location.hh" -namespace elna::source +namespace elna +{ +namespace source { position make_position(const yy::location& location); @@ -33,3 +35,4 @@ namespace elna::source const std::list>& errors() const noexcept; }; } +} diff --git a/include/elna/source/result.hpp b/include/elna/source/result.h similarity index 97% rename from include/elna/source/result.hpp rename to include/elna/source/result.h index 2dc9a69..d28dad8 100644 --- a/include/elna/source/result.hpp +++ b/include/elna/source/result.h @@ -2,9 +2,11 @@ #include #include -#include "elna/source/types.hpp" +#include "elna/source/types.h" -namespace elna::source +namespace elna +{ +namespace source { /** * Position in the source text. @@ -100,3 +102,4 @@ namespace elna::source operation kind; }; } +} diff --git a/include/elna/source/semantic.hpp b/include/elna/source/semantic.h similarity index 96% rename from include/elna/source/semantic.hpp rename to include/elna/source/semantic.h index 752c596..af05839 100644 --- a/include/elna/source/semantic.hpp +++ b/include/elna/source/semantic.h @@ -1,10 +1,12 @@ #pragma once #include -#include "elna/source/ast.hpp" -#include "elna/source/symbol_table.hpp" +#include "elna/source/ast.h" +#include "elna/source/symbol_table.h" -namespace elna::source +namespace elna +{ +namespace source { class name_analysis_visitor final : public empty_visitor { @@ -92,3 +94,4 @@ namespace elna::source void visit(assign_statement *statement) override; }; } +} diff --git a/include/elna/source/symbol_table.hpp b/include/elna/source/symbol_table.h similarity index 72% rename from include/elna/source/symbol_table.hpp rename to include/elna/source/symbol_table.h index f0eb9fa..b9b69ef 100644 --- a/include/elna/source/symbol_table.hpp +++ b/include/elna/source/symbol_table.h @@ -5,9 +5,18 @@ #include #include -namespace elna::source +namespace elna +{ +namespace source { class symbol_table; + class type_info; + class typed_info; + class constant_info; + class variable_info; + class parameter_info; + class intrinsic_info; + class procedure_info; /** * Generic language entity information. @@ -17,6 +26,14 @@ namespace elna::source public: virtual ~info() = 0; + virtual type_info *is_type_info() noexcept; + virtual typed_info *is_typed_info() noexcept; + virtual constant_info *is_constant_info() noexcept; + virtual variable_info *is_variable_info() noexcept; + virtual parameter_info *is_parameter_info() noexcept; + virtual intrinsic_info *is_intrinsic_info() noexcept; + virtual procedure_info *is_procedure_info() noexcept; + protected: info(); }; @@ -26,11 +43,13 @@ namespace elna::source */ class type_info final : public info { - std::shared_ptr m_type; + std::shared_ptr m_type; public: - explicit type_info(const class type& type); + explicit type_info(std::shared_ptr type); ~type_info() override; + + virtual type_info *is_type_info() noexcept override; std::shared_ptr type() const noexcept; }; @@ -47,6 +66,7 @@ namespace elna::source public: ~typed_info() override; + virtual typed_info *is_typed_info() noexcept override; std::shared_ptr type() const noexcept; }; @@ -60,6 +80,7 @@ namespace elna::source public: constant_info(std::shared_ptr type, const std::int32_t value); + virtual constant_info *is_constant_info() noexcept override; std::int32_t value() const noexcept; }; @@ -72,6 +93,8 @@ namespace elna::source std::ptrdiff_t offset{ 0 }; explicit variable_info(std::shared_ptr type); + + virtual variable_info *is_variable_info() noexcept override; }; /** @@ -83,6 +106,8 @@ namespace elna::source std::ptrdiff_t offset{ 0 }; explicit parameter_info(std::shared_ptr type); + + virtual parameter_info *is_parameter_info() noexcept override; }; /** @@ -98,6 +123,7 @@ namespace elna::source std::shared_ptr type() const noexcept; std::size_t parameter_stack_size() const noexcept; + virtual intrinsic_info *is_intrinsic_info() noexcept override; }; /** @@ -116,6 +142,7 @@ namespace elna::source std::shared_ptr scope(); std::size_t stack_size() const noexcept; + virtual procedure_info *is_procedure_info() noexcept override; }; /** @@ -158,4 +185,11 @@ namespace elna::source */ std::shared_ptr scope(); }; + + /** + * Creates a symbol table with predefined symbols. + * + * \return A symbol table with predefined symbols. + */ + std::shared_ptr add_builtin_symbols();} } diff --git a/include/elna/source/types.hpp b/include/elna/source/types.h similarity index 69% rename from include/elna/source/types.hpp rename to include/elna/source/types.h index 917ddda..478957d 100644 --- a/include/elna/source/types.hpp +++ b/include/elna/source/types.h @@ -4,12 +4,18 @@ #include #include -namespace elna::source +namespace elna { +namespace source +{ + class primitive_type; + class pointer_type; + class procedure_type; + /** * Type representation. */ - class type + class type { const std::size_t byte_size; @@ -27,6 +33,13 @@ namespace elna::source */ virtual std::size_t size() const noexcept; + /** + * \return Unique type representation. + */ + virtual std::string type_name() const = 0; + + virtual const pointer_type *is_pointer_type() const; + friend bool operator==(const type& lhs, const type& rhs) noexcept; friend bool operator!=(const type& lhs, const type& rhs) noexcept; }; @@ -34,11 +47,12 @@ namespace elna::source /** * Built-in type representation. */ - struct primitive_type : public type + class primitive_type final : public type { /// Type name. - const std::string type_name; + const std::string m_type_name; + public: /** * Constructor. * @@ -47,14 +61,13 @@ namespace elna::source */ primitive_type(const std::string& type_name, const std::size_t byte_size); - bool operator==(const primitive_type& that) const noexcept; - bool operator!=(const primitive_type& that) const noexcept; + virtual std::string type_name() const override; }; /** * Typed pointer. */ - struct pointer_type : public type + struct pointer_type final : public type { /// Pointer target type. std::shared_ptr base_type; @@ -67,14 +80,15 @@ namespace elna::source */ pointer_type(std::shared_ptr base_type, const std::size_t byte_size); - bool operator==(const pointer_type& that) const noexcept; - bool operator!=(const pointer_type& that) const noexcept; + virtual std::string type_name() const override; + + virtual const pointer_type *is_pointer_type() const override; }; /** * Type of a procedure. */ - struct procedure_type : public type + struct procedure_type final : public type { /// Argument types. std::vector> arguments; @@ -87,13 +101,13 @@ namespace elna::source */ procedure_type(std::vector> arguments, const std::size_t byte_size); - bool operator==(const procedure_type& that) const noexcept; - bool operator!=(const procedure_type& that) const noexcept; + virtual std::string type_name() const override; }; bool operator==(const type& lhs, const type& rhs) noexcept; bool operator!=(const type& lhs, const type& rhs) noexcept; - inline const primitive_type boolean_type{ "Boolean", 1 }; - inline const primitive_type int_type{ "Int", 4 }; + extern const primitive_type boolean_type; + extern const primitive_type int_type; +} } diff --git a/source/ast.cpp b/source/ast.cc similarity index 98% rename from source/ast.cpp rename to source/ast.cc index c6871df..bcefe5c 100644 --- a/source/ast.cpp +++ b/source/ast.cc @@ -1,7 +1,8 @@ -#include "elna/source/ast.hpp" -#include +#include "elna/source/ast.h" -namespace elna::source +namespace elna +{ +namespace source { void empty_visitor::visit(declaration *declaration) { @@ -69,7 +70,7 @@ namespace elna::source void empty_visitor::visit(program *program) { - visit(dynamic_cast(program)); + visit(reinterpret_cast(program)); } void empty_visitor::visit(binary_expression *expression) @@ -368,7 +369,7 @@ namespace elna::source this->m_operator = binary_operator::greater_equal; break; default: - throw std::logic_error("Invalid binary operator"); + __builtin_unreachable(); } } @@ -405,7 +406,7 @@ namespace elna::source this->m_operator = unary_operator::dereference; break; default: - throw std::logic_error("Invalid unary operator"); + __builtin_unreachable(); } } @@ -522,3 +523,4 @@ namespace elna::source return *m_body; } } +} diff --git a/source/driver.cpp b/source/driver.cc similarity index 93% rename from source/driver.cpp rename to source/driver.cc index a83ea8b..46d656f 100644 --- a/source/driver.cpp +++ b/source/driver.cc @@ -1,6 +1,8 @@ -#include "elna/source/driver.hpp" +#include "elna/source/driver.h" -namespace elna::source +namespace elna +{ +namespace source { position make_position(const yy::location& location) { @@ -36,3 +38,4 @@ namespace elna::source return m_errors; } } +} diff --git a/source/lexer.ll b/source/lexer.ll index cb69e5e..16541bd 100644 --- a/source/lexer.ll +++ b/source/lexer.ll @@ -3,10 +3,10 @@ #define YY_USER_ACTION this->location.columns(yyleng); #include -#include "parser.hpp" +#include "parser.hh" #undef YY_DECL -#define YY_DECL yy::parser::symbol_type elna::source::lexer::lex() +#define YY_DECL yy::parser::symbol_type elna::source::lexer::lex(elna::source::driver& driver) #define yyterminate() return yy::parser::make_YYEOF(this->location) %} @@ -126,6 +126,6 @@ false { std::stringstream ss; ss << "Illegal character 0x" << std::hex << static_cast(yytext[0]); - throw yy::parser::syntax_error(this->location, ss.str()); + driver.error(this->location, ss.str()); } %% diff --git a/source/parser.yy b/source/parser.yy index c892237..d9d7364 100644 --- a/source/parser.yy +++ b/source/parser.yy @@ -4,7 +4,7 @@ %code requires { #include #include - #include "elna/source/driver.hpp" + #include "elna/source/driver.h" #if !defined(yyFlexLexerOnce) #include @@ -30,7 +30,7 @@ { } - yy::parser::symbol_type lex(); + yy::parser::symbol_type lex(elna::source::driver& driver); }; } @@ -39,10 +39,9 @@ %define api.token.raw %define api.token.constructor %define api.value.type variant -%define parse.assert %parse-param {elna::source::lexer& lexer} -%parse-param {elna::source::driver& driver} +%param {elna::source::driver& driver} %locations %header @@ -58,7 +57,6 @@ %token IF THEN WHILE DO %token CONST VAR PROCEDURE %token BEGIN_BLOCK END_BLOCK -%token TRUE FALSE %token LEFT_PAREN RIGHT_PAREN SEMICOLON DOT COMMA %token GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS %token PLUS MINUS MULTIPLICATION DIVISION diff --git a/source/result.cpp b/source/result.cc similarity index 86% rename from source/result.cpp rename to source/result.cc index f79e85f..1f61acb 100644 --- a/source/result.cpp +++ b/source/result.cc @@ -1,6 +1,8 @@ -#include "elna/source/result.hpp" +#include "elna/source/result.h" -namespace elna::source +namespace elna +{ +namespace source { error::error(const std::filesystem::path& path, const position position) : m_position(position), m_path(path) @@ -33,8 +35,8 @@ namespace elna::source return "Name '" + name + "' was already defined"; } - type_mismatch::type_mismatch(std::shared_ptr got, operation kind, const std::filesystem::path& path, - const struct position position) + type_mismatch::type_mismatch(std::shared_ptr got, operation kind, + const std::filesystem::path& path, const struct position position) : error(path, position), kind(kind), got(got) { } @@ -44,3 +46,4 @@ namespace elna::source return "Type cannot be used here."; } } +} diff --git a/source/semantic.cpp b/source/semantic.cc similarity index 79% rename from source/semantic.cpp rename to source/semantic.cc index 789fd48..87de8e0 100644 --- a/source/semantic.cpp +++ b/source/semantic.cc @@ -1,8 +1,10 @@ -#include "elna/source/semantic.hpp" -#include "elna/source/result.hpp" +#include "elna/source/semantic.h" +#include "elna/source/result.h" #include -namespace elna::source +namespace elna +{ +namespace source { name_analysis_visitor::name_analysis_visitor(std::shared_ptr table, const std::filesystem::path& filename, const std::size_t target_pointer_size) @@ -12,15 +14,14 @@ namespace elna::source void name_analysis_visitor::visit(constant_definition *definition) { - auto constant_type = std::make_shared(int_type); + auto constant_type = std::make_shared(int_type); this->table->enter(definition->identifier(), std::make_shared(constant_type, definition->body().number())); } std::shared_ptr name_analysis_visitor::convert_declaration_type(const type_expression& ast_type) const { - auto variable_type = std::dynamic_pointer_cast(table->lookup(ast_type.base())) - ->type(); + auto variable_type = table->lookup(ast_type.base())->is_type_info()->type(); std::shared_ptr declaration_type; if (ast_type.is_pointer()) @@ -33,11 +34,11 @@ namespace elna::source } } - void name_analysis_visitor::visit(declaration *declaration) + void name_analysis_visitor::visit(declaration *declarationx) { - std::shared_ptr declaration_type = convert_declaration_type(declaration->type()); + std::shared_ptr declaration_type = convert_declaration_type(declarationx->type()); - this->table->enter(declaration->identifier(), + this->table->enter(declarationx->identifier(), std::make_shared(declaration_type)); } @@ -87,12 +88,12 @@ namespace elna::source { auto declaration_info = this->table->lookup(declaration->identifier()); - if (auto variable = std::dynamic_pointer_cast(declaration_info)) + if (auto variable = declaration_info->is_variable_info()) { this->local_offset -= sizeof(std::int32_t); variable->offset = this->local_offset; } - else if (auto parameter = std::dynamic_pointer_cast(declaration_info)) + else if (auto parameter = declaration_info->is_parameter_info()) { parameter->offset = this->argument_offset; this->argument_offset += sizeof(std::int32_t); @@ -105,7 +106,7 @@ namespace elna::source this->argument_offset = 0; empty_visitor::visit(program); - std::dynamic_pointer_cast(table->lookup("_start"))->local_stack_size = + table->lookup("_start")->is_procedure_info()->local_stack_size = std::abs(this->local_offset); } @@ -113,7 +114,7 @@ namespace elna::source { this->local_offset = 0; this->argument_offset = 0; - auto info = std::dynamic_pointer_cast(this->table->lookup(procedure->identifier())); + auto info = this->table->lookup(procedure->identifier())->is_procedure_info(); this->table = info->scope(); empty_visitor::visit(procedure); @@ -125,7 +126,7 @@ namespace elna::source void allocator_visitor::visit(call_statement *statement) { - auto call_info = std::dynamic_pointer_cast(this->table->lookup(statement->name())); + auto call_info = this->table->lookup(statement->name())->is_intrinsic_info(); this->argument_offset = std::max(static_cast(this->argument_offset), call_info->parameter_stack_size()); @@ -141,17 +142,14 @@ namespace elna::source { for (auto& definition : program->definitions()) { - if (dynamic_cast(definition.get()) != nullptr) - { - definition->accept(this); - } + definition->accept(this); } program->body().accept(this); } void type_analysis_visitor::visit(procedure_definition *procedure) { - auto info = std::dynamic_pointer_cast(this->table->lookup(procedure->identifier())); + auto info = this->table->lookup(procedure->identifier())->is_procedure_info(); this->table = info->scope(); procedure->body().accept(this); @@ -161,17 +159,17 @@ namespace elna::source void type_analysis_visitor::visit(integer_literal *literal) { - literal->data_type = std::dynamic_pointer_cast(table->lookup("Int"))->type(); + literal->data_type = table->lookup("Int")->is_type_info()->type(); } void type_analysis_visitor::visit(boolean_literal *literal) { - literal->data_type = std::dynamic_pointer_cast(table->lookup("Boolean"))->type(); + literal->data_type = table->lookup("Boolean")->is_type_info()->type(); } void type_analysis_visitor::visit(variable_expression *expression) { - expression->data_type = std::dynamic_pointer_cast(table->lookup(expression->name()))->type(); + expression->data_type = table->lookup(expression->name())->is_typed_info()->type(); } void type_analysis_visitor::visit(unary_expression *expression) @@ -187,9 +185,9 @@ namespace elna::source case unary_operator::dereference: auto operand_type = expression->operand().data_type; - if (auto referenced_type = std::dynamic_pointer_cast(operand_type)) + if (operand_type->is_pointer_type() != nullptr) { - expression->data_type = referenced_type; + expression->data_type = operand_type; } else if (operand_type != nullptr) { @@ -217,18 +215,16 @@ namespace elna::source case binary_operator::greater_equal: if (expression->lhs().data_type != nullptr && expression->rhs().data_type != nullptr) { - auto lhs_type = std::dynamic_pointer_cast(expression->lhs().data_type); - auto rhs_type = std::dynamic_pointer_cast(expression->rhs().data_type); - std::unique_ptr new_error; - if (lhs_type == nullptr || *lhs_type != int_type) + + if (*expression->lhs().data_type != int_type) { - new_error = std::make_unique(lhs_type, + new_error = std::make_unique(expression->lhs().data_type, type_mismatch::operation::arithmetic, this->filename, expression->lhs().position()); } - if (rhs_type == nullptr || *rhs_type != int_type) + if (*expression->rhs().data_type != int_type) { - new_error = std::make_unique(rhs_type, + new_error = std::make_unique(expression->rhs().data_type, type_mismatch::operation::arithmetic, this->filename, expression->rhs().position()); } if (new_error != nullptr) @@ -253,7 +249,7 @@ namespace elna::source void type_analysis_visitor::visit(call_statement *statement) { - auto call_info = std::dynamic_pointer_cast(this->table->lookup(statement->name())); + auto call_info = this->table->lookup(statement->name())->is_intrinsic_info(); std::size_t i{ 0 }; for (const auto& argument : statement->arguments()) @@ -280,7 +276,7 @@ namespace elna::source void type_analysis_visitor::visit(while_statement *statement) { statement->prerequisite().accept(this); - auto condition_type = std::dynamic_pointer_cast(statement->prerequisite().data_type); + auto condition_type = statement->prerequisite().data_type; if (condition_type != nullptr && *condition_type != boolean_type) { @@ -294,7 +290,7 @@ namespace elna::source void type_analysis_visitor::visit(if_statement *statement) { statement->prerequisite().accept(this); - auto condition_type = std::dynamic_pointer_cast(statement->prerequisite().data_type); + auto condition_type = statement->prerequisite().data_type; if (condition_type != nullptr && *condition_type != boolean_type) { @@ -308,7 +304,7 @@ namespace elna::source void type_analysis_visitor::visit(assign_statement *statement) { statement->rvalue().accept(this); - auto lvalue_info = std::dynamic_pointer_cast(this->table->lookup(statement->lvalue())); + auto lvalue_info = this->table->lookup(statement->lvalue())->is_typed_info(); if (statement->rvalue().data_type != nullptr && lvalue_info->type() == statement->rvalue().data_type) { @@ -323,3 +319,4 @@ namespace elna::source return m_errors; } } +} diff --git a/source/symbol_table.cc b/source/symbol_table.cc new file mode 100644 index 0000000..9144988 --- /dev/null +++ b/source/symbol_table.cc @@ -0,0 +1,230 @@ +#include "elna/source/types.h" +#include "elna/source/symbol_table.h" + +namespace elna +{ +namespace source +{ + symbol_table::symbol_table(std::shared_ptr scope) + : outer_scope(scope) + { + } + + std::shared_ptr symbol_table::lookup(const std::string& name) + { + auto entry = entries.find(name); + + if (entry != entries.cend()) + { + return entry->second; + } + if (this->outer_scope != nullptr) + { + return this->outer_scope->lookup(name); + } + return nullptr; + } + + void symbol_table::enter(const std::string& name, std::shared_ptr entry) + { + entries.insert({ name, entry }); + } + + std::shared_ptr symbol_table::scope() + { + return this->outer_scope; + } + + info::~info() + { + } + + type_info *info::is_type_info() noexcept + { + return nullptr; + } + + typed_info *info::is_typed_info() noexcept + { + return nullptr; + } + + constant_info *info::is_constant_info() noexcept + { + return nullptr; + } + + variable_info *info::is_variable_info() noexcept + { + return nullptr; + } + + parameter_info *info::is_parameter_info() noexcept + { + return nullptr; + } + + intrinsic_info *info::is_intrinsic_info() noexcept + { + return nullptr; + } + + procedure_info *info::is_procedure_info() noexcept + { + return nullptr; + } + + info::info() + { + } + + type_info::type_info(std::shared_ptr type) + : info(), m_type(type) + { + } + + type_info::~type_info() + { + } + + std::shared_ptr type_info::type() const noexcept + { + return m_type; + } + + type_info *type_info::is_type_info() noexcept + { + return this; + } + + typed_info::typed_info(std::shared_ptr type) + : m_type(type) + { + } + + typed_info::~typed_info() + { + } + + typed_info *typed_info::is_typed_info() noexcept + { + return this; + } + + std::shared_ptr typed_info::type() const noexcept + { + return m_type; + } + + constant_info::constant_info(const std::shared_ptr type, const std::int32_t value) + : typed_info(type), m_value(value) + { + } + + constant_info *constant_info::is_constant_info() noexcept + { + return this; + } + + std::int32_t constant_info::value() const noexcept + { + return m_value; + } + + variable_info::variable_info(std::shared_ptr type) + : typed_info(type) + { + } + + variable_info *variable_info::is_variable_info() noexcept + { + return this; + } + + parameter_info::parameter_info(std::shared_ptr type) + : typed_info(type) + { + } + + parameter_info *parameter_info::is_parameter_info() noexcept + { + return this; + } + + intrinsic_info::intrinsic_info(const class procedure_type& type) + : m_type(std::make_shared(type)) + { + } + + intrinsic_info::~intrinsic_info() + { + } + + std::shared_ptr intrinsic_info::type() const noexcept + { + return m_type; + } + + std::size_t intrinsic_info::parameter_stack_size() const noexcept + { + return type()->arguments.size() * sizeof(std::int32_t); + } + + intrinsic_info *intrinsic_info::is_intrinsic_info() noexcept + { + return this; + } + + procedure_info::procedure_info(const class procedure_type& type, std::shared_ptr outer_scope) + : intrinsic_info(type), local_table(std::make_shared(outer_scope)) + { + } + + procedure_info::~procedure_info() + { + } + + std::shared_ptr procedure_info::scope() + { + return local_table; + } + + std::size_t procedure_info::stack_size() const noexcept + { + return local_stack_size + argument_stack_size; + } + + procedure_info *procedure_info::is_procedure_info() noexcept + { + return this; + } + + constexpr std::size_t pointer_size = 4; + + std::shared_ptr add_builtin_symbols() + { + source::symbol_table result; + std::vector> intrinsic_arguments; + + auto prim = boolean_type; + auto boolean_info = std::make_shared(std::make_shared(boolean_type)); + auto int_info = std::make_shared(std::make_shared(int_type)); + result.enter("Boolean", boolean_info); + result.enter("Int", int_info); + + intrinsic_arguments.push_back(int_info->type()); + auto writei = std::make_shared( + source::procedure_type{ intrinsic_arguments, pointer_size }); + result.enter("writei", writei); + intrinsic_arguments.clear(); + + intrinsic_arguments.push_back(boolean_info->type()); + auto writeb = std::make_shared( + source::procedure_type{ intrinsic_arguments, pointer_size }); + result.enter("writeb", writeb); + intrinsic_arguments.clear(); + + return std::make_shared(std::move(result)); + } +} +} diff --git a/source/symbol_table.cpp b/source/symbol_table.cpp deleted file mode 100644 index 8801fa7..0000000 --- a/source/symbol_table.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include "elna/source/types.hpp" -#include "elna/source/symbol_table.hpp" - -namespace elna::source -{ - symbol_table::symbol_table(std::shared_ptr scope) - : outer_scope(scope) - { - } - - std::shared_ptr symbol_table::lookup(const std::string& name) - { - auto entry = entries.find(name); - - if (entry != entries.cend()) - { - return entry->second; - } - if (this->outer_scope != nullptr) - { - return this->outer_scope->lookup(name); - } - return nullptr; - } - - void symbol_table::enter(const std::string& name, std::shared_ptr entry) - { - entries.insert_or_assign(name, entry); - } - - std::shared_ptr symbol_table::scope() - { - return this->outer_scope; - } - - info::~info() - { - } - - info::info() - { - } - - type_info::type_info(const class type& type) - : info(), m_type(std::make_shared(type)) - { - } - - type_info::~type_info() - { - } - - std::shared_ptr type_info::type() const noexcept - { - return m_type; - } - - typed_info::typed_info(std::shared_ptr type) - : m_type(type) - { - } - - typed_info::~typed_info() - { - } - - std::shared_ptr typed_info::type() const noexcept - { - return m_type; - } - - constant_info::constant_info(const std::shared_ptr type, const std::int32_t value) - : typed_info(type), m_value(value) - { - } - - std::int32_t constant_info::value() const noexcept - { - return m_value; - } - - variable_info::variable_info(std::shared_ptr type) - : typed_info(type) - { - } - - parameter_info::parameter_info(std::shared_ptr type) - : typed_info(type) - { - } - - intrinsic_info::intrinsic_info(const class procedure_type& type) - : m_type(std::make_shared(type)) - { - } - - intrinsic_info::~intrinsic_info() - { - } - - std::shared_ptr intrinsic_info::type() const noexcept - { - return m_type; - } - - std::size_t intrinsic_info::parameter_stack_size() const noexcept - { - return type()->arguments.size() * sizeof(std::int32_t); - } - - procedure_info::procedure_info(const class procedure_type& type, std::shared_ptr outer_scope) - : intrinsic_info(type), local_table(std::make_shared(outer_scope)) - { - } - - procedure_info::~procedure_info() - { - } - - std::shared_ptr procedure_info::scope() - { - return local_table; - } - - std::size_t procedure_info::stack_size() const noexcept - { - return local_stack_size + argument_stack_size; - } -} diff --git a/source/types.cc b/source/types.cc new file mode 100644 index 0000000..be85c77 --- /dev/null +++ b/source/types.cc @@ -0,0 +1,80 @@ +#include + +namespace elna +{ +namespace source +{ + type::type(const std::size_t byte_size) + : byte_size(byte_size) + { + } + + std::size_t type::size() const noexcept + { + return this->byte_size; + } + + const pointer_type *type::is_pointer_type() const + { + return nullptr; + } + + primitive_type::primitive_type(const std::string& type_name, const std::size_t byte_size) + : type(byte_size), m_type_name(type_name) + { + } + + std::string primitive_type::type_name() const + { + return m_type_name; + } + + pointer_type::pointer_type(std::shared_ptr base_type, const std::size_t byte_size) + : type(byte_size), base_type(base_type) + { + } + + const pointer_type *pointer_type::is_pointer_type() const + { + return this; + } + + std::string pointer_type::type_name() const + { + return '^' + base_type->type_name(); + } + + procedure_type::procedure_type(std::vector> arguments, const std::size_t byte_size) + : arguments(std::move(arguments)), type(byte_size) + { + } + + std::string procedure_type::type_name() const + { + std::string result{ "proc(" }; + for (const auto& argument : arguments) + { + result += argument->type_name() + ','; + } + result.at(result.size() - 1) = ')'; + + return result; + } + + bool operator==(const type& lhs, const type& rhs) noexcept + { + auto lhs_type = lhs.type_name(); + auto rhs_type = rhs.type_name(); + + return lhs_type == rhs_type; + } + + bool operator!=(const type& lhs, const type& rhs) noexcept + { + return !(lhs == rhs); + } + + const primitive_type boolean_type{ "Boolean", 1 }; + const primitive_type int_type{ "Int", 4 }; +} +} diff --git a/source/types.cpp b/source/types.cpp deleted file mode 100644 index dbc96a9..0000000 --- a/source/types.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include - -namespace elna::source -{ - type::type(const std::size_t byte_size) - : byte_size(byte_size) - { - } - - std::size_t type::size() const noexcept - { - return this->byte_size; - } - - primitive_type::primitive_type(const std::string& type_name, const std::size_t byte_size) - : type(byte_size), type_name(type_name) - { - } - - bool primitive_type::operator==(const primitive_type& that) const noexcept - { - return this->type_name == that.type_name; - } - - bool primitive_type::operator!=(const primitive_type& that) const noexcept - { - return this->type_name != that.type_name; - } - - pointer_type::pointer_type(std::shared_ptr base_type, const std::size_t byte_size) - : type(byte_size), base_type(base_type) - { - } - - bool pointer_type::operator==(const pointer_type& that) const noexcept - { - return this->base_type == that.base_type; - } - - bool pointer_type::operator!=(const pointer_type& that) const noexcept - { - return this->base_type != that.base_type; - } - - procedure_type::procedure_type(std::vector> arguments, const std::size_t byte_size) - : arguments(std::move(arguments)), type(byte_size) - { - } - - bool procedure_type::operator==(const procedure_type &that) const noexcept - { - return this->arguments == that.arguments; - } - - bool procedure_type::operator!=(const procedure_type &that) const noexcept - { - return this->arguments != that.arguments; - } - - bool operator==(const type& lhs, const type& rhs) noexcept - { - { - auto lhs_type = dynamic_cast(&lhs); - auto rhs_type = dynamic_cast(&rhs); - - if (lhs_type != nullptr && rhs_type != nullptr) - { - return *lhs_type == *rhs_type; - } - } - { - auto lhs_type = dynamic_cast(&lhs); - auto rhs_type = dynamic_cast(&rhs); - - if (lhs_type != nullptr && rhs_type != nullptr) - { - return *lhs_type == *rhs_type; - } - } - { - auto lhs_type = dynamic_cast(&lhs); - auto rhs_type = dynamic_cast(&rhs); - - if (lhs_type != nullptr && rhs_type != nullptr) - { - return *lhs_type == *rhs_type; - } - } - return false; - } - - bool operator!=(const type& lhs, const type& rhs) noexcept - { - return !(lhs == rhs); - } -}