Add semantic passes

This commit is contained in:
Eugen Wissner 2024-12-23 13:54:11 +01:00
parent f080b75c52
commit 40306ac986
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
27 changed files with 1220 additions and 325 deletions

View File

@ -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})

View File

@ -1,21 +1,21 @@
#include <elna/source/driver.hpp>
#include "parser.hpp"
#include <elna/source/driver.h>
#include "elna/source/semantic.h"
#include "parser.hh"
#include <sstream>
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<elna::source::constant_definition *>(definition.get()))

99
gcc/Make-lang.in Normal file
View File

@ -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)

13
gcc/config-lang.in Normal file
View File

@ -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"

16
gcc/elna-spec.cc Normal file
View File

@ -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;

252
gcc/elna1.cc Normal file
View File

@ -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 <fstream>
#include <elna/source/driver.h>
#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"

68
gcc/generic-visitor.cc Normal file
View File

@ -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);
}
}
}

3
gcc/lang-specs.h Normal file
View File

@ -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},

250
gcc/tiny1.cc Normal file
View File

@ -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"

16
gcc/tinyspec.cc Normal file
View File

@ -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;

View File

@ -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;
};
}
}

View File

@ -1,10 +1,12 @@
#pragma once
#include <memory>
#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;
};
}
}

View File

@ -1,10 +1,12 @@
#pragma once
#include <list>
#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<std::unique_ptr<struct error>>& errors() const noexcept;
};
}
}

View File

@ -2,9 +2,11 @@
#include <cstddef>
#include <filesystem>
#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;
};
}
}

View File

@ -1,10 +1,12 @@
#pragma once
#include <list>
#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;
};
}
}

View File

@ -5,9 +5,18 @@
#include <string>
#include <memory>
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<class type> m_type;
std::shared_ptr<const class type> m_type;
public:
explicit type_info(const class type& type);
explicit type_info(std::shared_ptr<class type> type);
~type_info() override;
virtual type_info *is_type_info() noexcept override;
std::shared_ptr<const class type> 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<const class type> type() const noexcept;
};
@ -60,6 +80,7 @@ namespace elna::source
public:
constant_info(std::shared_ptr<const class type> 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<const class type> 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<const class type> type);
virtual parameter_info *is_parameter_info() noexcept override;
};
/**
@ -98,6 +123,7 @@ namespace elna::source
std::shared_ptr<const class procedure_type> 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<symbol_table> 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<symbol_table> scope();
};
/**
* Creates a symbol table with predefined symbols.
*
* \return A symbol table with predefined symbols.
*/
std::shared_ptr<source::symbol_table> add_builtin_symbols();}
}

View File

@ -4,12 +4,18 @@
#include <string>
#include <vector>
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<const type> base_type;
@ -67,14 +80,15 @@ namespace elna::source
*/
pointer_type(std::shared_ptr<const type> 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<std::shared_ptr<const type>> arguments;
@ -87,13 +101,13 @@ namespace elna::source
*/
procedure_type(std::vector<std::shared_ptr<const type>> 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;
}
}

View File

@ -1,7 +1,8 @@
#include "elna/source/ast.hpp"
#include <stdexcept>
#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<block *>(program));
visit(reinterpret_cast<block *>(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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -3,10 +3,10 @@
#define YY_USER_ACTION this->location.columns(yyleng);
#include <sstream>
#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<unsigned int>(yytext[0]);
throw yy::parser::syntax_error(this->location, ss.str());
driver.error(this->location, ss.str());
}
%%

View File

@ -4,7 +4,7 @@
%code requires {
#include <cstdint>
#include <iostream>
#include "elna/source/driver.hpp"
#include "elna/source/driver.h"
#if !defined(yyFlexLexerOnce)
#include <FlexLexer.h>
@ -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

View File

@ -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<const type> got, operation kind, const std::filesystem::path& path,
const struct position position)
type_mismatch::type_mismatch(std::shared_ptr<const type> 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.";
}
}
}

View File

