Merge GCC frontend into the branch
This commit is contained in:
174
gcc/Make-lang.in
Normal file
174
gcc/Make-lang.in
Normal file
@@ -0,0 +1,174 @@
|
||||
# Top level -*- makefile -*- fragment for the Elna frontend.
|
||||
# Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
|
||||
# GCC is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# GCC is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GCC; see the file COPYING3. If not see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
ELNA_INSTALL_NAME := $(shell echo gelna|sed '$(program_transform_name)')
|
||||
ELNA_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo gelna|sed '$(program_transform_name)')
|
||||
|
||||
elna: elna1$(exeext)
|
||||
|
||||
.PHONY: elna
|
||||
|
||||
# Driver
|
||||
|
||||
ELNA_OBJS = \
|
||||
$(GCC_OBJS) \
|
||||
elna/elna-spec.o \
|
||||
$(END)
|
||||
|
||||
gelna$(exeext): $(ELNA_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS)
|
||||
+$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
|
||||
$(ELNA_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a \
|
||||
$(EXTRA_GCC_LIBS) $(LIBS)
|
||||
|
||||
# Create a version of the gelna driver which calls the cross-compiler.
|
||||
gelna-cross$(exeext): gelna$(exeext)
|
||||
-rm -f gelna-cross$(exeext)
|
||||
cp gelna$(exeext) gelna-cross$(exeext)
|
||||
|
||||
# The compiler proper
|
||||
|
||||
elna_OBJS = \
|
||||
elna/elna1.o \
|
||||
elna/elna-generic.o \
|
||||
elna/elna-diagnostic.o \
|
||||
elna/elna-tree.o \
|
||||
elna/elna-builtins.o \
|
||||
elna/ast.o \
|
||||
elna/dependency.o \
|
||||
elna/driver.o \
|
||||
elna/lexer.o \
|
||||
elna/parser.o \
|
||||
elna/semantic.o \
|
||||
elna/symbol.o \
|
||||
elna/result.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: gelna-cross$(exeext)
|
||||
|
||||
elna.start.encap: gelna$(exeext)
|
||||
elna.rest.encap:
|
||||
|
||||
# No elna-specific selftests.
|
||||
selftest-elna:
|
||||
|
||||
ELNA_TEXI_FILES = \
|
||||
elna/gcc/gelna.texi \
|
||||
$(srcdir)/doc/include/fdl.texi \
|
||||
$(srcdir)/doc/include/gpl_v3.texi \
|
||||
$(srcdir)/doc/include/funding.texi \
|
||||
$(srcdir)/doc/include/gcc-common.texi \
|
||||
gcc-vers.texi
|
||||
|
||||
elna.install-common: installdirs
|
||||
-rm -f $(DESTDIR)$(bindir)/$(ELNA_INSTALL_NAME)$(exeext)
|
||||
$(INSTALL_PROGRAM) gelna$(exeext) $(DESTDIR)$(bindir)/$(ELNA_INSTALL_NAME)$(exeext)
|
||||
-if test -f elna1$(exeext); then \
|
||||
if test -f gelna-cross$(exeext); then \
|
||||
:; \
|
||||
else \
|
||||
rm -f $(DESTDIR)$(bindir)/$(ELNA_TARGET_INSTALL_NAME)$(exeext); \
|
||||
( cd $(DESTDIR)$(bindir) && \
|
||||
$(LN) $(ELNA_INSTALL_NAME)$(exeext) $(ELNA_TARGET_INSTALL_NAME)$(exeext) ); \
|
||||
fi; \
|
||||
fi
|
||||
|
||||
$(build_htmldir)/gelna/index.html: $(ELNA_TEXI_FILES)
|
||||
$(mkinstalldirs) $(@D)
|
||||
rm -f $(@D)/*
|
||||
$(TEXI2HTML) -I $(gcc_docdir)/include -I $(srcdir)/elna -o $(@D) $<
|
||||
|
||||
# Required goals, they still do nothing
|
||||
elna.install-man:
|
||||
elna.install-info:
|
||||
elna.install-pdf:
|
||||
elna.install-plugin:
|
||||
|
||||
elna.install-html: $(build_htmldir)/gelna
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(htmldir)"
|
||||
@for p in $(build_htmldir)/gelna; do \
|
||||
if test -f "$$p" || test -d "$$p"; then d=""; else d="$(srcdir)/"; fi; \
|
||||
f=$(html__strip_dir) \
|
||||
if test -d "$$d$$p"; then \
|
||||
echo " $(mkinstalldirs) '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(mkinstalldirs) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
|
||||
echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \
|
||||
else \
|
||||
echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
elna.info:
|
||||
elna.dvi:
|
||||
elna.pdf:
|
||||
elna.html: $(build_htmldir)/gelna/index.html
|
||||
elna.man:
|
||||
elna.mostlyclean:
|
||||
elna.clean:
|
||||
elna.distclean:
|
||||
elna.maintainer-clean:
|
||||
|
||||
# make uninstall
|
||||
elna.uninstall:
|
||||
-rm -f gelna$(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/include -I elna/generated
|
||||
ELNA_CXXFLAGS = -std=c++17
|
||||
|
||||
elna/%.o: elna/frontend/%.cc elna/generated/parser.hh elna/generated/location.hh
|
||||
$(COMPILE) $(ELNA_CXXFLAGS) $(ELNA_INCLUDES) $<
|
||||
$(POSTCOMPILE)
|
||||
|
||||
elna/%.o: elna/generated/%.cc elna/generated/parser.hh elna/generated/location.hh
|
||||
$(COMPILE) $(ELNA_CXXFLAGS) $(ELNA_INCLUDES) $<
|
||||
$(POSTCOMPILE)
|
||||
|
||||
elna/%.o: elna/gcc/%.cc elna/generated/parser.hh elna/generated/location.hh
|
||||
$(COMPILE) $(ELNA_CXXFLAGS) $(ELNA_INCLUDES) $<
|
||||
$(POSTCOMPILE)
|
||||
|
||||
elna/generated/parser.cc: elna/frontend/parser.yy
|
||||
mkdir -p $(dir $@)
|
||||
$(BISON) -d -o $@ $<
|
||||
|
||||
elna/generated/parser.hh elna/generated/location.hh: elna/generated/parser.cc
|
||||
@touch $@
|
||||
|
||||
elna/generated/lexer.cc: elna/frontend/lexer.ll
|
||||
mkdir -p $(dir $@)
|
||||
$(FLEX) -o $@ $<
|
||||
42
gcc/README.md
Normal file
42
gcc/README.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Elna programming language
|
||||
|
||||
## Current implementation
|
||||
|
||||
This repository contains a GCC frontend for Elna. After finishing the frontend
|
||||
I'm planning to rewrite the compiler in Elna itself with its own backend and
|
||||
a hand-written parser. So GCC gives a way to have a simple bootstrap compiler
|
||||
and a possbility to compile Elna programs for different platforms.
|
||||
|
||||
## Grammar
|
||||
|
||||
Flex and bison grammar specifications, `lexer.ll` and `parser.yy`, can be found
|
||||
in the `boot/` directory.
|
||||
|
||||
## Build
|
||||
|
||||
The frontend requires GCC 15.2.0 (not tested with other versions).
|
||||
|
||||
Download the GCC source. Copy the contents of this repository into `gcc/elna`
|
||||
inside GCC. Finally build GCC enabling the frontend with
|
||||
`--enable-languages=c,c++,elna`. After the installation the compiler can be
|
||||
invoked with `$prefix/bin/gelna`.
|
||||
|
||||
There is also a `Rakefile` that downloads, builds and installs GCC into the
|
||||
`./build/` subdirectory. The `Rakefile` assumes that ruby and rake, as well as
|
||||
all GCC dependencies are already available in the system. It works under Linux
|
||||
and Mac OS. In the latter case GCC is patched with the patches used by Homebrew
|
||||
(official GCC doesn't support Apple silicon targets). Invoke with
|
||||
|
||||
```sh
|
||||
rake boot
|
||||
```
|
||||
|
||||
`gcc` binary is used by default, but a different gcc version can be specified
|
||||
by passing `CC` and `CXX` environment variables to rake, e.g.:
|
||||
|
||||
```sh
|
||||
rake CC=gcc-15 CXX=g++-15 boot
|
||||
```
|
||||
|
||||
See `rake -T` for more tasks. The GCC source is under `build/tools`. The
|
||||
installation path is `build/host/install`.
|
||||
37
gcc/config-lang.in
Normal file
37
gcc/config-lang.in
Normal file
@@ -0,0 +1,37 @@
|
||||
# Top level configure fragment for gcc Elna frontend.
|
||||
# Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
|
||||
# GCC is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# GCC is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GCC; see the file COPYING3. If not see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Configure looks for the existence of this file to auto-config each language.
|
||||
# We define several parameters used by configure:
|
||||
#
|
||||
# language - name of language as it would appear in $(LANGUAGES)
|
||||
# boot_language - "yes" if we need to build this language in stage1
|
||||
# compilers - value to add to $(COMPILERS)
|
||||
|
||||
language="elna"
|
||||
gcc_subdir="elna/gcc"
|
||||
|
||||
compilers="elna1\$(exeext)"
|
||||
|
||||
target_libs=""
|
||||
|
||||
gtfiles="\$(srcdir)/elna/gcc/elna1.cc \$(srcdir)/elna/include/elna/gcc/elna1.h"
|
||||
|
||||
lang_requires_boot_languages=c++
|
||||
|
||||
# Do not build by default
|
||||
build_by_default="no"
|
||||
274
gcc/elna-builtins.cc
Normal file
274
gcc/elna-builtins.cc
Normal file
@@ -0,0 +1,274 @@
|
||||
/* Builtin definitions.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "elna/gcc/elna-builtins.h"
|
||||
#include "elna/gcc/elna1.h"
|
||||
#include "stor-layout.h"
|
||||
#include "stringpool.h"
|
||||
#include "elna/gcc/elna-tree.h"
|
||||
|
||||
namespace elna::gcc
|
||||
{
|
||||
void init_ttree()
|
||||
{
|
||||
elna_int_type_node = long_integer_type_node;
|
||||
elna_word_type_node = size_type_node;
|
||||
elna_char_type_node = unsigned_char_type_node;
|
||||
elna_pointer_type_node = ptr_type_node;
|
||||
elna_float_type_node = double_type_node;
|
||||
|
||||
elna_bool_type_node = boolean_type_node;
|
||||
elna_bool_true_node = boolean_true_node;
|
||||
elna_bool_false_node = boolean_false_node;
|
||||
|
||||
elna_pointer_nil_node = null_pointer_node;
|
||||
|
||||
elna_string_type_node = make_node(RECORD_TYPE);
|
||||
tree string_ptr_type = build_pointer_type_for_mode(elna_char_type_node, VOIDmode, true);
|
||||
|
||||
elna_string_length_field_node = build_field(UNKNOWN_LOCATION,
|
||||
elna_string_type_node, "length", build_qualified_type(elna_word_type_node, TYPE_QUAL_CONST));
|
||||
elna_string_ptr_field_node = build_field(UNKNOWN_LOCATION,
|
||||
elna_string_type_node, "ptr", build_qualified_type(string_ptr_type, TYPE_QUAL_CONST));
|
||||
|
||||
TYPE_FIELDS(elna_string_type_node) = chainon(elna_string_ptr_field_node, elna_string_length_field_node);
|
||||
layout_type(elna_string_type_node);
|
||||
}
|
||||
|
||||
static
|
||||
tree declare_builtin_type(std::shared_ptr<symbol_table> symbol_table, const char *name, tree type)
|
||||
{
|
||||
tree identifier = get_identifier(name);
|
||||
tree type_declaration = build_decl(UNKNOWN_LOCATION, TYPE_DECL, identifier, type);
|
||||
|
||||
symbol_table->enter(name, type_declaration);
|
||||
|
||||
return type_declaration;
|
||||
}
|
||||
|
||||
std::shared_ptr<symbol_table> builtin_symbol_table()
|
||||
{
|
||||
std::shared_ptr<elna::gcc::symbol_table> symbol_table = std::make_shared<elna::gcc::symbol_table>();
|
||||
|
||||
declare_builtin_type(symbol_table, "Int", elna_int_type_node);
|
||||
declare_builtin_type(symbol_table, "Word", elna_word_type_node);
|
||||
declare_builtin_type(symbol_table, "Char", elna_char_type_node);
|
||||
declare_builtin_type(symbol_table, "Bool", elna_bool_type_node);
|
||||
declare_builtin_type(symbol_table, "Pointer", elna_pointer_type_node);
|
||||
declare_builtin_type(symbol_table, "Float", elna_float_type_node);
|
||||
|
||||
tree string_declaration = declare_builtin_type(symbol_table, "String", elna_string_type_node);
|
||||
TYPE_NAME(elna_string_type_node) = DECL_NAME(string_declaration);
|
||||
TYPE_STUB_DECL(elna_string_type_node) = string_declaration;
|
||||
|
||||
return symbol_table;
|
||||
}
|
||||
|
||||
tree build_composite_type(const std::vector<frontend::type_field>& fields, tree composite_type_node,
|
||||
std::shared_ptr<symbol_table> symbols)
|
||||
{
|
||||
for (auto& field : fields)
|
||||
{
|
||||
tree rewritten_field = get_inner_alias(field.second, symbols);
|
||||
tree field_declaration = build_field(UNKNOWN_LOCATION,
|
||||
composite_type_node, field.first, rewritten_field);
|
||||
TYPE_FIELDS(composite_type_node) = chainon(TYPE_FIELDS(composite_type_node), field_declaration);
|
||||
}
|
||||
layout_type(composite_type_node);
|
||||
return composite_type_node;
|
||||
}
|
||||
|
||||
tree build_procedure_type(const frontend::procedure_type& procedure, std::shared_ptr<symbol_table> symbols)
|
||||
{
|
||||
std::vector<tree> parameter_types(procedure.parameters.size());
|
||||
|
||||
for (std::size_t i = 0; i < procedure.parameters.size(); ++i)
|
||||
{
|
||||
parameter_types[i] = get_inner_alias(procedure.parameters.at(i), symbols);
|
||||
}
|
||||
tree return_type = void_type_node;
|
||||
|
||||
if (!procedure.return_type.proper_type.empty())
|
||||
{
|
||||
return_type = get_inner_alias(procedure.return_type.proper_type, symbols);
|
||||
}
|
||||
return build_function_type_array(return_type, procedure.parameters.size(), parameter_types.data());
|
||||
}
|
||||
|
||||
tree get_inner_alias(const frontend::type& type, std::shared_ptr<symbol_table> symbols)
|
||||
{
|
||||
if (auto reference = type.get<frontend::primitive_type>())
|
||||
{
|
||||
auto looked_up = symbols->lookup(reference->identifier);
|
||||
gcc_assert(looked_up != NULL_TREE);
|
||||
|
||||
return TREE_TYPE(looked_up);
|
||||
}
|
||||
else if (auto reference = type.get<frontend::record_type>())
|
||||
{
|
||||
tree composite_type_node = make_node(RECORD_TYPE);
|
||||
|
||||
build_composite_type(reference->fields, composite_type_node, symbols);
|
||||
|
||||
return composite_type_node;
|
||||
}
|
||||
else if (auto reference = type.get<frontend::union_type>())
|
||||
{
|
||||
tree composite_type_node = make_node(UNION_TYPE);
|
||||
|
||||
build_composite_type(reference->fields, composite_type_node, symbols);
|
||||
|
||||
return composite_type_node;
|
||||
}
|
||||
else if (auto reference = type.get<frontend::enumeration_type>())
|
||||
{
|
||||
return build_enumeration_type(reference->members);
|
||||
}
|
||||
else if (auto reference = type.get<frontend::pointer_type>())
|
||||
{
|
||||
return build_global_pointer_type(get_inner_alias(reference->base, symbols));
|
||||
}
|
||||
else if (auto reference = type.get<frontend::array_type>())
|
||||
{
|
||||
tree base = get_inner_alias(reference->base, symbols);
|
||||
|
||||
return build_static_array_type(base, reference->size);
|
||||
}
|
||||
else if (auto reference = type.get<frontend::procedure_type>())
|
||||
{
|
||||
auto procedure = build_procedure_type(*reference, symbols);
|
||||
|
||||
return build_global_pointer_type(procedure);
|
||||
}
|
||||
else if (auto reference = type.get<frontend::alias_type>())
|
||||
{
|
||||
return TREE_TYPE(handle_symbol(reference->name, reference, symbols));
|
||||
}
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
tree handle_symbol(const std::string& symbol_name, std::shared_ptr<frontend::alias_type> reference,
|
||||
std::shared_ptr<symbol_table> symbols)
|
||||
{
|
||||
tree looked_up = symbols->lookup(symbol_name);
|
||||
|
||||
if (looked_up == NULL_TREE)
|
||||
{
|
||||
tree type_tree = get_inner_alias(reference->reference, symbols);
|
||||
looked_up = build_decl(UNKNOWN_LOCATION, TYPE_DECL,
|
||||
get_identifier(symbol_name.c_str()), type_tree);
|
||||
|
||||
TREE_PUBLIC(looked_up) = 1;
|
||||
if (is_unique_type(type_tree))
|
||||
{
|
||||
TYPE_NAME(type_tree) = DECL_NAME(looked_up);
|
||||
TYPE_STUB_DECL(type_tree) = looked_up;
|
||||
}
|
||||
else
|
||||
{
|
||||
TYPE_NAME(type_tree) = looked_up;
|
||||
}
|
||||
symbols->enter(symbol_name, looked_up);
|
||||
}
|
||||
return looked_up;
|
||||
}
|
||||
|
||||
void declare_procedure(const std::string& name, const frontend::procedure_info& info,
|
||||
std::shared_ptr<symbol_table> symbols)
|
||||
{
|
||||
tree declaration_type = gcc::build_procedure_type(info.symbol, symbols);
|
||||
tree fndecl = build_fn_decl(name.c_str(), declaration_type);
|
||||
symbols->enter(name, fndecl);
|
||||
|
||||
if (info.symbol.return_type.no_return)
|
||||
{
|
||||
TREE_THIS_VOLATILE(fndecl) = 1;
|
||||
}
|
||||
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, TREE_TYPE(declaration_type));
|
||||
DECL_CONTEXT(resdecl) = fndecl;
|
||||
DECL_RESULT(fndecl) = resdecl;
|
||||
|
||||
tree argument_chain = NULL_TREE;
|
||||
function_args_iterator parameter_type;
|
||||
function_args_iter_init(¶meter_type, declaration_type);
|
||||
|
||||
std::vector<std::string>::const_iterator parameter_name = info.names.cbegin();
|
||||
|
||||
for (frontend::type parameter : info.symbol.parameters)
|
||||
{
|
||||
tree declaration_tree = build_decl(UNKNOWN_LOCATION, PARM_DECL,
|
||||
get_identifier(parameter_name->c_str()), function_args_iter_cond(¶meter_type));
|
||||
DECL_CONTEXT(declaration_tree) = fndecl;
|
||||
DECL_ARG_TYPE(declaration_tree) = function_args_iter_cond(¶meter_type);
|
||||
|
||||
argument_chain = chainon(argument_chain, declaration_tree);
|
||||
function_args_iter_next(¶meter_type);
|
||||
++parameter_name;
|
||||
}
|
||||
DECL_ARGUMENTS(fndecl) = argument_chain;
|
||||
TREE_ADDRESSABLE(fndecl) = 1;
|
||||
DECL_EXTERNAL(fndecl) = info.is_extern();
|
||||
TREE_PUBLIC(fndecl) = info.exported;
|
||||
}
|
||||
|
||||
tree declare_variable(const std::string& name, const frontend::variable_info& info,
|
||||
std::shared_ptr<symbol_table> symbols)
|
||||
{
|
||||
auto variable_type = get_inner_alias(info.symbol, symbols);
|
||||
tree declaration_tree = build_decl(UNKNOWN_LOCATION, VAR_DECL, get_identifier(name.c_str()), variable_type);
|
||||
|
||||
TREE_ADDRESSABLE(declaration_tree) = 1;
|
||||
DECL_EXTERNAL(declaration_tree) = info.is_extern;
|
||||
TREE_PUBLIC(declaration_tree) = info.exported;
|
||||
|
||||
symbols->enter(name, declaration_tree);
|
||||
|
||||
return declaration_tree;
|
||||
}
|
||||
|
||||
void declare_type(const std::string& name, const frontend::type_info& info, std::shared_ptr<symbol_table> symbols)
|
||||
{
|
||||
// The top level symbol table has basic (builtin) types in it which are not aliases.
|
||||
if (auto alias_type = info.symbol.get<frontend::alias_type>())
|
||||
{
|
||||
tree type_declaration = handle_symbol(name, alias_type, symbols);
|
||||
|
||||
TREE_PUBLIC(type_declaration) = info.exported;
|
||||
}
|
||||
}
|
||||
|
||||
void rewrite_symbol_table(std::shared_ptr<frontend::symbol_table> info_table, std::shared_ptr<symbol_table> symbols)
|
||||
{
|
||||
for (auto& [symbol_name, symbol_info] : *info_table)
|
||||
{
|
||||
if (auto type_info = symbol_info->is_type())
|
||||
{
|
||||
declare_type(symbol_name, *type_info, symbols);
|
||||
}
|
||||
else if (auto variable_info = symbol_info->is_variable())
|
||||
{
|
||||
declare_variable(symbol_name, *variable_info, symbols);
|
||||
}
|
||||
else if (auto procedure_info = symbol_info->is_procedure())
|
||||
{
|
||||
declare_procedure(symbol_name, *procedure_info, symbols);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
167
gcc/elna-diagnostic.cc
Normal file
167
gcc/elna-diagnostic.cc
Normal file
@@ -0,0 +1,167 @@
|
||||
/* Elna frontend specific diagnostic routines.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "elna/gcc/elna-diagnostic.h"
|
||||
#include "elna/gcc/elna-tree.h"
|
||||
#include "elna/gcc/elna1.h"
|
||||
|
||||
namespace elna::gcc
|
||||
{
|
||||
linemap_guard::linemap_guard(const char *filename)
|
||||
{
|
||||
linemap_add(line_table, LC_ENTER, 0, filename, 1);
|
||||
}
|
||||
|
||||
linemap_guard::~linemap_guard()
|
||||
{
|
||||
linemap_add(line_table, LC_LEAVE, 0, NULL, 0);
|
||||
}
|
||||
|
||||
location_t get_location(const frontend::position *position)
|
||||
{
|
||||
linemap_line_start(line_table, position->line, 0);
|
||||
|
||||
return linemap_position_for_column(line_table, position->column);
|
||||
}
|
||||
|
||||
std::string print_aggregate_name(tree type, const std::string& kind_name)
|
||||
{
|
||||
if (TYPE_IDENTIFIER(type) == NULL_TREE)
|
||||
{
|
||||
return kind_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string(IDENTIFIER_POINTER(TYPE_IDENTIFIER(type)));
|
||||
}
|
||||
}
|
||||
|
||||
std::string print_type(tree type)
|
||||
{
|
||||
gcc_assert(TYPE_P(type));
|
||||
|
||||
tree unqualified_type = get_qualified_type(type, TYPE_UNQUALIFIED);
|
||||
tree_code code = TREE_CODE(type);
|
||||
|
||||
if (unqualified_type == elna_int_type_node)
|
||||
{
|
||||
return "Int";
|
||||
}
|
||||
else if (unqualified_type == elna_word_type_node)
|
||||
{
|
||||
return "Word";
|
||||
}
|
||||
else if (unqualified_type == elna_bool_type_node)
|
||||
{
|
||||
return "Bool";
|
||||
}
|
||||
else if (unqualified_type == elna_pointer_type_node)
|
||||
{
|
||||
return "Pointer";
|
||||
}
|
||||
else if (unqualified_type == elna_float_type_node)
|
||||
{
|
||||
return "Float";
|
||||
}
|
||||
else if (unqualified_type == elna_char_type_node)
|
||||
{
|
||||
return "Char";
|
||||
}
|
||||
else if (unqualified_type == elna_string_type_node)
|
||||
{
|
||||
return "String";
|
||||
}
|
||||
else if (is_void_type(unqualified_type)) // For procedures without a return type.
|
||||
{
|
||||
return "()";
|
||||
}
|
||||
else if (POINTER_TYPE_P(unqualified_type))
|
||||
{
|
||||
tree pointer_target_type = TREE_TYPE(type);
|
||||
|
||||
if (TREE_CODE(pointer_target_type) == FUNCTION_TYPE)
|
||||
{
|
||||
return print_type(pointer_target_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string("^" + print_type(pointer_target_type));
|
||||
}
|
||||
}
|
||||
else if (code == FUNCTION_TYPE)
|
||||
{
|
||||
std::string output = "proc(";
|
||||
tree parameter_type = TYPE_ARG_TYPES(type);
|
||||
while (TREE_VALUE(parameter_type) != void_type_node)
|
||||
{
|
||||
output += print_type(TREE_VALUE(parameter_type));
|
||||
parameter_type = TREE_CHAIN(parameter_type);
|
||||
if (TREE_VALUE(parameter_type) == void_type_node)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
output += ", ";
|
||||
}
|
||||
}
|
||||
output += ')';
|
||||
tree return_type = TREE_TYPE(type);
|
||||
|
||||
if (!is_void_type(return_type))
|
||||
{
|
||||
output += " -> " + print_type(return_type);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
else if (code == ARRAY_TYPE)
|
||||
{
|
||||
return "array";
|
||||
}
|
||||
else if (code == RECORD_TYPE)
|
||||
{
|
||||
return print_aggregate_name(unqualified_type, "record");
|
||||
}
|
||||
else if (code == UNION_TYPE)
|
||||
{
|
||||
return print_aggregate_name(unqualified_type, "union");
|
||||
}
|
||||
else if (code == ENUMERAL_TYPE)
|
||||
{
|
||||
return print_aggregate_name(unqualified_type, "enumeration");
|
||||
}
|
||||
else
|
||||
{
|
||||
return "<<unknown-type>>";
|
||||
}
|
||||
gcc_unreachable();
|
||||
}
|
||||
|
||||
void report_errors(const std::deque<std::unique_ptr<frontend::error>>& errors)
|
||||
{
|
||||
for (const auto& error : errors)
|
||||
{
|
||||
location_t gcc_location{ UNKNOWN_LOCATION };
|
||||
|
||||
if (error->position.line != 0 || error->position.column != 0)
|
||||
{
|
||||
gcc_location = elna::gcc::get_location(&error->position);
|
||||
}
|
||||
error_at(gcc_location, error->what().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
1277
gcc/elna-generic.cc
Normal file
1277
gcc/elna-generic.cc
Normal file
File diff suppressed because it is too large
Load Diff
31
gcc/elna-spec.cc
Normal file
31
gcc/elna-spec.cc
Normal file
@@ -0,0 +1,31 @@
|
||||
/* Specific flags and argument handling of the Elna front end.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
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;
|
||||
315
gcc/elna-tree.cc
Normal file
315
gcc/elna-tree.cc
Normal file
@@ -0,0 +1,315 @@
|
||||
/* Utilities to manipulate GCC trees.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "elna/gcc/elna-tree.h"
|
||||
#include "elna/gcc/elna-diagnostic.h"
|
||||
#include "elna/gcc/elna1.h"
|
||||
|
||||
#include "function.h"
|
||||
#include "stor-layout.h"
|
||||
#include "diagnostic-core.h"
|
||||
|
||||
namespace elna::gcc
|
||||
{
|
||||
bool is_integral_type(tree type)
|
||||
{
|
||||
gcc_assert(TYPE_P(type));
|
||||
return TREE_CODE(type) == INTEGER_TYPE && type != elna_char_type_node;
|
||||
}
|
||||
|
||||
bool is_numeric_type(tree type)
|
||||
{
|
||||
return is_integral_type(type) || type == elna_float_type_node;
|
||||
}
|
||||
|
||||
bool is_unique_type(tree type)
|
||||
{
|
||||
gcc_assert(TYPE_P(type));
|
||||
return RECORD_OR_UNION_TYPE_P(type) || TREE_CODE(type) == ENUMERAL_TYPE;
|
||||
}
|
||||
|
||||
bool is_void_type(tree type)
|
||||
{
|
||||
return type == NULL_TREE || type == void_type_node;
|
||||
}
|
||||
|
||||
bool is_castable_type(tree type)
|
||||
{
|
||||
gcc_assert(TYPE_P(type));
|
||||
return INTEGRAL_TYPE_P(type) || POINTER_TYPE_P(type) || TREE_CODE(type) == REAL_TYPE;
|
||||
}
|
||||
|
||||
bool are_compatible_pointers(tree lhs_type, tree rhs)
|
||||
{
|
||||
gcc_assert(TYPE_P(lhs_type));
|
||||
tree rhs_type = TREE_TYPE(rhs);
|
||||
|
||||
return (POINTER_TYPE_P(lhs_type) && rhs == elna_pointer_nil_node)
|
||||
|| (POINTER_TYPE_P(lhs_type) && lhs_type == rhs_type);
|
||||
}
|
||||
|
||||
tree prepare_rvalue(tree rvalue)
|
||||
{
|
||||
if (DECL_P(rvalue) && TREE_CODE(TREE_TYPE(rvalue)) == FUNCTION_TYPE)
|
||||
{
|
||||
return build1(ADDR_EXPR, build_pointer_type_for_mode(TREE_TYPE(rvalue), VOIDmode, true), rvalue);
|
||||
}
|
||||
else
|
||||
{
|
||||
return rvalue;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_assignable_from(tree assignee, tree assignment)
|
||||
{
|
||||
return get_qualified_type(TREE_TYPE(assignment), TYPE_UNQUALIFIED) == assignee
|
||||
|| are_compatible_pointers(assignee, assignment);
|
||||
}
|
||||
|
||||
void append_statement(tree statement_tree)
|
||||
{
|
||||
if (!vec_safe_is_empty(f_binding_level->defers))
|
||||
{
|
||||
append_to_statement_list(statement_tree, &f_binding_level->defers->begin()->try_statements);
|
||||
}
|
||||
else
|
||||
{
|
||||
append_to_statement_list(statement_tree, &f_binding_level->statement_list);
|
||||
}
|
||||
}
|
||||
|
||||
void defer(tree statement_tree)
|
||||
{
|
||||
defer_scope new_defer{ statement_tree, alloc_stmt_list() };
|
||||
vec_safe_insert(f_binding_level->defers, 0, new_defer);
|
||||
}
|
||||
|
||||
tree chain_defer()
|
||||
{
|
||||
if (vec_safe_is_empty(f_binding_level->defers))
|
||||
{
|
||||
return f_binding_level->statement_list;
|
||||
}
|
||||
defer_scope *defer_iterator = f_binding_level->defers->begin();
|
||||
tree defer_tree = build2(TRY_FINALLY_EXPR, void_type_node,
|
||||
defer_iterator->try_statements, defer_iterator->defer_block);
|
||||
int i;
|
||||
|
||||
FOR_EACH_VEC_ELT_FROM(*f_binding_level->defers, i, defer_iterator, 1)
|
||||
{
|
||||
append_to_statement_list(defer_tree, &defer_iterator->try_statements);
|
||||
defer_tree = build2(TRY_FINALLY_EXPR, void_type_node,
|
||||
defer_iterator->try_statements, defer_iterator->defer_block);
|
||||
}
|
||||
return build2(COMPOUND_EXPR, TREE_TYPE(defer_tree), f_binding_level->statement_list, defer_tree);
|
||||
}
|
||||
|
||||
tree build_field(location_t location, tree record_type, const std::string name, tree type)
|
||||
{
|
||||
tree field_declaration = build_decl(location,
|
||||
FIELD_DECL, get_identifier(name.c_str()), type);
|
||||
TREE_ADDRESSABLE(field_declaration) = 1;
|
||||
DECL_CONTEXT(field_declaration) = record_type;
|
||||
|
||||
return field_declaration;
|
||||
}
|
||||
|
||||
tree do_pointer_arithmetic(frontend::binary_operator binary_operator,
|
||||
tree left, tree right, location_t operation_location)
|
||||
{
|
||||
tree left_type = get_qualified_type(TREE_TYPE(left), TYPE_UNQUALIFIED);
|
||||
tree right_type = get_qualified_type(TREE_TYPE(right), TYPE_UNQUALIFIED);
|
||||
if (binary_operator == frontend::binary_operator::sum)
|
||||
{
|
||||
tree pointer{ NULL_TREE };
|
||||
tree offset{ NULL_TREE };
|
||||
tree pointer_type{ NULL_TREE };
|
||||
|
||||
if (POINTER_TYPE_P(left_type) && is_integral_type(right_type))
|
||||
{
|
||||
pointer = left;
|
||||
offset = right;
|
||||
pointer_type = left_type;
|
||||
}
|
||||
else if (is_integral_type(left_type) && POINTER_TYPE_P(right_type))
|
||||
{
|
||||
pointer = right;
|
||||
offset = left;
|
||||
pointer_type = right_type;
|
||||
}
|
||||
else
|
||||
{
|
||||
return error_mark_node;
|
||||
}
|
||||
tree size_exp = pointer_type == elna_pointer_type_node
|
||||
? size_one_node
|
||||
: fold_convert(TREE_TYPE(offset), size_in_bytes(TREE_TYPE(TREE_TYPE(pointer))));
|
||||
|
||||
offset = fold_build2(MULT_EXPR, TREE_TYPE(offset), offset, size_exp);
|
||||
offset = fold_convert(sizetype, offset);
|
||||
|
||||
return fold_build2_loc(operation_location, POINTER_PLUS_EXPR, TREE_TYPE(pointer), pointer, offset);
|
||||
}
|
||||
else if (binary_operator == frontend::binary_operator::subtraction)
|
||||
{
|
||||
if (POINTER_TYPE_P(left_type) && is_integral_type(right_type))
|
||||
{
|
||||
tree pointer_type = left_type;
|
||||
tree offset_type = right_type;
|
||||
tree size_exp = fold_convert(offset_type, size_in_bytes(TREE_TYPE(pointer_type)));
|
||||
|
||||
tree convert_expression = fold_build2(MULT_EXPR, offset_type, right, size_exp);
|
||||
convert_expression = fold_convert(sizetype, convert_expression);
|
||||
|
||||
convert_expression = fold_build1(NEGATE_EXPR, sizetype, convert_expression);
|
||||
return fold_build2_loc(operation_location, POINTER_PLUS_EXPR, pointer_type, left, convert_expression);
|
||||
}
|
||||
else if (POINTER_TYPE_P(left_type) && POINTER_TYPE_P(right_type) && left_type == right_type)
|
||||
{
|
||||
return fold_build2_loc(operation_location, POINTER_DIFF_EXPR, ssizetype, left, right);
|
||||
}
|
||||
}
|
||||
gcc_unreachable();
|
||||
}
|
||||
|
||||
tree build_binary_operation(bool condition, frontend::binary_expression *expression,
|
||||
tree_code operator_code, tree left, tree right, tree target_type)
|
||||
{
|
||||
location_t expression_location = get_location(&expression->position());
|
||||
tree left_type = get_qualified_type(TREE_TYPE(left), TYPE_UNQUALIFIED);
|
||||
tree right_type = get_qualified_type(TREE_TYPE(right), TYPE_UNQUALIFIED);
|
||||
|
||||
if (condition)
|
||||
{
|
||||
return fold_build2_loc(expression_location, operator_code, target_type, left, right);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_at(expression_location,
|
||||
"invalid operands of type '%s' and '%s' for operator %s",
|
||||
print_type(left_type).c_str(), print_type(right_type).c_str(),
|
||||
elna::frontend::print_binary_operator(expression->operation()));
|
||||
return error_mark_node;
|
||||
}
|
||||
}
|
||||
|
||||
tree find_field_by_name(location_t expression_location, tree type, const std::string& field_name)
|
||||
{
|
||||
if (type == error_mark_node)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
tree field_declaration = TYPE_FIELDS(type);
|
||||
|
||||
if (!RECORD_OR_UNION_TYPE_P(type))
|
||||
{
|
||||
error_at(expression_location, "Type '%s' does not have a field named '%s'",
|
||||
print_type(type).c_str(), field_name.c_str());
|
||||
return error_mark_node;
|
||||
}
|
||||
while (field_declaration != NULL_TREE)
|
||||
{
|
||||
tree declaration_name = DECL_NAME(field_declaration);
|
||||
const char *identifier_pointer = IDENTIFIER_POINTER(declaration_name);
|
||||
|
||||
if (field_name == identifier_pointer)
|
||||
{
|
||||
break;
|
||||
}
|
||||
field_declaration = TREE_CHAIN(field_declaration);
|
||||
}
|
||||
if (field_declaration == NULL_TREE)
|
||||
{
|
||||
error_at(expression_location, "Aggregate type does not have a field '%s'", field_name.c_str());
|
||||
return error_mark_node;
|
||||
}
|
||||
return field_declaration;
|
||||
}
|
||||
|
||||
tree build_global_pointer_type(tree type)
|
||||
{
|
||||
return build_pointer_type_for_mode(type, VOIDmode, true);
|
||||
}
|
||||
|
||||
tree build_static_array_type(tree type, const std::uint64_t size)
|
||||
{
|
||||
tree upper_bound = build_int_cst_type(integer_type_node, size);
|
||||
tree range_type = build_range_type(integer_type_node, size_one_node, upper_bound);
|
||||
|
||||
return build_array_type(type, range_type);
|
||||
}
|
||||
|
||||
tree build_enumeration_type(const std::vector<std::string>& members)
|
||||
{
|
||||
tree composite_type_node = make_node(ENUMERAL_TYPE);
|
||||
const tree base_type = integer_type_node;
|
||||
|
||||
TREE_TYPE(composite_type_node) = base_type;
|
||||
ENUM_IS_SCOPED(composite_type_node) = 1;
|
||||
|
||||
tree *pp = &TYPE_VALUES(composite_type_node);
|
||||
std::size_t order{ 1 };
|
||||
|
||||
for (const std::string& member : members)
|
||||
{
|
||||
tree member_name = get_identifier(member.c_str());
|
||||
tree member_declaration = build_decl(UNKNOWN_LOCATION, CONST_DECL, member_name, composite_type_node);
|
||||
|
||||
DECL_CONTEXT(member_declaration) = composite_type_node;
|
||||
DECL_INITIAL(member_declaration) = build_int_cst_type(composite_type_node, order++);
|
||||
TREE_CONSTANT(member_declaration) = 1;
|
||||
TREE_READONLY(member_declaration) = 1;
|
||||
|
||||
TYPE_MAX_VALUE(composite_type_node) = DECL_INITIAL(member_declaration);
|
||||
|
||||
*pp = build_tree_list(member_name, member_declaration);
|
||||
pp = &TREE_CHAIN(*pp);
|
||||
}
|
||||
TYPE_MIN_VALUE(composite_type_node) = DECL_INITIAL(TREE_VALUE(TYPE_VALUES(composite_type_node)));
|
||||
TYPE_UNSIGNED(composite_type_node) = TYPE_UNSIGNED(base_type);
|
||||
SET_TYPE_ALIGN(composite_type_node, TYPE_ALIGN(base_type));
|
||||
TYPE_SIZE(composite_type_node) = NULL_TREE;
|
||||
TYPE_PRECISION(composite_type_node) = TYPE_PRECISION(base_type);
|
||||
|
||||
layout_type(composite_type_node);
|
||||
return composite_type_node;
|
||||
}
|
||||
|
||||
tree build_label_decl(const char *name, location_t loc)
|
||||
{
|
||||
auto label_decl = build_decl(loc, LABEL_DECL, get_identifier(name), void_type_node);
|
||||
|
||||
DECL_CONTEXT(label_decl) = current_function_decl;
|
||||
|
||||
return label_decl;
|
||||
}
|
||||
|
||||
tree extract_constant(tree expression)
|
||||
{
|
||||
int code = TREE_CODE(expression);
|
||||
|
||||
if (code == CONST_DECL)
|
||||
{
|
||||
return DECL_INITIAL(expression);
|
||||
}
|
||||
else if (TREE_CODE_CLASS(code) == tcc_constant)
|
||||
{
|
||||
return expression;
|
||||
}
|
||||
return NULL_TREE;
|
||||
}
|
||||
}
|
||||
256
gcc/elna1.cc
Normal file
256
gcc/elna1.cc
Normal file
@@ -0,0 +1,256 @@
|
||||
/* Language-dependent hooks for Elna.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "target.h"
|
||||
#include "function.h"
|
||||
#include "tree.h"
|
||||
#include "elna/gcc/elna1.h"
|
||||
#include "diagnostic.h"
|
||||
#include "opts.h"
|
||||
#include "debug.h"
|
||||
#include "langhooks.h"
|
||||
#include "langhooks-def.h"
|
||||
|
||||
#include <fstream>
|
||||
#include "elna/frontend/dependency.h"
|
||||
#include "elna/gcc/elna-tree.h"
|
||||
#include "elna/gcc/elna-generic.h"
|
||||
#include "elna/gcc/elna-diagnostic.h"
|
||||
#include "elna/gcc/elna-builtins.h"
|
||||
|
||||
tree elna_global_trees[ELNA_TI_MAX];
|
||||
hash_map<nofree_string_hash, tree> *elna_global_decls = nullptr;
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
/* Language hooks. */
|
||||
|
||||
static bool elna_langhook_init(void)
|
||||
{
|
||||
build_common_tree_nodes(false);
|
||||
|
||||
elna::gcc::init_ttree();
|
||||
elna_global_decls = hash_map<nofree_string_hash, tree>::create_ggc(default_hash_map_size);
|
||||
|
||||
build_common_builtin_nodes();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
using dependency_state = elna::frontend::dependency_state<std::shared_ptr<elna::gcc::symbol_table>>;
|
||||
|
||||
static elna::frontend::dependency elna_parse_file(dependency_state& state, const char *filename)
|
||||
{
|
||||
std::ifstream entry_point{ filename, std::ios::in };
|
||||
|
||||
if (!entry_point)
|
||||
{
|
||||
fatal_error(UNKNOWN_LOCATION, "Cannot open filename %s: %m", filename);
|
||||
}
|
||||
elna::gcc::linemap_guard{ filename };
|
||||
elna::frontend::dependency outcome = elna::frontend::read_source(entry_point, filename);
|
||||
|
||||
if (outcome.has_errors())
|
||||
{
|
||||
elna::gcc::report_errors(outcome.errors());
|
||||
return outcome;
|
||||
}
|
||||
elna::frontend::symbol_bag outcome_bag = elna::frontend::symbol_bag{ std::move(outcome.unresolved), state.globals };
|
||||
|
||||
for (const auto& sub_tree : outcome.tree->imports)
|
||||
{
|
||||
std::filesystem::path sub_path = "source" / elna::frontend::build_path(sub_tree->segments);
|
||||
std::unordered_map<std::filesystem::path, elna::frontend::symbol_bag>::const_iterator cached_import =
|
||||
state.cache.find(sub_path);
|
||||
|
||||
if (cached_import == state.cache.end())
|
||||
{
|
||||
elna_parse_file(state, sub_path.c_str());
|
||||
cached_import = state.cache.find(sub_path);
|
||||
}
|
||||
outcome_bag.add_import(cached_import->second);
|
||||
}
|
||||
outcome.errors() = analyze_semantics(filename, outcome.tree, outcome_bag);
|
||||
|
||||
if (outcome.has_errors())
|
||||
{
|
||||
elna::gcc::report_errors(outcome.errors());
|
||||
return outcome;
|
||||
}
|
||||
state.cache.insert({ filename, outcome_bag });
|
||||
elna::gcc::rewrite_symbol_table(outcome_bag.leave(), state.custom);
|
||||
|
||||
return outcome;
|
||||
}
|
||||
|
||||
static void elna_langhook_parse_file(void)
|
||||
{
|
||||
dependency_state state{ elna::gcc::builtin_symbol_table() };
|
||||
|
||||
for (unsigned int i = 0; i < num_in_fnames; i++)
|
||||
{
|
||||
elna::frontend::dependency outcome = elna_parse_file(state, in_fnames[i]);
|
||||
|
||||
linemap_add(line_table, LC_ENTER, 0, in_fnames[i], 1);
|
||||
elna::gcc::generic_visitor generic_visitor{ state.custom, state.cache.find(in_fnames[i])->second };
|
||||
outcome.tree->accept(&generic_visitor);
|
||||
linemap_add(line_table, LC_LEAVE, 0, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static tree elna_langhook_type_for_mode(enum machine_mode mode, int unsignedp)
|
||||
{
|
||||
if (mode == TYPE_MODE(float_type_node))
|
||||
{
|
||||
return float_type_node;
|
||||
}
|
||||
else 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;
|
||||
}
|
||||
else if (mode == TYPE_MODE(intHI_type_node))
|
||||
{
|
||||
return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
|
||||
}
|
||||
else if (mode == TYPE_MODE(intSI_type_node))
|
||||
{
|
||||
return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
|
||||
}
|
||||
else if (mode == TYPE_MODE(intDI_type_node))
|
||||
{
|
||||
return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
|
||||
}
|
||||
else if (mode == TYPE_MODE(intTI_type_node))
|
||||
{
|
||||
return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
|
||||
}
|
||||
else if (mode == TYPE_MODE(integer_type_node))
|
||||
{
|
||||
return unsignedp ? unsigned_type_node : integer_type_node;
|
||||
}
|
||||
else if (mode == TYPE_MODE(long_integer_type_node))
|
||||
{
|
||||
return unsignedp ? long_unsigned_type_node : long_integer_type_node;
|
||||
}
|
||||
else 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 nullptr;
|
||||
}
|
||||
|
||||
static bool global_bindings_p(void)
|
||||
{
|
||||
return current_function_decl == NULL_TREE;
|
||||
}
|
||||
|
||||
static tree pushdecl(tree decl)
|
||||
{
|
||||
return decl;
|
||||
}
|
||||
|
||||
static tree elna_langhook_builtin_function(tree decl)
|
||||
{
|
||||
elna_global_decls->put(IDENTIFIER_POINTER(DECL_NAME(decl)), decl);
|
||||
return decl;
|
||||
}
|
||||
|
||||
static unsigned int elna_langhook_option_lang_mask(void)
|
||||
{
|
||||
return CL_Elna;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
if (error_operand_p(type) || error_operand_p(expr))
|
||||
{
|
||||
return error_mark_node;
|
||||
}
|
||||
if (TREE_TYPE(expr) == type)
|
||||
{
|
||||
return expr;
|
||||
}
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
#undef LANG_HOOKS_NAME
|
||||
#define LANG_HOOKS_NAME "GNU 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_GETDECLS
|
||||
#define LANG_HOOKS_GETDECLS hook_tree_void_null
|
||||
|
||||
#undef LANG_HOOKS_BUILTIN_FUNCTION
|
||||
#define LANG_HOOKS_BUILTIN_FUNCTION elna_langhook_builtin_function
|
||||
|
||||
#undef LANG_HOOKS_IDENTIFIER_SIZE
|
||||
#define LANG_HOOKS_IDENTIFIER_SIZE sizeof(struct tree_identifier)
|
||||
|
||||
#undef LANG_HOOKS_OPTION_LANG_MASK
|
||||
#define LANG_HOOKS_OPTION_LANG_MASK elna_langhook_option_lang_mask
|
||||
|
||||
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
|
||||
|
||||
#include "gt-elna-elna1.h"
|
||||
#include "gtype-elna.h"
|
||||
135
gcc/gelna.texi
Normal file
135
gcc/gelna.texi
Normal file
@@ -0,0 +1,135 @@
|
||||
\input texinfo @c -*-texinfo-*-
|
||||
@setfilename gelna.info
|
||||
@settitle The GNU Elna Compiler
|
||||
|
||||
@c Create a separate index for command line options
|
||||
@defcodeindex op
|
||||
@c Merge the standard indexes into a single one.
|
||||
@syncodeindex fn cp
|
||||
@syncodeindex vr cp
|
||||
@syncodeindex ky cp
|
||||
@syncodeindex pg cp
|
||||
@syncodeindex tp cp
|
||||
|
||||
@include gcc-common.texi
|
||||
|
||||
@c Copyright years for this manual.
|
||||
@set copyrights-elna 2025
|
||||
|
||||
@copying
|
||||
@c man begin COPYRIGHT
|
||||
Copyright @copyright{} @value{copyrights-elna} Free Software Foundation, Inc.
|
||||
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
under the terms of the GNU Free Documentation License, Version 1.3 or
|
||||
any later version published by the Free Software Foundation; with no
|
||||
Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
|
||||
A copy of the license is included in the
|
||||
@c man end
|
||||
section entitled ``GNU Free Documentation License''.
|
||||
@ignore
|
||||
@c man begin COPYRIGHT
|
||||
man page gfdl(7).
|
||||
@c man end
|
||||
@end ignore
|
||||
@end copying
|
||||
|
||||
@ifinfo
|
||||
@format
|
||||
@dircategory Software development
|
||||
@direntry
|
||||
* Gelna: (gelna). A GCC-based compiler for the Elna language
|
||||
@end direntry
|
||||
@end format
|
||||
|
||||
@insertcopying
|
||||
@end ifinfo
|
||||
|
||||
@titlepage
|
||||
@title The GNU Elna Compiler
|
||||
@versionsubtitle
|
||||
@author Eugen Wissner
|
||||
|
||||
@page
|
||||
@vskip 0pt plus 1filll
|
||||
Published by the Free Software Foundation @*
|
||||
51 Franklin Street, Fifth Floor@*
|
||||
Boston, MA 02110-1301, USA@*
|
||||
@sp 1
|
||||
@insertcopying
|
||||
@end titlepage
|
||||
@contents
|
||||
@page
|
||||
|
||||
@node Top
|
||||
@top Introduction
|
||||
|
||||
This manual describes how to use @command{gelna}, the GNU compiler for
|
||||
the Elna programming language. This manual is specifically about how to
|
||||
invoke @command{gelna}.
|
||||
|
||||
@menu
|
||||
* Copying:: The GNU General Public License.
|
||||
* GNU Free Documentation License::
|
||||
How you can share and copy this manual.
|
||||
* Invoking gelna:: How to run gelna.
|
||||
* Option Index:: Index of command line options.
|
||||
* Keyword Index:: Index of concepts.
|
||||
@end menu
|
||||
|
||||
|
||||
@include gpl_v3.texi
|
||||
|
||||
@include fdl.texi
|
||||
|
||||
|
||||
@node Invoking gelna
|
||||
@chapter Invoking gelna
|
||||
|
||||
@c man title gelna A GCC-based compiler for the Elna language
|
||||
|
||||
@ignore
|
||||
@c man begin SYNOPSIS gelna
|
||||
gelna [@option{-c}|@option{-S}]
|
||||
[@option{-g}] [@option{-pg}]
|
||||
[@option{-o} @var{outfile}] @var{infile}@dots{}
|
||||
|
||||
Only the most useful options are listed here; see below for the
|
||||
remainder.
|
||||
@c man end
|
||||
@c man begin SEEALSO
|
||||
gpl(7), gfdl(7), fsf-funding(7), gcc(1)
|
||||
and the Info entries for @file{gelna} and @file{gcc}.
|
||||
@c man end
|
||||
@end ignore
|
||||
|
||||
@c man begin DESCRIPTION gelna
|
||||
|
||||
The @command{gelna} command is a frontend to @command{gcc} and
|
||||
supports many of the same options. @xref{Option Summary, , Option
|
||||
Summary, gcc, Using the GNU Compiler Collection (GCC)}. This manual
|
||||
only documents the options specific to @command{gelna}.
|
||||
|
||||
@c man end
|
||||
|
||||
@c man begin OPTIONS gelna
|
||||
|
||||
@c man end
|
||||
|
||||
@node Option Index
|
||||
@unnumbered Option Index
|
||||
|
||||
@command{gelna}'s command line options are indexed here without any
|
||||
initial @samp{-} or @samp{--}. Where an option has both positive and
|
||||
negative forms (such as -foption and -fno-option), relevant entries in
|
||||
the manual are indexed under the most appropriate form; it may sometimes
|
||||
be useful to look up both forms.
|
||||
|
||||
@printindex op
|
||||
|
||||
@node Keyword Index
|
||||
@unnumbered Keyword Index
|
||||
|
||||
@printindex cp
|
||||
|
||||
@bye
|
||||
28
gcc/lang-specs.h
Normal file
28
gcc/lang-specs.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/* GCC driver specs for Elna frontend.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* gcc/gcc.cc */
|
||||
{".elna", "@elna", nullptr, 0, 0},
|
||||
{"@elna",
|
||||
"elna1 %i \
|
||||
%{!Q:-quiet} " DUMPS_OPTIONS("") " %{m*} %{aux-info*} \
|
||||
%{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs} \
|
||||
%{pg:-p} %{p} %{f*} %{undef} \
|
||||
%{!fsyntax-only:%{S:%W{o*}%{!o*:-o %w%b.s}}} \
|
||||
%{fsyntax-only:-o %j} %{-param*} \
|
||||
%{!fsyntax-only:%(invoke_as)}",
|
||||
nullptr, 0, 0},
|
||||
23
gcc/lang.opt
Normal file
23
gcc/lang.opt
Normal file
@@ -0,0 +1,23 @@
|
||||
; lang.opt -- Options for the Elna front end.
|
||||
; Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
;
|
||||
; GCC is free software; you can redistribute it and/or modify it under
|
||||
; the terms of the GNU General Public License as published by the Free
|
||||
; Software Foundation; either version 3, or (at your option) any later
|
||||
; version.
|
||||
;
|
||||
; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
; WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
; for more details.
|
||||
;
|
||||
; You should have received a copy of the GNU General Public License
|
||||
; along with GCC; see the file COPYING3. If not see
|
||||
; <http://www.gnu.org/licenses/>.
|
||||
|
||||
; See the GCC internals manual for a description of this file's format.
|
||||
|
||||
; Please try to keep this file in ASCII collating order.
|
||||
|
||||
Language
|
||||
Elna
|
||||
2
gcc/lang.opt.urls
Normal file
2
gcc/lang.opt.urls
Normal file
@@ -0,0 +1,2 @@
|
||||
; Autogenerated by regenerate-opt-urls.py from gcc/lang.opt and generated HTML
|
||||
|
||||
Reference in New Issue
Block a user