@ -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 <cstdlib>
namespace elna::source
namespace elna
{
namespace source
{
name_analysis_visitor::name_analysis_visitor(std::shared_ptr<symbol_table> 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<const class type>(int_type);
auto constant_type = std::make_shared<const class primitive_type>(int_type);
this->table->enter(definition->identifier(),
std::make_shared<constant_info>(constant_type, definition->body().number()));
}
std::shared_ptr<const type> name_analysis_visitor::convert_declaration_type(const type_expression& ast_type) const
{
auto variable_type = std::dynamic_pointer_cast<type_info>(table->lookup(ast_type.base()))
->type();
auto variable_type = table->lookup(ast_type.base())->is_type_info()->type();
std::shared_ptr<type> 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<const type> declaration_type = convert_declaration_type(declaration->type());
std::shared_ptr<const type> declaration_type = convert_declaration_type(declarationx->type());
this->table->enter(declaration->identifier(),
this->table->enter(declarationx->identifier(),
std::make_shared<variable_info>(declaration_type));
}
@ -87,12 +88,12 @@ namespace elna::source
{
auto declaration_info = this->table->lookup(declaration->identifier());
if (auto variable = std::dynamic_pointer_cast<variable_info>(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<parameter_info>(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<procedure_info>(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<procedure_info>(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<intrinsic_info>(this->table->lookup(statement->name()));
auto call_info = this->table->lookup(statement->name())->is_intrinsic_info();
this->argument_offset = std::max(static_cast<std::size_t>(this->argument_offset),
call_info->parameter_stack_size());
@ -141,17 +142,14 @@ namespace elna::source
{
for (auto& definition : program->definitions())
{
if (dynamic_cast<procedure_definition *>(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<procedure_info>(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<type_info>(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<type_info>(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<typed_info>(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<const pointer_type>(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<const primitive_type>(expression->lhs().data_type);
auto rhs_type = std::dynamic_pointer_cast<const primitive_type>(expression->rhs().data_type);
std::unique_ptr<type_mismatch> new_error;
if (lhs_type == nullptr || *lhs_type != int_type)
if (*expression->lhs().data_type != int_type)
{
new_error = std::make_unique<type_mismatch>(lhs_type,
new_error = std::make_unique<type_mismatch>(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<type_mismatch>(rhs_type,
new_error = std::make_unique<type_mismatch>(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<intrinsic_info>(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<const primitive_type>(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<const primitive_type>(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<typed_info>(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;
}
}
}

230
source/symbol_table.cc Normal file
View File

@ -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<symbol_table> scope)
: outer_scope(scope)
{
}
std::shared_ptr<info> 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<info> entry)
{
entries.insert({ name, entry });
}
std::shared_ptr<symbol_table> 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<class type> type)
: info(), m_type(type)
{
}
type_info::~type_info()
{
}
std::shared_ptr<const class type> 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<const class type> type)
: m_type(type)
{
}
typed_info::~typed_info()
{
}
typed_info *typed_info::is_typed_info() noexcept
{
return this;
}
std::shared_ptr<const class type> typed_info::type() const noexcept
{
return m_type;
}
constant_info::constant_info(const std::shared_ptr<const class type> 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<const class type> type)
: typed_info(type)
{
}
variable_info *variable_info::is_variable_info() noexcept
{
return this;
}
parameter_info::parameter_info(std::shared_ptr<const class type> 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<procedure_type>(type))
{
}
intrinsic_info::~intrinsic_info()
{
}
std::shared_ptr<const class procedure_type> 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<symbol_table> outer_scope)
: intrinsic_info(type), local_table(std::make_shared<symbol_table>(outer_scope))
{
}
procedure_info::~procedure_info()
{
}
std::shared_ptr<symbol_table> 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<source::symbol_table> add_builtin_symbols()
{
source::symbol_table result;
std::vector<std::shared_ptr<const source::type>> intrinsic_arguments;
auto prim = boolean_type;
auto boolean_info = std::make_shared<type_info>(std::make_shared<primitive_type>(boolean_type));
auto int_info = std::make_shared<source::type_info>(std::make_shared<primitive_type>(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::intrinsic_info>(
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::intrinsic_info>(
source::procedure_type{ intrinsic_arguments, pointer_size });
result.enter("writeb", writeb);
intrinsic_arguments.clear();
return std::make_shared<source::symbol_table>(std::move(result));
}
}
}

View File

@ -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<symbol_table> scope)
: outer_scope(scope)
{
}
std::shared_ptr<info> 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<info> entry)
{
entries.insert_or_assign(name, entry);
}
std::shared_ptr<symbol_table> 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<class type>(type))
{
}
type_info::~type_info()
{
}
std::shared_ptr<const class type> type_info::type() const noexcept
{
return m_type;
}
typed_info::typed_info(std::shared_ptr<const class type> type)
: m_type(type)
{
}
typed_info::~typed_info()
{
}
std::shared_ptr<const class type> typed_info::type() const noexcept
{
return m_type;
}
constant_info::constant_info(const std::shared_ptr<const class type> 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<const class type> type)
: typed_info(type)
{
}
parameter_info::parameter_info(std::shared_ptr<const class type> type)
: typed_info(type)
{
}
intrinsic_info::intrinsic_info(const class procedure_type& type)
: m_type(std::make_shared<procedure_type>(type))
{
}
intrinsic_info::~intrinsic_info()
{
}
std::shared_ptr<const class procedure_type> 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<symbol_table> outer_scope)
: intrinsic_info(type), local_table(std::make_shared<symbol_table>(outer_scope))
{
}
procedure_info::~procedure_info()
{
}
std::shared_ptr<symbol_table> procedure_info::scope()
{
return local_table;
}
std::size_t procedure_info::stack_size() const noexcept
{
return local_stack_size + argument_stack_size;
}
}

80
source/types.cc Normal file
View File

@ -0,0 +1,80 @@
#include <elna/source/types.h>
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<const type> 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<std::shared_ptr<const type>> 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 };
}
}

View File

@ -1,96 +0,0 @@
#include <elna/source/types.hpp>
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<const type> 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<std::shared_ptr<const type>> 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<const primitive_type *>(&lhs);
auto rhs_type = dynamic_cast<const primitive_type *>(&rhs);
if (lhs_type != nullptr && rhs_type != nullptr)
{
return *lhs_type == *rhs_type;
}
}
{
auto lhs_type = dynamic_cast<const pointer_type *>(&lhs);
auto rhs_type = dynamic_cast<const pointer_type *>(&rhs);
if (lhs_type != nullptr && rhs_type != nullptr)
{
return *lhs_type == *rhs_type;
}
}
{
auto lhs_type = dynamic_cast<const procedure_type *>(&lhs);
auto rhs_type = dynamic_cast<const procedure_type *>(&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);
}
}