Commit 6cfea11b by Tim Josling Committed by Tim Josling

Added new sample language treelang.

From-SVN: r53169
parent 6d030676
# Copyright (C) 1988, 90, 91, 92, 95, 96, 1997, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# Having this file here magically tells dejagnu that the treelang
# directory is worthy of testing
2002-04-13 Tim Josling <tej@melbpc.org.au>
* treetree.c (tree_code_create_function_initial)
Remove duplicate call to layout_decl
2001-12-02 Tim Josling <tej@melbpc.org.au>
* Make-lang.in
Ensure directory is built during install (installdirs dependency)
* lex.l
Work around poisoned malloc (undef IN_GCC)
Remove fake definition of tree.
* parse.y
Work around poisoned malloc (undef IN_GCC)
* tree1.c
New front end interface.
(top level) New structure lang_hooks.
(tree_post_options) Remove.
errorcount now a macro so do not define it.
current_nesting_level => work_nesting_level due to clash.
* treelang.h
errorcount now a macro so do not reference it.
* treetree.c
Replace NULL_PTR by NULL.
(tree_code_get_expression) Mark op3 unused.
Do not init builtins.
2001-06-11 Tim Josling <tej@melbpc.org.au>
* treelang.exp (global) remove COBOL specific code.
2001-05-24 Tim Josling <tej@melbpc.org.au>
Created this directory and its tests. All derived from the cobol
test swamp which was also all written by me.
# Copyright (C) 2001, 2002 Free Software Foundation, Inc.
all:
clean:
-rm -f *.o *.diff *~ *.bad core *.x
distclean: clean
-rm -f Makefile config.status
/* Driver for treelang test pgm */
int add(int, int);
int subtract(int, int);
int first_nonzero(int, int);
int
main (int argc, char *argv[])
{
printf("2:%d\n", add(1,1));
printf("7:%d\n", add(3,4));
printf("-1:%d\n", subtract(3,4));
printf("1:%d\n", subtract(2,1));
printf("3:%d\n", first_nonzero(0,3));
printf("0:%d\n", first_nonzero(0,0));
printf("1:%d\n", first_nonzero(1,0));
printf("15:%d\n", double_plus_one(7));
return 0;
}
// -*- c -*- c mode in emacs
external_definition int add(int arg1, int arg2);
external_definition int subtract(int arg3, int arg4);
external_definition int first_nonzero(int arg5, int arg6);
external_definition int double_plus_one(int arg7);
add
{
return arg1 + arg2;
}
subtract
{
return arg3 - arg4;
}
double_plus_one
{
automatic int aaa;
aaa=add(arg7, arg7);
aaa=add(aaa, aaa);
aaa=subtract(subtract(aaa, arg7), arg7) + 1;
return aaa;
}
first_nonzero
{
if (arg5)
{
return arg5;
}
else
{
}
return arg6;
}
2:2
7:7
-1:-1
1:1
3:3
0:0
1:1
15:15
# Tests for treelang; run from gcc/treelang/Make-lang.in => gcc/Makefile
# Copyright (C) 1999, 2000, 2001, 2002 by The Free Software Foundation
# find ttt for the actual tests
# Check the pgm is even there and set up the basics
proc init_utility {pgm} {
global transform
global pgm_actual
global pgm_base
global fix_progname
global path
# maybe add "X" to front of fail to say it is an expected failure
global X
set pgm_base ${pgm}
set pgm_actual ${pgm}
if { ${transform} != "s,x,x,"} {
verbose "1. program name was ${pgm}" 2
set sed_rc [catch {eval exec sed -e "${transform}" <<${pgm} } catch_res]
if { ${sed_rc} != "0" } {
verbose "2. Program name transform failed rc=${sed_rc} stat=${catch_res}" 1
${X}fail "${pgm} sed"
return 0
}
set pgm_actual ${catch_res}
verbose "3. program name after transformation is ${pgm_actual}" 2
}
set which_rc [catch {exec which ${pgm_actual}} stat]
if { ${which_rc} != "0" } {
verbose "4. ${pgm_base} cannot be found rc=${which_rc} stat=${stat}" 1
${X}fail "${pgm} = ${pgm_actual} not found in path (${path})"
return 0
}
set fix_progname "s,${pgm_actual},${pgm_base},"
verbose "5. fix program name value = ${fix_progname}" 4
return 1
}
#run pgm, option to remove file names from outputs
proc run3 {srcdd testdd parms group_nbr item_nbr nonzero_RC_expected check_file sanitize_output tree1 pipe} {
global transform
global pgm_actual
global pgm_base
global fix_progname
global X
global extras
set error_msg 0
set basefile "a${group_nbr}${pgm_base}.out${item_nbr}"
set infile ""
set outfile ""
set suffix ""
set temp_extras "-O3 "
set real_pgm_actual ${pgm_actual}
if {${tree1} > 0} {
if {"${pgm_actual}" == "gcc"} {
set real_pgm_actual "xgcc"
set temp_extras "${extras}"
}
set infile "${srcdd}/a${group_nbr}${pgm_base}i${item_nbr}.tree"
set mainfile "${srcdd}/a${group_nbr}${pgm_base}i${item_nbr}.c"
set outfile "-o ${testdd}/a${group_nbr}${pgm_base}o${item_nbr}${suffix}"
}
verbose "6. exec ${real_pgm_actual} ${temp_extras} ${parms} ${mainfile} ${infile} ${outfile} >${testdd}/${basefile} 2>${testdd}/${basefile}err" 2
set run_rc [catch {eval exec ${real_pgm_actual} ${temp_extras} ${parms} ${mainfile} ${infile} ${outfile} >${testdd}/${basefile} 2>${testdd}/${basefile}err} catch_res]
if {${run_rc} == 1} {
if {${nonzero_RC_expected} == 0} {
verbose "7. ${real_pgm_actual} ${group_nbr} ${item_nbr} failed due to rc=${run_rc} status=${catch_res}" 1
${X}fail "${pgm_base} ${group_nbr} ${item_nbr} rc!=0"
return
}
} else {
if {${nonzero_RC_expected} == 1} {
verbose "8. ${pgm_actual} ${group_nbr} ${item_nbr} failed - did not produce nonzero return code as expected rc=${run_rc} status=${catch_res}" 1
${X}fail "${pgm_base} ${group_nbr} ${item_nbr} rc=0"
return
}
}
# change the filenames to (file) in output if needed to allow testing
set checkfile1 "${srcdd}/${basefile}"
set checkfile2 "${testdd}/${basefile}"
if {${sanitize_output} != 0} {
set oldcheckfile1 "${checkfile1}"
set oldcheckfile2 "${checkfile2}"
set checkfile1 "${testdd}/${basefile}.test.nofilename"
set checkfile2 "${testdd}/${basefile}.run.nofilename"
set run_rc [catch {eval exec sed -f ${srcdd}/filefix.sed <${oldcheckfile1} >${checkfile1}} catch_res]
if {${run_rc} == 1} {
verbose "9. sed to cleanup filenames (std 1) in pgm output failed due to rc=${run_rc} status=${catch_res}" 1
if {${error_msg} == 0} {
set error_msg "9. sed to cleanup filenames (std 1) in pgm output failed due to rc=${run_rc} status=${catch_res}"
}
}
set run_rc [catch {eval exec sed -f ${srcdd}/filefix.sed <${oldcheckfile2} | sed -e "${fix_progname}" >${checkfile2}} catch_res]
if {${run_rc} == 1} {
verbose "10. sed to cleanup filenames (std 2) in pgm output failed due to rc=${run_rc} status=${catch_res}" 1
if {${error_msg} == 0} {
set error_msg "10. sed to cleanup filenames (std 2) in pgm output failed due to rc=${run_rc} status=${catch_res}"
}
}
}
set diff [diff ${checkfile1} ${checkfile2}]
if {${diff} != 1} {
verbose "11. ${pgm_actual} ${group_nbr} ${item_nbr} diff stdout failed rc=${diff}" 1
if {${error_msg} == 0} {
set error_msg "11. ${pgm_actual} ${group_nbr} ${item_nbr} diff stdout failed rc=${diff}"
}
}
set checkfile1 "${srcdd}/${basefile}err"
set checkfile2 "${testdd}/${basefile}err"
if {${sanitize_output} != 0} {
set oldcheckfile1 "${checkfile1}"
set oldcheckfile2 "${checkfile2}"
set checkfile1 "${testdd}/${basefile}err.test.nofilename"
set checkfile2 "${testdd}/${basefile}err.run.nofilename"
set run_rc [catch {eval exec sed -f ${srcdd}/filefix.sed <${oldcheckfile1} >${checkfile1}} catch_res]
if {${run_rc} == 1} {
verbose "12. sed to cleanup filenames (err 1) in pgm output failed due to rc=${run_rc} status=${catch_res}" 1
if {${error_msg} == 0} {
set error_msg "12. sed to cleanup filenames (err 1) in pgm output failed due to rc=${run_rc} status=${catch_res}"
}
}
set run_rc [catch {eval exec sed -f ${srcdd}/filefix.sed <${oldcheckfile2} | sed -e "${fix_progname}" >${checkfile2}} catch_res]
if {${run_rc} == 1} {
verbose "13. sed to cleanup filenames (err 2) in pgm output failed due to rc=${run_rc} status=${catch_res}" 1
if {${error_msg} == 0} {
set error_msg "13. sed to cleanup filenames (err 2) in pgm output failed due to rc=${run_rc} status=${catch_res}"
}
}
}
set diff [diff ${checkfile1} ${checkfile2}]
if {${diff} != 1} {
verbose "14. ${pgm_actual} ${group_nbr} ${item_nbr} diff stderr failed rc=${diff}" 1
if {${error_msg} == 0} {
set error_msg "14. ${pgm_actual} ${group_nbr} ${item_nbr} diff stderr failed rc=${diff}"
}
}
if {${check_file} >0} {
if {${tree1} == 0} {
set checkfile1 "${srcdd}/${basefile}file"
set checkfile2 "${testdd}/${basefile}file"
if {${sanitize_output} != 0} {
set oldcheckfile1 "${checkfile1}"
set oldcheckfile2 "${checkfile2}"
set checkfile1 "${testdd}/${basefile}file.test.nofilename"
set checkfile2 "${testdd}/${basefile}file.run.nofilename"
set run_rc [catch {eval exec sed -f ${srcdd}/filefix.sed <${oldcheckfile1} >${checkfile1}} catch_res]
if {${run_rc} == 1} {
verbose "15. sed to cleanup filenames (err 1) in pgm stdout failed due to rc=${run_rc} status=${catch_res}" 1
if {${error_msg} == 0} {
set error_msg "15. sed to cleanup filenames (err 1) in pgm stdout failed due to rc=${run_rc} status=${catch_res}"
}
}
set run_rc [catch {eval exec sed -f ${srcdd}/filefix.sed <${oldcheckfile2} | sed -e "${fix_progname}" >${checkfile2}} catch_res]
if {${run_rc} == 1} {
verbose "16. sed to cleanup filenames (err 2) in pgm stdout failed due to rc=${run_rc} status=${catch_res}" 1
if {${error_msg} == 0} {
set error_msg "16. sed to cleanup filenames (err 2) in pgm stdout failed due to rc=${run_rc} status=${catch_res}"
}
}
}
set diff [diff ${checkfile1} ${checkfile2}]
if {${diff} != 1} {
verbose "17. ${pgm_actual} ${group_nbr} ${item_nbr} diff stdout file failed rc=${diff}" 1
if {${error_msg} == 0} {
set error_msg "17. ${pgm_actual} ${group_nbr} ${item_nbr} diff stdout file failed rc=${diff}"
}
}
}
}
if {${check_file} >1} {
if {${tree1} == 0} {
set checkfile1 "${srcdd}/${outfile}"
set checkfile2 "${testdd}/${outfile}"
if {${sanitize_output} != 0} {
set oldcheckfile1 "${checkfile1}"
set oldcheckfile2 "${checkfile2}"
set checkfile1 "${testdd}/${basefile}out.test.nofilename"
set checkfile2 "${testdd}/${basefile}out.run.nofilename"
set run_rc [catch {eval exec sed -f ${srcdd}/filefix.sed <${oldcheckfile1} >${checkfile1}} catch_res]
if {${run_rc} == 1} {
verbose "18. sed to cleanup filenames (err 1) in pgm output failed due to rc=${run_rc} status=${catch_res}" 1
if {${error_msg} == 0} {
set error_msg "18. sed to cleanup filenames (err 1) in pgm output failed due to rc=${run_rc} status=${catch_res}"
}
}
set run_rc [catch {eval exec sed -f ${srcdd}/filefix.sed <${oldcheckfile2} | sed -e "${fix_progname}" >${checkfile2}} catch_res]
if {${run_rc} == 1} {
verbose "19. sed to cleanup filenames (err 2) in pgm output failed due to rc=${run_rc} status=${catch_res}" 1
if {${error_msg} == 0} {
set error_msg "19. sed to cleanup filenames (err 2) in pgm output failed due to rc=${run_rc} status=${catch_res}"
}
}
}
set diff [diff ${checkfile1} ${checkfile2}]
if {${diff} != 1} {
verbose "20. ${pgm_actual} ${group_nbr} ${item_nbr} diff output file failed rc=${diff}" 1
if {${error_msg} == 0} {
set error_msg "20. ${pgm_actual} ${group_nbr} ${item_nbr} diff output file failed rc=${diff}"
}
}
}
}
if {${check_file} >2} {
set outfile "a${group_nbr}${pgm_base}o${item_nbr}${suffix}"
set pgmrun "${testdd}/a${group_nbr}${pgm_base}o${item_nbr}${suffix}"
set checkfile1 "${srcdd}/${outfile}runpgm"
set checkfile2 "${testdd}/${outfile}runpgm"
verbose "21. exec ${pgmrun} >${checkfile2} 2>${checkfile2}err" 2
set run_rc [catch {eval exec ${pgmrun} >${checkfile2} 2>${checkfile2}err} catch_res]
if {${run_rc} == 1} {
if {${nonzero_RC_expected} == 0} {
verbose "22. ${pgm_actual} ${group_nbr} ${item_nbr} failed due to rc=${run_rc} status=${catch_res}" 1
${X}fail "${pgm_base} ${group_nbr} ${item_nbr} run"
return
}
} else {
if {${nonzero_RC_expected} == 1} {
verbose "23. ${pgm_actual} ${group_nbr} ${item_nbr} failed - did not produce nonzero return code as expected rc=${run_rc} status=${catch_res}" 1
${X}fail "${pgm_base} ${group_nbr} ${item_nbr} run"
return
}
}
set diff [diff ${checkfile1} ${checkfile2}]
if {${diff} != 1} {
verbose "24. ${pgm_actual} ${group_nbr} ${item_nbr} diff run output file failed rc=${diff}" 1
if {${error_msg} == 0} {
set error_msg "24. ${pgm_actual} ${group_nbr} ${item_nbr} diff run output file failed rc=${diff}"
}
}
set diff [diff ${checkfile1}err ${checkfile2}err]
if {${diff} != 1} {
verbose "25. ${pgm_actual} ${group_nbr} ${item_nbr} diff run stderr file failed rc=${diff}" 1
if {${error_msg} == 0} {
set error_msg "25. ${pgm_actual} ${group_nbr} ${item_nbr} diff run stderr file failed rc=${diff}"
}
}
}
if {${error_msg}>0} {
${X}fail "${pgm_base} ${group_nbr} ${item_nbr} fail code=${error_msg}"
} else {
pass "${pgm_base} ${group_nbr} ${item_nbr}"
}
return
}
set extras "$env(gcc_extras)"
set path $env(PATH)
set transform $env(TRANSFORM)
set srcdir $env(srcdir)
verbose "source directory ${srcdir}\n" 2
verbose "transform ${transform}\n" 2
set sourcedir "${srcdir}/testsuite/treelang"
set testdir "treelang"
set pgm_actual ""
# srcdd testdd parms group_nbr item_nbr nonzero_RC_expected check_file sanitize_output tree1
# ttt
#GCC - main C compiler tests via GCC
set X ""
set check_rc [init_utility "gcc"]
if {${check_rc} == 1} {
#
#set X "x"
set X ""
run3 "${sourcedir}" "${testdir}" " -g -O3 " 01 01 0 3 0 1 0
set X ""
}
2002-05-05 Tim Josling <tej@melbpc.org.au>
* Updated for gcc3.2 experimental. Major changes throughout.
2002-03-31 Tim Josling <tej@melbpc.org.au>
* Make-lang.in: Changes so build and check work more reliably
2001-07-30 Tim Josling <tej@melbpc.org.au>
* root.texi: remove
* treelang.texi: updates based on feedback
2001-06-11 Tim Josling <tej@melbpc.org.au>
* all (all) Revamp code to conform to GCC coding standards, fix
typos in texi files.
2001-05-11 Tim Josling <tej@melbpc.org.au>
Create the new language.
# Top level makefile fragment for TREELANG For GCC. -*- makefile -*-
# Copyright (C) 1994, 1995, 1997, 1998, 1999 2000, 2001, 2002 Free
# Software Foundation, Inc.
#This file is part of GCC.
#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 2, 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 COPYING. If not, write to
#the Free Software Foundation, 59 Temple Place - Suite 330,
#Boston, MA 02111-1307, USA.
# This file provides the language dependent support in the main Makefile.
# Each language makefile fragment must provide the following targets:
#
# foo.all.build, foo.all.cross, foo.start.encap, foo.rest.encap,
# foo.info, foo.dvi,
# foo.install-normal, foo.install-common, foo.install-info, foo.install-man,
# foo.uninstall, foo.distdir,
# foo.mostlyclean, foo.clean, foo.distclean, foo.extraclean,
# foo.maintainer-clean, foo.stage1, foo.stage2, foo.stage3, foo.stage4
#
# where `foo' is the name of the language.
#
# It should also provide rules for:
#
# - making any compiler driver (eg: GCC)
# - the compiler proper (eg: treelang)
# - define the names for selecting the language in LANGUAGES.
#
## note program-prefix and program-suffix options are not supported
## just program_transform_name which is a sed script to transform the
## names
TREELANGSED = sed
TREELANGSEDFLAGS = -n
# back end compiler libraries etc
TREE_BE_LIBS = $(BACKEND) $(LIBIBERTY) $(INTLLIBS) $(LIBS) $(LIBDEPS)
GCC_EXTRAS = -B./ -B$(build_tooldir)/bin/ -isystem $(build_tooldir)/include
# ./xgcc is the just built compiler. See GCC_FOR_TARGET in the GCC Makefile.in.
# If this can't be found, you probably have not done a bootstrap of GCC,
# which you need to do.
# GCC_FOR_TREELANG = ./xgcc $(GCC_EXTRAS)
TREE_GENERATED = $(srcdir)/treelang/lex.c $(srcdir)/treelang/parse.c\
$(srcdir)/treelang/parse.h $(srcdir)/treelang/parse.output $(srcdir)/treelang/TAGS
TREE_SOURCE = ${srcdir}/treelang/parse.y ${srcdir}/treelang/lex.l ${srcdir}/treelang/tree1.c ${srcdir}/treelang/treelang.h ${srcdir}/treelang/treetree.c $(srcdir)/treelang/treetree.h
TREE_EXES = tree1$(exeext)
#no -Wtraditional warnings, allow long long
treelang-warn = $(LOOSE_WARN) -pedantic -Wno-long-long -Wmissing-prototypes -Wmissing-declarations
#
# Define the names for selecting treelang in LANGUAGES.
.phony: treelang TREELANG
treelang TREELANG:treelang.done
treelang.done: tree1$(exeext)
$(STAMP) treelang.done
# no preprocessor
# core compiler
tree1$(exeext): treelang/tree1.o treelang/treetree.o treelang/lex.o treelang/parse.o\
$(TREE_BE_LIBS) c-convert.o c-typeck.o c-common.o c-decl.o attribs.o
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ \
treelang/tree1.o treelang/treetree.o treelang/lex.o treelang/parse.o c-convert.o\
c-typeck.o c-common.o c-decl.o attribs.o $(TREE_BE_LIBS)
#
# Compiling object files from source files.
# object file makes
treelang/tree1.o: $(srcdir)/treelang/tree1.c $(srcdir)/treelang/treelang.h $(srcdir)/treelang/parse.h
$(CC) -o $@ -c $(ALL_CFLAGS) $(INCLUDES) $<
treelang/treetree.o: $(srcdir)/treelang/treetree.c $(srcdir)/treelang/treetree.h
$(CC) -o $@ -c $(ALL_CFLAGS) $(INCLUDES) $<
treelang/parse.o: $(srcdir)/treelang/parse.c $(srcdir)/treelang/treelang.h $(srcdir)/treelang/treetree.h
$(CC) -o $@ -c $(ALL_CFLAGS) $(INCLUDES) $<
treelang/lex.o: $(srcdir)/treelang/lex.c $(srcdir)/treelang/parse.h $(srcdir)/treelang/treelang.h
$(CC) -o $@ -c $(ALL_CFLAGS) $(INCLUDES) $<
# generated files the files from lex and yacc are put into the source
# directory in case someone wants to build but does not have
# lex/yacc
$(srcdir)/treelang/lex.c: $(srcdir)/treelang/lex.l
$(LEX) $(LEXFLAGS) -o$(srcdir)/treelang/lex.c $(srcdir)/treelang/lex.l
$(srcdir)/treelang/parse.c $(srcdir)/treelang/parse.h: $(srcdir)/treelang/parse.y
$(BISON) $(BISONFLAGS) -v $(srcdir)/treelang/parse.y\
--output=$(srcdir)/treelang/parse.c --defines
# -v
#
# Build hooks:
treelang.all.build: treelang
treelang.all.cross:
_error_not_here_yet - havent even thought about it - it may even work
treelang.start.encap:
treelang.rest.encap:
.phony:treelang.info
treelang.info: $(srcdir)/treelang/treelang.info
$(srcdir)/treelang/treelang.info: $(srcdir)/treelang/treelang.texi
cd $(srcdir)/treelang && $(MAKEINFO) $(MAKEINFOFLAGS) -I../doc/include \
-o $(srcdir)/treelang/treelang.info $(srcdir)/treelang/treelang.texi
treelang.dvi: $(srcdir)/treelang/treelang.texi
TEXINPUTS=$(srcdir)/treelang:$(srcdir):$$TEXINPUTS $(TEXI2DVI) $(srcdir)/treelang/treelang.texi; \
texindex treelang.??; \
TEXINPUTS=$(srcdir)/treelang:$(srcdir):$$TEXINPUTS $(TEXI2DVI) $(srcdir)/treelang/treelang.texi; \
mv treelang.dvi treelang;
#
# Install hooks:
# Nothing to do here.
treelang.install-normal: treelang.install.common
# Install
.phony:treelang.install.common
.phony:treelang.install
treelang.install treelang.install.common treelang.install-common: treelang.install.common.done
treelang.install.common.done: installdirs treelang.done
for name in $(TREE_EXES); \
do \
if [ -f $$name ] ; then \
name2="`echo \`basename $$name\` | sed -e '$(program_transform_name)' `"; \
rm -f $(bindir)/$$name2$(exeext); \
$(INSTALL_PROGRAM) $$name$(exeext) $(bindir)/$$name2$(exeext); \
chmod a+x $(bindir)/$$name2$(exeext); \
fi ; \
done
$(STAMP) treelang.install.common.done
treelang.install-info: $(srcdir)/treelang/treelang.info
for name in $(srcdir)/treelang/treelang.info; \
do \
if [ -f $$name ] ; then \
name2="`echo \`basename $$name\` | sed -e '$(program_transform_name)' `"; \
rm -f $(libsubdir)/$$name2$(exeext); \
$(INSTALL_PROGRAM) $$name$(exeext) $(libsubdir)/$$name2$(exeext); \
chmod a+x $(libsubdir)/$$name2$(exeext); \
fi ; \
done
treelang.install-man:
treelang.uninstall:
for name in $(TREE_EXES); \
do \
echo $$name; \
name2="`echo $$name | sed -e '$(program_transform_name)' `"; \
echo becomes $$name2; \
echo -rm -rf $(bindir)/$$name2$(exeext); \
rm -rf $(bindir)/$$name2$(exeext); \
done
-rm treelang.install.common.done
#
# Clean hooks:
# A lot of the ancillary files are deleted by the main makefile.
# We just have to delete files specific to us.
treelang.mostlyclean:
for name in $(TREE_EXES); \
do \
echo deleting $$name; \
if [ -f treelang/$$name$(exeext) ] ; then \
rm -f treelang/$$name$(exeext); \
fi ; \
done
-rm -f treelang/*.o
-rm treelang.done
treelang.clean: treelang.mostlyclean
treelang.distclean: treelang.clean
-rm -f treelang/config.status
-rm -f treelang/*.output
treelang.extraclean: treelang.distclean
treelang.maintainer-clean: treelang.extraclean
for name in $(TREE_GENERATED); \
do \
if [ -f $(srcdir)/treelang/$$name ] ; then \
echo deleting $(srcdir)/treelang/$$name; \
rm -f $(srcdir)/treelang/$$name; \
fi ; \
done
-rm -R $(srcdir)/treelang/*~
#
# Stage hooks:
# The main makefile has already created stage?/treelang.
treelang.stage1: stage1-start
-mv treelang/*$(objext) stage1/treelang
treelang.stage2: stage2-start
-mv treelang/*$(objext) stage2/treelang
treelang.stage3: stage3-start
-mv treelang/*$(objext) stage3/treelang
treelang.stage4: stage4-start
-mv treelang/*$(objext) stage4/treelang
#
# Maintenance hooks:
# This target creates the files that can be rebuilt, but go in the
# distribution anyway. It then copies the files to the distdir directory.
treelang.distdir:
# not here yet sorry not sure if this is needed or not???
# test hook
# the other languages are hard coded in the main makefile.in - that seems to be wrong
check: treelang.check
TESTSUITEDIR = testsuite
treelang.check: $(TESTSUITEDIR)/site.exp
-mkdir testsuite/treelang
# these three files are empty and it seems diff has trouble generating
# patch files for new empty files as required for cvs.
# STAMP does not cut it here as I need an empty file.
touch $(srcdir)/testsuite/treelang/{a01gcco01runpgmerr,a01gcc.out01,a01gcc.out01err}
-rootme=`pwd`; export rootme; \
srcdir=`cd ${srcdir}; pwd` ; export srcdir ; \
cd testsuite; \
EXPECT=${EXPECT} ; export EXPECT ; \
TRANSFORM=$(program_transform_name); export TRANSFORM; \
if [ -f $${rootme}/../expect/expect ] ; then \
TCL_LIBRARY=`cd .. ; cd ${srcdir}/../tcl/library ; pwd` ; \
export TCL_LIBRARY ; fi ; \
PATH=`cd ..;pwd`:$$PATH; export PATH; \
gcc_extras="-B`cd ..;pwd` -B`cd ..;pwd`/treelang"; export gcc_extras; \
$(RUNTEST) --tool treelang $(RUNTESTFLAGS)
rm $(srcdir)/testsuite/treelang/{a01gcco01runpgmerr,a01gcc.out01,a01gcc.out01err}
# GCC_EXTRAS="$(GCC_EXTRAS)"; export GCC_EXTRAS; \
# copy the output files from the current test to source ie say the new results are OK
treelang.check.fix: force
srcdir=`cd ${srcdir}; pwd` ; export srcdir ;
-cp testsuite/treelang/*.out* t
-cp testsuite/treelang/*runpgm* t
-rm -f t/*nofilename
treelang.wc: force
wc ${TREE_SOURCE}
#
# Update the tags table for emacs find label (alt-.) function
TAGS: treelang.tags
.PHONY: treelang.tags
treelang.tags:
cd $(srcdir)/treelang; \
etags -l c ${TREE_SOURCE}
.PHONY: treelang.html
treelang.html:
cd $(srcdir)/treelang && texi2html -I ../doc/include -verbose -menu -split_chapter -number treelang.texi
# mv treelang*.html $(srcdir)/treelang
This is a sample language front end for GCC.
This is a replacement for 'toy' which had potential copyright issues,
but more importantly it did not exercise very much of GCC. The intent
of this language is that it should provide a cookbook of language
elements that you can use in any language front end.
To this end, treelang is essentially an implementation of a subset of
the GCC back end 'tree' interface in syntax.
Thanks to Richard Kenner, Joachim Nadler and many others for helping
me to understand enough of GCC to do this.
Tim Josling
May 2001
# Top level configure fragment for GNU C++.
# Copyright (C) 1994, 1995, 1997, 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
#This file is part of GCC.
#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 2, 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 COPYING. If not, write to
#the Free Software Foundation, 59 Temple Place - Suite 330,
#Boston, MA 02111-1307, USA.
# 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)
# compilers - value to add to $(COMPILERS)
# stagestuff - files to add to $(STAGESTUFF)
# diff_excludes - files to ignore when building diffs between two versions.
language="treelang"
compilers="tree1\$(exeext)"
stagestuff=
diff_excludes="-x lex.c -x parse.c -x parse.h"
headers=
build_by_default="no"
/* Definitions for switches for TREELANG.
Copyright (C) 1995, 96-98, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of GCC.
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 2, 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 this program; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
DEFINE_LANG_NAME ("treelang")
/* This is the contribution to the `lang_options' array in gcc.c for
treelang. */
{"-fparser-trace", N_("(debug) trace parsing process")},
{"-flexer-trace", N_("(debug) trace lexical analysis")},
/* Definitions for specs for TREELANG
The format of the specs file is documented in gcc.c
Copyright (C) 1995, 96-98, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of GCC.
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 2, 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 this program; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/*
This is the contribution to the `default_compilers' array in GCC.c for
treelang.
This file must compile with 'traditional', so no ANSI string concatenations
*/
{".tree", "@treelang", NULL},
{".TREE", "@treelang", NULL},
{".tre", "@treelang", NULL},
{".TRE", "@treelang", NULL},
{"@treelang",
"tree1\
%{!Q:-quiet}\
%{d*}\
%{m*}\
%{a}\
%{g*}\
%{O*}\
%{W*}\
%{w}\
%{ansi}\
%{v}\
%{--help:--help}\
%{pg:-p}\
%{p}\
%{f*}\
%{pg|p:%{fomit-frame-pointer:%e-pg or -p and -fomit-frame-pointer are incompatible}}\
%{S:%W{o*}%{!o*:-o %b.s}}\
%{!S:-o %g.s}\
%i\n\
%{!S:as %a\
%Y\
%{c:%W{o*}%{!o*:-o %w%b%O}}\
%{!c:-o %d%w%u%O}\
%g.s\
%A\n}\
", NULL
},
%{ /* -*- c -*- = mode for emacs editor
/*
TREELANG lexical analysis
---------------------------------------------------------------------
Copyright (C) 1986, 87, 89, 92-96, 1997, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This program 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 2, or (at your option) any
later version.
This program 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 this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding!
---------------------------------------------------------------------
Written by Tim Josling 1999-2001, based in part on other parts of
the GCC compiler.
*/
/* Avoid poisoned malloc problem. */
#undef IN_GCC
#if 0
/* tree is defined as void* here to avoid any knowledge of tree stuff in this file. */
typedef void *tree;
#endif
#include <stdio.h>
#if 0
#include <ctype.h>
#endif
#include <memory.h>
#include "ansidecl.h"
#include "config.h"
#include "system.h"
#include "diagnostic.h"
/* Token defs. */
#include "treelang.h"
#include "parse.h"
extern int option_lexer_trace;
int yylex (void);
void update_yylval (int a);
static int next_tree_lineno=1;
static int next_tree_charno=1;
static void update_lineno_charno (void);
static void dump_lex_value (int lexret);
#define SAVE_RETURN(a) {update_yylval (a); if (option_lexer_trace)\
{fprintf (stderr, "\nlexer returning"); dump_lex_value (a);} return a;}
#define NOT_RETURN(a) {update_yylval (a); if (option_lexer_trace)\
{fprintf (stderr, "\nlexer swallowing"); dump_lex_value (a);}}
%}
%option nostack
%option nounput
%option noyywrap
%option pointer
%option nodefault
%%
{
yylval = my_malloc (sizeof (struct token));
((struct token*)yylval)->lineno = next_tree_lineno;
((struct token*)yylval)->charno = next_tree_charno;
}
[ \n]+ {
update_lineno_charno ();
NOT_RETURN (WHITESPACE);
}
"//".* {
/* Comment. */
update_lineno_charno ();
NOT_RETURN (COMMENT);
}
"{" {
update_lineno_charno ();
SAVE_RETURN (LEFT_BRACE);
}
"}" {
update_lineno_charno ();
SAVE_RETURN (RIGHT_BRACE);
}
"(" {
update_lineno_charno ();
SAVE_RETURN (LEFT_PARENTHESIS);
}
")" {
update_lineno_charno ();
SAVE_RETURN (RIGHT_PARENTHESIS);
}
"," {
update_lineno_charno ();
SAVE_RETURN (COMMA);
}
";" {
update_lineno_charno ();
SAVE_RETURN (SEMICOLON);
}
"+" {
update_lineno_charno ();
SAVE_RETURN (PLUS);
}
"-" {
update_lineno_charno ();
SAVE_RETURN (MINUS);
}
"=" {
update_lineno_charno ();
SAVE_RETURN (ASSIGN);
}
"==" {
update_lineno_charno ();
SAVE_RETURN (EQUALS);
}
[+-]?[0-9]+ {
update_lineno_charno ();
SAVE_RETURN (INTEGER);
}
"external_reference" {
update_lineno_charno ();
SAVE_RETURN (EXTERNAL_REFERENCE);
}
"external_definition" {
update_lineno_charno ();
SAVE_RETURN (EXTERNAL_DEFINITION);
}
"static" {
update_lineno_charno ();
SAVE_RETURN (STATIC);
}
"automatic" {
update_lineno_charno ();
SAVE_RETURN (STATIC);
}
"int" {
update_lineno_charno ();
SAVE_RETURN (INT);
}
"char" {
update_lineno_charno ();
SAVE_RETURN (CHAR);
}
"void" {
update_lineno_charno ();
SAVE_RETURN (VOID);
}
"unsigned" {
update_lineno_charno ();
SAVE_RETURN (UNSIGNED);
}
"return" {
update_lineno_charno ();
SAVE_RETURN (RETURN);
}
"if" {
update_lineno_charno ();
SAVE_RETURN (IF);
}
"else" {
update_lineno_charno ();
SAVE_RETURN (ELSE);
}
[A-Za-z_]+[A-Za-z_0-9]* {
update_lineno_charno ();
update_yylval (NAME);
if (option_lexer_trace)
{
fprintf (stderr, "\nlexer returning");
dump_lex_value (NAME);
}
return NAME;
}
[^\n] {
update_lineno_charno ();
fprintf (stderr, "%s:%i:%i: Unrecognized character %c\n", in_fname,
((struct token*)yylval)->lineno,
((struct token*)yylval)->charno, yytext[0]);
errorcount++;
}
%%
/*
Update line number (1-) and character number (1-). Call this
before processing the token. */
static void
update_lineno_charno (void)
{
/* Update the values we send to caller in case we sometimes don't
tell them about all the 'tokens' eg comments etc. */
int yyl;
((struct token*)yylval)->lineno = next_tree_lineno;
((struct token*)yylval)->charno = next_tree_charno;
for ( yyl = 0; yyl < yyleng; ++yyl )
{
if ( yytext[yyl] == '\n' )
{
++next_tree_lineno;
next_tree_charno = 1;
}
else
next_tree_charno++;
}
}
/* Fill in the fields of yylval - the value of the token. The token
type is A. */
void
update_yylval (int a)
{
struct token* tok;
tok=yylval;
tok->category = token_category;
tok->type = a;
tok->length = yyleng;
/* Have to copy yytext as it is just a ptr into the buffer at the
moment. */
tok->chars = my_malloc (yyleng + 1);
memcpy (tok->chars, yytext, yyleng);
}
/* Trace the value LEXRET and the position and token details being
returned by the lexical analyser. */
static void
dump_lex_value (int lexret)
{
int ix;
fprintf (stderr, " %d l:%d c:%d ln:%d text=", lexret,
((struct token*) yylval)->lineno,
((struct token*) yylval)->charno,
((struct token*) yylval)->length);
for (ix = 0; ix < yyleng; ix++)
{
fprintf (stderr, "%c", yytext[ix]);
}
fprintf (stderr, " in hex:");
for (ix = 0; ix < yyleng; ix++)
{
fprintf (stderr, " %2.2x", yytext[ix]);
}
fprintf (stderr, "\n");
}
%{ /* -*- c -*- emacs mode c */
/*
TREELANG Compiler parser.
---------------------------------------------------------------------
Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This program 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 2, or (at your option) any
later version.
This program 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 this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding!
---------------------------------------------------------------------
Written by Tim Josling 1999-2001, based in part on other parts of
the GCC compiler.
*/
/*
Grammar Conflicts
*****************
There are no conflicts in this grammar. Please keep it that way.
*/
#undef IN_GCC
typedef void *tree;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ansidecl.h"
#include "config.h"
#include "system.h"
#include "diagnostic.h"
#include "treelang.h"
#include "treetree.h"
#define YYDEBUG 1
#define YYPRINT(file, type, value) print_token (file, type, value)
#define YYERROR_VERBOSE YES
extern int option_parser_trace;
/* Local prototypes. */
static void yyerror (const char *error_message);
int yylex (void);
int yyparse (void);
void print_token (FILE * file, unsigned int type ATTRIBUTE_UNUSED, YYSTYPE value);
static struct production *reverse_prod_list (struct production *old_first);
static void ensure_not_void (unsigned int type, struct token* name);
static int check_type_match (int type_num, struct production *exp);
static int get_common_type (struct production *type1, struct production *type2);
static struct production *make_integer_constant (struct token* value);
static void set_storage (struct production *prod);
/* File global variables. */
static struct production *current_function=NULL;
%}
/* Not %raw - seems to have bugs. */
%token_table
/* Punctuation. */
%token RIGHT_BRACE
%token LEFT_BRACE
%token RIGHT_SQUARE_BRACKET
%token LEFT_SQUARE_BRACKET
%token RIGHT_PARENTHESIS
%token LEFT_PARENTHESIS
%token SEMICOLON
%token ASTERISK
%token COMMA
%right EQUALS
%right ASSIGN
%left PLUS
%left MINUS
/* Literals. */
%token INTEGER
/* Keywords. */
%token IF
%token ELSE
%token RETURN
%token CHAR
%token INT
%token UNSIGNED
%token VOID
%token TYPEDEF
%token NAME
%token STATIC
%token AUTOMATIC
%token EXTERNAL_DEFINITION
%token EXTERNAL_REFERENCE
/* Tokens not passed to parser. */
%token WHITESPACE
%token COMMENT
/* Pseudo tokens - productions. */
%token PROD_VARIABLE_NAME
%token PROD_TYPE_NAME
%token PROD_FUNCTION_NAME
%token PROD_INTEGER_CONSTANT
%token PROD_PLUS_EXPRESSION
%token PROD_MINUS_EXPRESSION
%token PROD_ASSIGN_EXPRESSION
%token PROD_VARIABLE_REFERENCE_EXPRESSION
%token PROD_PARAMETER
%token PROD_FUNCTION_INVOCATION
%expect 0
%%
file:
/* Nil. */ {
/* Nothing to do. */
}
|declarations {
/* Nothing to do. */
}
;
declarations:
declaration {
/* Nothing to do. */
}
| declarations declaration {
/* Nothing to do. */
}
;
declaration:
variable_def {
/* Nothing to do. */
}
|function_prototype {
/* Nothing to do. */
}
|function {
/* Nothing to do. */
}
;
variable_def:
storage typename NAME init_opt SEMICOLON {
struct token* tok;
struct production *prod;
tok = $3;
prod = make_production (PROD_VARIABLE_NAME, tok);
SYMBOL_TABLE_NAME (prod) = tok;
EXPRESSION_TYPE (prod) = $2;
VAR_INIT (prod) = $4;
NUMERIC_TYPE (prod) = NUMERIC_TYPE (( (struct production*)EXPRESSION_TYPE (prod)));
ensure_not_void (NUMERIC_TYPE (prod), tok);
if (insert_tree_name (prod))
{
YYERROR;
}
STORAGE_CLASS_TOKEN (prod) = $1;
set_storage (prod);
if (VAR_INIT (prod))
{
if (! ((struct production*)VAR_INIT (prod))->code)
abort ();
if (STORAGE_CLASS (prod) == EXTERNAL_REFERENCE_STORAGE)
{
fprintf (stderr, "%s:%i:%i: External reference variables may not have initial value\n", in_fname,
tok->lineno, tok->charno);
print_token (stderr, 0, tok);
errorcount++;
YYERROR;
}
}
prod->code = tree_code_create_variable
(STORAGE_CLASS (prod),
((struct token*)SYMBOL_TABLE_NAME (prod))->chars,
((struct token*)SYMBOL_TABLE_NAME (prod))->length,
NUMERIC_TYPE (prod),
VAR_INIT (prod)? ((struct production*)VAR_INIT (prod))->code:NULL,
in_fname,
tok->lineno);
if (!prod->code)
abort ();
}
;
storage:
STATIC
|AUTOMATIC
|EXTERNAL_DEFINITION
|EXTERNAL_REFERENCE
;
parameter:
typename NAME {
struct token* tok;
struct production *prod;
struct production *prod2;
tok = $2;
prod = make_production (PROD_VARIABLE_NAME, tok);
SYMBOL_TABLE_NAME (prod) = $2;
EXPRESSION_TYPE (prod) = $1;
NUMERIC_TYPE (prod) = NUMERIC_TYPE (( (struct production*)EXPRESSION_TYPE (prod)));
ensure_not_void (NUMERIC_TYPE (prod), tok);
if (insert_tree_name (prod))
{
YYERROR;
}
prod2 = make_production (PROD_PARAMETER, tok);
VARIABLE (prod2) = prod;
$$ = prod2;
}
;
function_prototype:
storage typename NAME LEFT_PARENTHESIS parameters RIGHT_PARENTHESIS SEMICOLON {
struct token* tok;
struct production *prod;
struct production *type;
struct tree_parameter_list* first_parms;
struct tree_parameter_list* last_parms;
struct tree_parameter_list* this_parms;
struct production *this_parm;
struct production *this_parm_var;
tok = $3;
prod = make_production (PROD_FUNCTION_NAME, $3);
SYMBOL_TABLE_NAME (prod) = $3;
EXPRESSION_TYPE (prod) = $2;
NUMERIC_TYPE (prod) = NUMERIC_TYPE (( (struct production*)EXPRESSION_TYPE (prod)));
PARAMETERS (prod) = reverse_prod_list ($5);
insert_tree_name (prod);
STORAGE_CLASS_TOKEN (prod) = $1;
set_storage (prod);
switch (STORAGE_CLASS (prod))
{
case STATIC_STORAGE:
case EXTERNAL_DEFINITION_STORAGE:
break;
case AUTOMATIC_STORAGE:
fprintf (stderr, "%s:%i:%i: A function cannot be automatic\n", in_fname,
tok->lineno, tok->charno);
print_token (stderr, 0, tok);
errorcount++;
YYERROR;
break;
default:
abort ();
}
type = EXPRESSION_TYPE (prod);
/* Create a parameter list in a non-front end specific format. */
for (first_parms = NULL, last_parms = NULL, this_parm = PARAMETERS (prod);
this_parm;
this_parm = this_parm->next)
{
if (this_parm->category != production_category)
abort ();
this_parm_var = VARIABLE (this_parm);
if (!this_parm_var)
abort ();
if (this_parm_var->category != production_category)
abort ();
this_parms = my_malloc (sizeof (struct tree_parameter_list));
if (!this_parm_var->main_token)
abort ();
this_parms->variable_name = this_parm_var->main_token->chars;
this_parms->type = NUMERIC_TYPE (( (struct production*)EXPRESSION_TYPE (this_parm_var)));
if (last_parms)
{
last_parms->next = this_parms;
last_parms = this_parms;
}
else
{
first_parms = this_parms;
last_parms = this_parms;
}
this_parms->where_to_put_var_tree = & (( (struct production*)VARIABLE (this_parm))->code);
}
FIRST_PARMS (prod) = first_parms;
prod->code = tree_code_create_function_prototype
(tok->chars, STORAGE_CLASS (prod), NUMERIC_TYPE (type),
first_parms, in_fname, tok->lineno);
}
;
function:
NAME LEFT_BRACE {
struct production *proto;
struct production search_prod;
struct token* tok;
struct production *this_parm;
tok = $1;
SYMBOL_TABLE_NAME ((&search_prod)) = tok;
current_function = proto = lookup_tree_name (&search_prod);
if (!proto)
{
fprintf (stderr, "%s:%i:%i: Function prototype not found\n", in_fname,
tok->lineno, tok->charno);
print_token (stderr, 0, tok);
errorcount++;
YYERROR;
}
if (!proto->code)
abort ();
tree_code_create_function_initial
(proto->code, in_fname, tok->lineno,
FIRST_PARMS (current_function));
/* Check all the parameters have code. */
for (this_parm = PARAMETERS (proto);
this_parm;
this_parm = this_parm->next)
{
if (! (struct production*)VARIABLE (this_parm))
abort ();
if (! (( (struct production*)VARIABLE (this_parm))->code))
abort ();
}
}
variable_defs_opt statements_opt RIGHT_BRACE {
struct token* tok;
tok = $1;
tree_code_create_function_wrapup (in_fname, tok->lineno);
current_function = NULL;
}
;
variable_defs_opt:
/* Nil. */ {
$$ = 0;
}
|variable_defs {
$$ = $1;
}
;
statements_opt:
/* Nil. */ {
$$ = 0;
}
|statements {
$$ = $1;
}
;
variable_defs:
variable_def {
/* Nothing to do. */
}
|variable_defs variable_def {
/* Nothing to do. */
}
;
typename:
INT {
struct token* tok;
struct production *prod;
tok = $1;
prod = make_production (PROD_TYPE_NAME, tok);
NUMERIC_TYPE (prod) = SIGNED_INT;
prod->code = tree_code_get_type (NUMERIC_TYPE (prod));
$$ = prod;
}
|UNSIGNED INT {
struct token* tok;
struct production *prod;
tok = $1;
prod = make_production (PROD_TYPE_NAME, tok);
NUMERIC_TYPE (prod) = UNSIGNED_INT;
prod->code = tree_code_get_type (NUMERIC_TYPE (prod));
$$ = prod;
}
|CHAR {
struct token* tok;
struct production *prod;
tok = $1;
prod = make_production (PROD_TYPE_NAME, tok);
NUMERIC_TYPE (prod) = SIGNED_CHAR;
prod->code = tree_code_get_type (NUMERIC_TYPE (prod));
$$ = prod;
}
|UNSIGNED CHAR {
struct token* tok;
struct production *prod;
tok = $1;
prod = make_production (PROD_TYPE_NAME, tok);
NUMERIC_TYPE (prod) = UNSIGNED_CHAR;
prod->code = tree_code_get_type (NUMERIC_TYPE (prod));
$$ = prod;
}
|VOID {
struct token* tok;
struct production *prod;
tok = $1;
prod = make_production (PROD_TYPE_NAME, tok);
NUMERIC_TYPE (prod) = VOID_TYPE;
prod->code = tree_code_get_type (NUMERIC_TYPE (prod));
$$ = prod;
}
;
parameters:
parameter {
/* Nothing to do. */
$$ = $1;
}
|parameters COMMA parameter {
struct production *prod1;
prod1 = $3;
prod1->next = $1; /* Insert in reverse order. */
$$ = prod1;
}
;
statements:
statement {
/* Nothing to do. */
}
|statements statement {
/* Nothing to do. */
}
;
statement:
expression SEMICOLON {
struct production *exp;
exp = $1;
tree_code_output_expression_statement (exp->code, in_fname, exp->main_token->lineno);
}
|return SEMICOLON {
/* Nothing to do. */
}
|if_statement {
/* Nothing to do. */
}
;
if_statement:
IF LEFT_PARENTHESIS expression RIGHT_PARENTHESIS {
struct token* tok;
struct production *exp;
tok = $1;
exp = $3;
ensure_not_void (NUMERIC_TYPE (exp), exp->main_token);
tree_code_if_start (exp->code, in_fname, tok->lineno);
}
LEFT_BRACE statements_opt RIGHT_BRACE {
/* Just let the statements flow. */
}
ELSE {
struct token* tok;
tok = $1;
tree_code_if_else (in_fname, tok->lineno);
}
LEFT_BRACE statements_opt RIGHT_BRACE {
struct token* tok;
tok = $12;
tree_code_if_end (in_fname, tok->lineno);
}
;
return:
RETURN expression_opt {
struct production *type_prod;
struct token* ret_tok;
ret_tok = $1;
type_prod = EXPRESSION_TYPE (current_function);
if (NUMERIC_TYPE (type_prod) == VOID)
if ($2 == NULL)
tree_code_generate_return (type_prod->code, NULL);
else
{
fprintf (stderr, "%s:%i:%i: Redundant expression in return\n", in_fname,
ret_tok->lineno, ret_tok->charno);
print_token (stderr, 0, ret_tok);
errorcount++;
tree_code_generate_return (type_prod->code, NULL);
}
else
if ($2 == NULL)
{
fprintf (stderr, "%s:%i:%i: Expression missing in return\n", in_fname,
ret_tok->lineno, ret_tok->charno);
print_token (stderr, 0, ret_tok);
errorcount++;
}
else
{
struct production *exp;
exp = $2;
/* Check same type. */
if (check_type_match (NUMERIC_TYPE (type_prod), $2))
{
if (!type_prod->code)
abort ();
if (!exp->code)
abort ();
/* Generate the code. */
tree_code_generate_return (type_prod->code, exp->code);
}
}
}
;
expression_opt:
/* Nil. */ {
$$ = 0;
}
|expression {
struct production *exp;
exp = $1;
if (!exp->code)
abort ();
$$ = $1;
}
;
expression:
INTEGER {
$$ = make_integer_constant ($1);
}
|variable_ref {
$$ = $1;
}
|expression PLUS expression {
struct token* tok;
struct production *prod;
struct production *op1;
struct production *op2;
tree type;
op1 = $1;
op2 = $3;
tok = $2;
ensure_not_void (NUMERIC_TYPE (op1), op1->main_token);
ensure_not_void (NUMERIC_TYPE (op2), op2->main_token);
prod = make_production (PROD_PLUS_EXPRESSION, tok);
NUMERIC_TYPE (prod) = get_common_type (op1, op2);
if (!NUMERIC_TYPE (prod))
YYERROR;
else
{
type = get_type_for_numeric_type (NUMERIC_TYPE (prod));
if (!type)
abort ();
OP1 (prod) = $1;
OP2 (prod) = $3;
prod->code = tree_code_get_expression
(EXP_PLUS, type, op1->code, op2->code, NULL);
}
$$ = prod;
}
|expression MINUS expression %prec PLUS {
struct token* tok;
struct production *prod;
struct production *op1;
struct production *op2;
tree type;
op1 = $1;
op2 = $3;
ensure_not_void (NUMERIC_TYPE (op1), op1->main_token);
ensure_not_void (NUMERIC_TYPE (op2), op2->main_token);
tok = $2;
prod = make_production (PROD_PLUS_EXPRESSION, tok);
NUMERIC_TYPE (prod) = get_common_type (op1, op2);
if (!NUMERIC_TYPE (prod))
YYERROR;
else
{
type = get_type_for_numeric_type (NUMERIC_TYPE (prod));
if (!type)
abort ();
OP1 (prod) = $1;
OP2 (prod) = $3;
prod->code = tree_code_get_expression (EXP_MINUS,
type, op1->code, op2->code, NULL);
}
$$ = prod;
}
|expression EQUALS expression {
struct token* tok;
struct production *prod;
struct production *op1;
struct production *op2;
tree type;
op1 = $1;
op2 = $3;
ensure_not_void (NUMERIC_TYPE (op1), op1->main_token);
ensure_not_void (NUMERIC_TYPE (op2), op2->main_token);
tok = $2;
prod = make_production (PROD_PLUS_EXPRESSION, tok);
NUMERIC_TYPE (prod) = SIGNED_INT;
if (!NUMERIC_TYPE (prod))
YYERROR;
else
{
type = get_type_for_numeric_type (NUMERIC_TYPE (prod));
if (!type)
abort ();
OP1 (prod) = $1;
OP2 (prod) = $3;
prod->code = tree_code_get_expression (EXP_EQUALS,
type, op1->code, op2->code, NULL);
}
$$ = prod;
}
|variable_ref ASSIGN expression {
struct token* tok;
struct production *prod;
struct production *op1;
struct production *op2;
tree type;
op1 = $1;
op2 = $3;
tok = $2;
ensure_not_void (NUMERIC_TYPE (op2), op2->main_token);
prod = make_production (PROD_ASSIGN_EXPRESSION, tok);
NUMERIC_TYPE (prod) = NUMERIC_TYPE (op1);
if (!NUMERIC_TYPE (prod))
YYERROR;
else
{
type = get_type_for_numeric_type (NUMERIC_TYPE (prod));
if (!type)
abort ();
OP1 (prod) = $1;
OP2 (prod) = $3;
prod->code = tree_code_get_expression (EXP_ASSIGN,
type, op1->code, op2->code, NULL);
}
$$ = prod;
}
|function_invocation {
$$ = $1;
}
;
function_invocation:
NAME LEFT_PARENTHESIS expressions_with_commas RIGHT_PARENTHESIS {
struct production *prod;
struct token* tok;
struct production search_prod;
struct production *proto;
struct production *exp;
struct production *exp_proto;
struct production *var;
int exp_proto_count;
int exp_count;
tree parms;
tree type;
tok = $1;
prod = make_production (PROD_FUNCTION_INVOCATION, tok);
SYMBOL_TABLE_NAME (prod) = tok;
PARAMETERS (prod) = reverse_prod_list ($3);
SYMBOL_TABLE_NAME ((&search_prod)) = tok;
proto = lookup_tree_name (&search_prod);
if (!proto)
{
fprintf (stderr, "%s:%i:%i: Function prototype not found\n", in_fname,
tok->lineno, tok->charno);
print_token (stderr, 0, tok);
errorcount++;
YYERROR;
}
EXPRESSION_TYPE (prod) = EXPRESSION_TYPE (proto);
NUMERIC_TYPE (prod) = NUMERIC_TYPE (proto);
/* Count the expressions and ensure they match the prototype. */
for (exp_proto_count = 0, exp_proto = PARAMETERS (proto);
exp_proto; exp_proto = exp_proto->next)
exp_proto_count++;
for (exp_count = 0, exp = PARAMETERS (prod); exp; exp = exp->next)
exp_count++;
if (exp_count != exp_proto_count)
{
fprintf (stderr, "%s:%i:%i: expression count mismatch with prototype\n", in_fname,
tok->lineno, tok->charno);
print_token (stderr, 0, tok);
errorcount++;
YYERROR;
}
parms = tree_code_init_parameters ();
for (exp_proto = PARAMETERS (proto), exp = PARAMETERS (prod);
exp_proto;
exp = exp->next, exp_proto = exp_proto->next)
{
if (!exp)
abort ();
if (!exp_proto)
abort ();
if (!exp->code)
abort ();
var = VARIABLE (exp_proto);
if (!var)
abort ();
if (!var->code)
abort ();
parms = tree_code_add_parameter (parms, var->code, exp->code);
}
type = get_type_for_numeric_type (NUMERIC_TYPE (prod));
prod->code = tree_code_get_expression
(EXP_FUNCTION_INVOCATION, type, proto->code, parms, NULL);
$$ = prod;
}
;
expressions_with_commas:
expression {
struct production *exp;
exp = $1;
ensure_not_void (NUMERIC_TYPE (exp), exp->main_token);
$$ = $1;
}
|expressions_with_commas COMMA expression {
struct production *exp;
exp = $3;
ensure_not_void (NUMERIC_TYPE (exp), exp->main_token);
exp->next = $1; /* Reverse order. */
$$ = exp;
}
;
variable_ref:
NAME {
struct production search_prod;
struct production *prod;
struct production *symbol_table_entry;
struct token* tok;
tree type;
tok = $1;
SYMBOL_TABLE_NAME ((&search_prod)) = tok;
symbol_table_entry = lookup_tree_name (&search_prod);
if (!symbol_table_entry)
{
fprintf (stderr, "%s:%i:%i: Variable referred to but not defined\n", in_fname,
tok->lineno, tok->charno);
print_token (stderr, 0, tok);
errorcount++;
YYERROR;
}
prod = make_production (PROD_VARIABLE_REFERENCE_EXPRESSION, tok);
NUMERIC_TYPE (prod) = NUMERIC_TYPE (symbol_table_entry);
type = get_type_for_numeric_type (NUMERIC_TYPE (prod));
if (!NUMERIC_TYPE (prod))
YYERROR;
OP1 (prod) = $1;
prod->code = tree_code_get_expression (EXP_REFERENCE, type,
symbol_table_entry->code, NULL, NULL);
$$ = prod;
}
;
init_opt:
/* Nil. */ {
$$ = 0;
}
|init {
/* Nothing to do. */
}
init:
ASSIGN init_element {
}
;
init_element:
INTEGER {
$$ = make_integer_constant ($1);
}
;
%%
/* Print a token VALUE to file FILE. Ignore TYPE which is the token
type. */
void
print_token (FILE * file, unsigned int type ATTRIBUTE_UNUSED, YYSTYPE value)
{
struct token *tok;
unsigned int ix;
tok = value;
fprintf (file, "%d \"", tok->lineno);
for (ix = 0; ix < tok->length; ix++)
fprintf (file, "%c", tok->chars[ix]);
fprintf (file, "\"");
}
/* Output a message ERROR_MESSAGE from the parser. */
void
yyerror (const char *error_message)
{
struct token *tok;
tok = yylval;
if (tok)
{
fprintf (stderr, "%s:%i:%i: %s\n", in_fname, tok->lineno, tok->charno, error_message);
print_token (stderr, 0, tok);
}
else
fprintf (stderr, "%s\n", error_message);
errorcount++;
}
/* Reverse the order of a token list, linked by parse_next, old first
token is OLD_FIRST. */
static struct production*
reverse_prod_list (struct production *old_first)
{
struct production *current;
struct production *next;
struct production *prev = NULL;
current = old_first;
prev = NULL;
while (current)
{
if (current->category != production_category)
abort ();
next = current->next;
current->next = prev;
prev = current;
current = next;
}
return prev;
}
/* Ensure TYPE is not VOID. Use NAME as the token for the error location. */
static void
ensure_not_void (unsigned int type, struct token* name)
{
if (type == VOID)
{
fprintf (stderr, "%s:%i:%i: Type must not be void in this context\n", in_fname,
name->lineno, name->charno);
print_token (stderr, 0, name);
errorcount++;
}
}
/* Check TYPE1 and TYPE2 which are integral types. Return the lowest
common type (min is signed int). */
static int
get_common_type (struct production *type1, struct production *type2)
{
if (NUMERIC_TYPE (type1) == UNSIGNED_INT)
return UNSIGNED_INT;
if (NUMERIC_TYPE (type2) == UNSIGNED_INT)
return UNSIGNED_INT;
return SIGNED_INT;
}
/* Check type (TYPE_NUM) and expression (EXP) match. Return the 1 if
OK else 0. Must be exact match - same name unless it is an
integral type. */
static int
check_type_match (int type_num, struct production *exp)
{
switch (type_num)
{
case SIGNED_INT:
case UNSIGNED_INT:
case SIGNED_CHAR:
case UNSIGNED_CHAR:
switch (NUMERIC_TYPE (exp))
{
case SIGNED_INT:
case UNSIGNED_INT:
case SIGNED_CHAR:
case UNSIGNED_CHAR:
return 1;
case VOID:
abort ();
default:
abort ();
}
break;
case VOID:
abort ();
default:
abort ();
}
}
/* Make a production for an integer constant VALUE. */
static struct production *
make_integer_constant (struct token* value)
{
struct token* tok;
struct production *prod;
tok = value;
prod = make_production (PROD_INTEGER_CONSTANT, tok);
if ((tok->chars[0] == (unsigned char)'-')|| (tok->chars[0] == (unsigned char)'+'))
NUMERIC_TYPE (prod) = SIGNED_INT;
else
NUMERIC_TYPE (prod) = UNSIGNED_INT;
prod->code = tree_code_get_integer_value (tok->chars, tok->length);
return prod;
}
/* Set STORAGE_CLASS in PROD according to CLASS_TOKEN. */
static void
set_storage (struct production *prod)
{
struct token* stg_class;
stg_class = STORAGE_CLASS_TOKEN (prod);
switch (stg_class->type)
{
case STATIC:
STORAGE_CLASS (prod) = STATIC_STORAGE;
break;
case AUTOMATIC:
STORAGE_CLASS (prod) = AUTOMATIC_STORAGE;
break;
case EXTERNAL_DEFINITION:
STORAGE_CLASS (prod) = EXTERNAL_DEFINITION_STORAGE;
break;
case EXTERNAL_REFERENCE:
STORAGE_CLASS (prod) = EXTERNAL_REFERENCE_STORAGE;
break;
default:
abort ();
}
}
/* Set parse trace. */
void
treelang_debug (void)
{
if (option_parser_trace)
yydebug = 1;
}
/*
TREELANG Compiler almost main (tree1)
Called by GCC's toplev.c
Copyright (C) 1986, 87, 89, 92-96, 1997, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This program 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 2, or (at your option) any
later version.
This program 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 this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding!
---------------------------------------------------------------------------
Written by Tim Josling 1999, 2000, 2001, based in part on other
parts of the GCC compiler.
*/
#include "config.h"
#include "system.h"
#include "ansidecl.h"
#include "flags.h"
#include "output.h"
#include "toplev.h"
#include "ggc.h"
#include "tree.h"
#include "diagnostic.h"
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include "treelang.h"
#include "treetree.h"
extern int yyparse (void);
/* Linked list of symbols - all must be unique in treelang. */
struct production *symbol_table = NULL;
/* Language for usage for messages. */
const char *const language_string = "TREELANG - sample front end for GCC ";
/* Local prototypes. */
void version (void);
/* GC routine for symbol table. */
static void symbol_table_ggc (void *m);
/* Global variables. */
extern struct cbl_tree_struct_parse_tree_top* parse_tree_top;
/*
Options.
*/
/* Trace the parser. */
unsigned int option_parser_trace = 0;
/* Trace the lexical analysis. */
unsigned int option_lexer_trace = 0;
/* Warning levels. */
/* Local variables. */
unsigned char *in_fname = NULL; /* Input file name. */
/* This is 1 if we have output the version string. */
static int version_done = 0;
/* Variable nesting level. */
static unsigned int work_nesting_level = 0;
/* Process one switch - called by toplev.c. */
int
treelang_decode_option (num_options_left, first_option_left)
int num_options_left ATTRIBUTE_UNUSED;
char** first_option_left;
{
/*
Process options - bear in mind I may get options that are really
meant for someone else (eg the main compiler) so I have to be very
permissive.
*/
if (first_option_left[0][0] != '-')
return 0;
switch (first_option_left[0][1])
{
case '-':
if (!strcmp (first_option_left[0],"--help"))
{
if (!version_done)
{
fputs (language_string, stdout);
fputs (version_string, stdout);
fputs ("\n", stdout);
version_done = 1;
}
fprintf (stdout, "Usage: tree1 [switches] -o output input\n");
return 1;
}
case 'v':
if (!strcmp (first_option_left[0],"-v"))
{
if (!version_done)
{
fputs (language_string, stdout);
fputs (version_string, stdout);
fputs ("\n", stdout);
version_done = 1;
}
return 1;
}
case 'y':
if (!strcmp (first_option_left[0],"-y"))
{
option_lexer_trace = 1;
option_parser_trace = 1;
return 1;
}
case 'f':
if (!strcmp (first_option_left[0],"-fparser-trace"))
{
option_parser_trace = 1;
return 1;
}
if (!strcmp (first_option_left[0],"-flexer-trace"))
{
option_lexer_trace = 1;
return 1;
}
return 0;
case 'w':
if (!strcmp (first_option_left[0],"-w"))
{
/* Tolerate this option but ignore it - we always put out
all warnings. */
return 1;
}
return 0;
case 'W':
if (!strcmp (first_option_left[0],"-Wall"))
{
return 1;
}
return 0;
default:
return 0;
}
return 0;
}
/* Language dependent parser setup. */
const char*
treelang_init (const char* filename)
{
/* Define my garbage collection routines. */
ggc_add_root (&symbol_table, 1,
/* Unused size. */ sizeof (void*), symbol_table_ggc);
/* Note: only storage that has to be kept across functions needs to
be protected from GC. */
/* Define my garbage collection routines. */
ggc_add_root (&symbol_table, 1,
/* Unused size. */ sizeof (void*), symbol_table_ggc);
/* Note: only storage that has to be kept across functions needs to
be protected from GC. */
/* Set up the declarations needed for this front end. */
input_filename = "";
lineno = 0;
treelang_init_decl_processing ();
/* This error will not happen from GCC as it will always create a
fake input file. */
if (!filename || (filename[0] == ' ') || (!filename[0]))
{
if (!version_done)
{
fprintf (stderr, "No input file specified, try --help for help\n");
exit (1);
}
in_fname = NULL;
return NULL;
}
yyin = fopen (filename, "r");
if (!yyin)
{
fprintf (stderr, "Unable to open input file %s\n", filename);
exit (1);
}
input_filename = filename;
return (char*) (in_fname = (unsigned char*)filename);
}
/* Language dependent wrapup. */
void
treelang_finish (void)
{
fclose (yyin);
}
/* Parse a file. Debug flag doesn't seem to work. */
void
treelang_parse_file (int debug_flag ATTRIBUTE_UNUSED)
{
treelang_debug ();
yyparse ();
}
/* Scan the symbol table* M, marking storage used. */
static void
symbol_table_ggc (void *m)
{
struct production *pp;
pp = * (struct production**)m;
/* Actually it is a pointer to a pointer, to allow reallocation and
relinking. */
mark_production_used (pp);
}
/* Mark a production PP as used so it wont be garbage collected. */
void
mark_production_used (struct production *pp)
{
int sub_ix;
loop:
if (!pp)
return;
ggc_mark (pp);
if (pp->category == token_category)
{
mark_token_used ((struct token*)pp);
return;
}
if (pp->category != production_category)
abort ();
mark_token_used (pp->main_token);
for (sub_ix = 0; sub_ix < SUB_COUNT; sub_ix++)
mark_production_used (pp->sub[sub_ix]);
/* The macro tests for NULL so I don't need to. */
ggc_mark_tree (pp->code);
pp = pp->next;
goto loop;
}
/* Mark a token TT as used so it wont be garbage collected. */
void
mark_token_used (struct token* tt)
{
if (!tt)
return;
ggc_mark (tt);
if (tt->chars)
ggc_mark (tt->chars);
}
/* Allocate SIZE bytes and clear them. */
void *
my_malloc (size_t size)
{
void *mem;
mem = ggc_alloc (size);
if (!mem)
{
fprintf (stderr, "\nOut of memory\n");
abort ();
}
memset (mem, 0, size);
return mem;
}
/* Look up a name in PROD->SYMBOL_TABLE_NAME in the symbol table;
return the symbol table entry from the symbol table if found there,
else 0. */
struct production*
lookup_tree_name (struct production *prod)
{
struct production *this;
struct token* this_tok;
struct token* tok;
tok = SYMBOL_TABLE_NAME (prod);
for (this = symbol_table; this; this = this->next)
{
this_tok = this->main_token;
if (tok->length != this_tok->length)
continue;
if (memcmp (tok->chars, this_tok->chars, this_tok->length))
continue;
if (option_parser_trace)
fprintf (stderr, "Found symbol %s (%i:%i) as %i \n", tok->chars,
tok->lineno, tok->charno, NUMERIC_TYPE (this));
return this;
}
if (option_parser_trace)
fprintf (stderr, "Not found symbol %s (%i:%i) as %i \n", tok->chars,
tok->lineno, tok->charno, tok->type);
return NULL;
}
/* Insert name PROD into the symbol table. Return 1 if duplicate, 0 if OK. */
int
insert_tree_name (struct production *prod)
{
struct token* tok;
tok = SYMBOL_TABLE_NAME (prod);
if (lookup_tree_name (prod))
{
fprintf (stderr, "%s:%i:%i duplicate name %s\n", in_fname, tok->lineno, tok->charno, tok->chars);
errorcount++;
return 1;
}
prod->next = symbol_table;
NESTING_LEVEL (prod) = work_nesting_level;
symbol_table = prod;
return 0;
}
/* Create a struct productions of type TYPE, main token MAIN_TOK. */
struct production *
make_production (int type, struct token* main_tok)
{
struct production *prod;
prod = my_malloc (sizeof (struct production));
prod->category = production_category;
prod->type = type;
prod->main_token = main_tok;
return prod;
}
/*
TREELANG Compiler common definitions (treelang.h)
Copyright (C) 1986, 87, 89, 92-96, 1997, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This program 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 2, or (at your option) any
later version.
This program 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 this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding!
---------------------------------------------------------------------------
Written by Tim Josling 1999, 2000, 2001, based in part on other
parts of the GCC compiler.
*/
/* Parse structure type. */
enum category_enum
{ /* These values less likely to be there by chance unlike 0/1,
make checks more meaningful */
token_category = 111,
production_category = 222
};
/* Input file name and FILE. */
extern unsigned char* in_fname;
extern FILE* yyin;
#if 0
extern int errorcount; /* In toplev.c. */
#endif
struct token
{
enum category_enum category; /* Token or production. */
unsigned int type; /* Token type. */
/* Prior to this point, production must match token. */
unsigned int lineno;
unsigned int charno;
unsigned int length; /* The value. */
unsigned char* chars;
};
struct production
{
enum category_enum category; /* Token or Production. */
unsigned int type; /* Production type - a fake token name. */
/* Prior to this point, production must match token. */
struct token* main_token; /* Main token for error msgs; variable name token. */
unsigned int info[2]; /* Extra information. */
#define NESTING_LEVEL(a) a->info[0] /* Level used for variable definitions. */
#define NUMERIC_TYPE(a) a->info[1] /* Numeric type used in type definitions and expressions. */
#define SUB_COUNT 5
void *sub[SUB_COUNT]; /* Sub productions or tokens. */
#define SYMBOL_TABLE_NAME(a) (a->sub[0]) /* Name token. */
#define EXPRESSION_TYPE(a) (a->sub[1]) /* Type identifier. */
#define OP1(a) (a->sub[2]) /* Exp operand1. */
#define PARAMETERS(a) (a->sub[2]) /* Function parameters. */
#define VARIABLE(a) (a->sub[2]) /* Parameter variable ptr. */
#define VAR_INIT(a) (a->sub[2]) /* Variable init. */
#define OP2(a) (a->sub[3]) /* Exp operand2. */
#define FIRST_PARMS(a) (a->sub[3]) /* Function parameters linked via struct tree_parameter_list. */
#define OP3(a) (a->sub[4]) /* Exp operand3. */
#define STORAGE_CLASS_TOKEN(a) (a->sub[4]) /* Storage class token. */
void *code; /* Back end hook for this item. */
struct production *next; /* Next in chains of various types. */
unsigned int flag1:2;
#define STORAGE_CLASS(a) a->flag1 /* Values in treetree.h. */
unsigned int flag2:1;
unsigned int flag3:1;
unsigned int flag4:1;
unsigned int flag5:1;
unsigned int flag6:1;
unsigned int flag7:1;
};
/* For parser. Alternatively you can define it using %union (bison) or
union. */
#define YYSTYPE void *
void *my_malloc (size_t size);
int insert_tree_name (struct production *prod);
struct production *lookup_tree_name (struct production *prod);
struct production *make_production (int type, struct token* main_tok);
void mark_production_used (struct production * pp);
void mark_token_used (struct token* tt);
void treelang_debug (void);
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename treelang.info
@set last-update 2001-07-30
@set copyrights-treelang 1995,1996,1997,1998,1999,2000,2001,2002
@c DEVELOPMENT is set to indicate an in-development version,
@c as compared to a release version. When making a release
@c (e.g. a release branch in the CVS repository for GCC),
@c clear this and set the version information correctly.
@clear DEVELOPMENT
@set version-treelang 1.0
@set version-GCC 3.0
@set email-general gcc@@gcc.gnu.org
@set email-bugs gcc-bugs@@gcc.gnu.org or bug-gcc@@gnu.org
@set email-patches gcc-patches@@gcc.gnu.org
@set path-treelang gcc/gcc/treelang
@set which-treelang GCC-@value{version-GCC}
@set which-GCC GCC
@set email-josling tej@@melbpc.org.au
@set www-josling http://www.geocities.com/timjosling
@c This tells @include'd files that they're part of the overall TREELANG doc
@c set. (They might be part of a higher-level doc set too.)
@set DOC-TREELANG
@c @setfilename usetreelang.info
@c @setfilename maintaintreelang.info
@c To produce the full manual, use the "treelang.info" setfilename, and
@c make sure the following do NOT begin with '@c' (and the @clear lines DO)
@set INTERNALS
@set USING
@c To produce a user-only manual, use the "usetreelang.info" setfilename, and
@c make sure the following does NOT begin with '@c':
@c @clear INTERNALS
@c To produce a maintainer-only manual, use the "maintaintreelang.info" setfilename,
@c and make sure the following does NOT begin with '@c':
@c @clear USING
@c 6/27/96 FSF DO wants smallbook fmt for 1st bound edition. (from gcc.texi)
@c @smallbook
@c i also commented out the finalout command, so if there *are* any
@c overfulls, you'll (hopefully) see the rectangle in the right hand
@c margin. -- burley 1999-03-13 (from mew's comment in GCC.texi).
@c @finalout
@ifset INTERNALS
@ifset USING
@settitle Using and Maintaining GNU Treelang
@end ifset
@end ifset
@c seems reasonable to assume at least one of INTERNALS or USING is set...
@ifclear INTERNALS
@settitle Using GNU Treelang
@end ifclear
@ifclear USING
@settitle Maintaining GNU Treelang
@end ifclear
@c then again, have some fun
@ifclear INTERNALS
@ifclear USING
@settitle Doing Very Little at all with GNU Treelang
@end ifclear
@end ifclear
@syncodeindex fn cp
@syncodeindex vr cp
@c %**end of header
@c Cause even numbered pages to be printed on the left hand side of
@c the page and odd numbered pages to be printed on the right hand
@c side of the page. Using this, you can print on both sides of a
@c sheet of paper and have the text on the same part of the sheet.
@c The text on right hand pages is pushed towards the right hand
@c margin and the text on left hand pages is pushed toward the left
@c hand margin.
@c (To provide the reverse effect, set bindingoffset to -0.75in.)
@c @tex
@c \global\bindingoffset=0.75in
@c \global\normaloffset =0.75in
@c @end tex
@ifinfo
@dircategory Programming
@direntry
* treelang: (treelang). The GNU Treelang compiler.
@end direntry
@ifset INTERNALS
@ifset USING
This file documents the use and the internals of the GNU Treelang
(@code{treelang}) compiler. At the moment this manual is not
incorporated into the main GCC manual as it is too incomplete. It
corresponds to the @value{which-treelang} version of @code{treelang}.
@end ifset
@end ifset
@ifclear USING
This file documents the internals of the GNU Treelang (@code{treelang}) compiler.
It corresponds to the @value{which-treelang} version of @code{treelang}.
@end ifclear
@ifclear INTERNALS
This file documents the use of the GNU Treelang (@code{treelang}) compiler.
It corresponds to the @value{which-treelang} version of @code{treelang}.
@end ifclear
Published by the Free Software Foundation
59 Temple Place - Suite 330
Boston, MA 02111-1307 USA
Copyright (C) @value{copyrights-treelang} 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.1 or
any later version published by the Free Software Foundation; with the
Invariant Sections being ``GNU General Public License'', the Front-Cover
texts being (a) (see below), and with the Back-Cover Texts being (b)
(see below). A copy of the license is included in the section entitled
``GNU Free Documentation License''.
(a) The FSF's Front-Cover Text is:
A GNU Manual
(b) The FSF's Back-Cover Text is:
You have freedom to copy and modify this GNU Manual, like GNU
software. Copies published by the Free Software Foundation raise
funds for GNU development.
@end ifinfo
treelang was Contributed by Tim Josling (@email{@value{email-josling}}).
Inspired by and based on the 'toy' language, written by Richard Kenner.
This document was written by Tim Josling, based on the GNU C++
documentation.
@setchapternewpage odd
@c @finalout
@titlepage
@ifset INTERNALS
@ifset USING
@center @titlefont{Using and Maintaining GNU Treelang}
@end ifset
@end ifset
@ifclear INTERNALS
@title Using GNU Treelang
@end ifclear
@ifclear USING
@title Maintaining GNU Treelang
@end ifclear
@sp 2
@center Tim Josling
@sp 3
@center Last updated @value{last-update}
@sp 1
@center for version @value{version-treelang}
@page
@vskip 0pt plus 1filll
Copyright @copyright{} @value{copyrights-treelang} Free Software Foundation, Inc.
@sp 2
For the @value{which-treelang} Version*
@sp 1
Published by the Free Software Foundation @*
59 Temple Place - Suite 330@*
Boston, MA 02111-1307, USA@*
@c Last printed ??ber, 19??.@*
@c Printed copies are available for $? each.@*
@c ISBN ???
@sp 1
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.1 or
any later version published by the Free Software Foundation; with the
Invariant Sections being ``GNU General Public License'', the Front-Cover
texts being (a) (see below), and with the Back-Cover Texts being (b)
(see below). A copy of the license is included in the section entitled
``GNU Free Documentation License''.
(a) The FSF's Front-Cover Text is:
A GNU Manual
(b) The FSF's Back-Cover Text is:
You have freedom to copy and modify this GNU Manual, like GNU
software. Copies published by the Free Software Foundation raise
funds for GNU development.
@end titlepage
@page
@ifinfo
@node Top, Copying,, (dir)
@top Introduction
@cindex Introduction
@ifset INTERNALS
@ifset USING
This manual documents how to run, install and maintain @code{treelang},
as well as its new features and incompatibilities,
and how to report bugs.
It corresponds to the @value{which-treelang} version of @code{treelang}.
@end ifset
@end ifset
@ifclear INTERNALS
This manual documents how to run and install @code{treelang},
as well as its new features and incompatibilities, and how to report
bugs.
It corresponds to the @value{which-treelang} version of @code{treelang}.
@end ifclear
@ifclear USING
This manual documents how to maintain @code{treelang}, as well as its
new features and incompatibilities, and how to report bugs. It
corresponds to the @value{which-treelang} version of @code{treelang}.
@end ifclear
@end ifinfo
@ifset DEVELOPMENT
@emph{Warning:} This document is still under development, and might not
accurately reflect the @code{treelang} code base of which it is a part.
@end ifset
@menu
* Copying::
* Contributors::
* GNU Free Documentation License::
* Funding::
* Getting Started::
* What is GNU Treelang?::
* Lexical Syntax::
* Parsing Syntax::
* Compiler Overview::
* TREELANG and GCC::
* Compiler::
* Other Languages::
* treelang internals::
* Open Questions::
* Bugs::
* Service::
* Projects::
* Index::
@detailmenu
--- The Detailed Node Listing ---
Other Languages
* Interoperating with C and C++::
treelang internals
* treelang files::
* treelang compiler interfaces::
* Hints and tips::
treelang compiler interfaces
* treelang driver::
* treelang main compiler::
treelang main compiler
* Interfacing to toplev.c::
* Interfacing to the garbage collection::
* Interfacing to the code generation code. ::
Reporting Bugs
* Sending Patches::
@end detailmenu
@end menu
@include gpl.texi
@include fdl.texi
@node Contributors
@unnumbered Contributors to GNU Treelang
@cindex contributors
@cindex credits
Treelang was based on 'toy' by Richard Kenner, and also uses code from
the GCC core code tree. Tim Josling first created the language and
documentation, based on the GCC Fortran compiler's documentation
framework.
@itemize @bullet
@item
The packaging and compiler portions of GNU Treelang are based largely
on the GCC compiler.
@xref{Contributors,,Contributors to GCC,GCC,Using and Maintaining GCC},
for more information.
@item
There is no specific run-time library for treelang, other than the
standard C runtime.
@item
It would have been difficult to build treelang without access to Joachim
Nadler's guide to writing a front end to GCC (written in German). A
translation of this document into English is available via the
CobolForGCC project or via the documentation links from the GCC home
page @uref{http://GCC.gnu.org}.
@end itemize
@include funding.texi
@node Getting Started
@chapter Getting Started
@cindex getting started
@cindex new users
@cindex newbies
@cindex beginners
Treelang is a sample language, useful only to help people understand how
to implement a new language front end to GCC. It is not a useful
language in itself other than as an example or basis for building a new
language. Therefore only language developers are likely to have an
interest in it.
This manual assumes familiarity with GCC, which you can obtain by using
it and by reading the manual @samp{Using and Porting GCC}.
To install treelang, follow the GCC installation instructions,
taking care to ensure you specify treelang in the configure step.
If you're generally curious about the future of
@code{treelang}, see @ref{Projects}.
If you're curious about its past,
see @ref{Contributors}.
To see a few of the questions maintainers of @code{treelang} have,
and that you might be able to answer,
see @ref{Open Questions}.
@ifset USING
@node What is GNU Treelang?, Lexical Syntax, Getting Started, Top
@chapter What is GNU Treelang?
@cindex concepts, basic
@cindex basic concepts
GNU Treelang, or @code{treelang}, is designed initially as a free
replacement for, or alternative to, the 'toy' language, but which is
amenable to inclusion within the GCC source tree.
@code{treelang} is largely a cut down version of C, designed to showcase
the features of the GCC code generation back end. Only those features
that are directly supported by the GCC code generation back end are
implemented. Features are implemented in a manner which is easiest and
clearest to implement. Not all or even most code generation back end
features are implemented. The intention is to add features incrementally
until most features of the GCC back end are implemented in treelang.
The main features missing are structures, arrays and pointers.
A sample program follows:
@example
// function prototypes
// function 'add' taking two ints and returning an int
external_definition int add(int arg1, int arg2);
external_definition int subtract(int arg3, int arg4);
external_definition int first_nonzero(int arg5, int arg6);
external_definition int double_plus_one(int arg7);
// function definition
add
@{
// return the sum of arg1 and arg2
return arg1 + arg2;
@}
subtract
@{
return arg3 - arg4;
@}
double_plus_one
@{
// aaa is a variable, of type integer and allocated at the start of the function
automatic int aaa;
// set aaa to the value returned from aaa, when passed arg7 and arg7 as the two parameters
aaa=add(arg7, arg7);
aaa=add(aaa, aaa);
aaa=subtract(subtract(aaa, arg7), arg7) + 1;
return aaa;
@}
first_nonzero
@{
// C-like if statement
if (arg5)
@{
return arg5;
@}
else
@{
@}
return arg6;
@}
@end example
@node Lexical Syntax, Parsing Syntax, What is GNU Treelang?, Top
@chapter Lexical Syntax
@cindex Lexical Syntax
Treelang programs consist of whitespace, comments, keywords and names.
@itemize @bullet
@item
Whitespace consists of the space character and the end of line
character. Tabs are not allowed. Line terminations are as defined by the
standard C library. Whitespace is ignored except within comments,
and where it separates parts of the program. In the example below, A and
B are two separate names separated by whitespace.
@smallexample
A B
@end smallexample
@item
Comments consist of @samp{//} followed by any characters up to the end
of the line. C style comments (/* */) are not supported. For example,
the assignment below is followed by a not very helpful comment.
@smallexample
x=1; // Set X to 1
@end smallexample
@item
Keywords consist of any reserved words or symbols as described
later. The list of keywords follows:
@smallexample
@{ - used to start the statements in a function
@} - used to end the statements in a function
( - start list of function arguments, or to change the precedence of operators in an expression
) - end list or prioritised operators in expression
, - used to separate parameters in a function prototype or in a function call
; - used to end a statement
+ - addition
- - subtraction
= - assignment
== - equality test
if - begin IF statement
else - begin 'else' portion of IF statement
static - indicate variable is permanent, or function has file scope only
automatic - indicate that variable is allocated for the life of the function
external_reference - indicate that variable or function is defined in another file
external_definition - indicate that variable or function is to be accessible from other files
int - variable is an integer (same as C int)
char - variable is a character (same as C char)
unsigned - variable is unsigned. If this is not present, the variable is signed
return - start function return statement
void - used as function type to indicate function returns nothing
@end smallexample
@item
Names consist of any letter or "_" followed by any number of letters or
numbers or "_". "$" is not allowed in a name. All names must be globally
unique - the same name may not be used twice in any context - and must
not be a keyword. Names and keywords are case sensitive. For example:
@smallexample
a A _a a_ IF_X
@end smallexample
are all different names.
@end itemize
@node Parsing Syntax, Compiler Overview, Lexical Syntax, Top
@chapter Parsing Syntax
@cindex Parsing Syntax
Declarations are built up from the lexical elements described above. A
file may contain one of more declarations.
@itemize @bullet
@item
declaration: variable declaration OR function prototype OR function declaration
@item
Function Prototype: storage type NAME ( parameter_list )
@smallexample
static int add (int a, int b)
@end smallexample
@item
variable_declaration: storage type NAME initial;
Example:
@smallexample
int temp1=1;
@end smallexample
A variable declaration can be outside a function, or at the start of a function.
@item
storage: automatic OR static OR external_reference OR external_definition
This defines the scope, duration and visibility of a function or variable
@enumerate 1
@item
automatic: This means a variable is allocated at start of function and
released when the function returns. This can only be used for variables
within functions. It cannot be used for functions.
@item
static: This means a variable is allocated at start of program and
remains allocated until the program as a whole ends. For a function, it
means that the function is only visible within the current file.
@item
external_definition: For a variable, which must be defined outside a
function, it means that the variable is visible from other files. For a
function, it means that the function is visible from another file.
@item
external_reference: For a variable, which must be defined outside a
function, it means that the variable is defined in another file. For a
function, it means that the function is defined in another file.
@end enumerate
@item
type: int OR unsigned int OR char OR unsigned char OR void
This defines the data type of a variable or the return type of a function.
@enumerate a
@item
int: The variable is a signed integer. The function returns a signed integer.
@item
unsigned int: The variable is an unsigned integer. The function returns an unsigned integer.
@item
char: The variable is a signed character. The function returns a signed character.
@item
unsigned char: The variable is an unsigned character. The function returns an unsigned character.
@end enumerate
@item
parameter_list OR parameter [, parameter]...
@item
parameter: variable_declaration ,
The variable declarations must not have initialisations.
@item
initial: = value
@item
value: integer_constant
@smallexample
eg 1 +2 -3
@end smallexample
@item
function_declaration: name @{variable_declarations statements @}
A function consists of the function name then the declarations (if any)
and statements (if any) within one pair of braces.
The details of the function arguments come from the function
prototype. The function prototype must precede the function declaration
in the file.
@item
statement: if_statement OR expression_statement OR return_statement
@item
if_statement: if (expression) @{ statements @} else @{ statements @}
The first lot of statements is executed if the expression is
non-zero. Otherwise the second lot of statements is executed. Either
list of statements may be empty, but both sets of braces and the else must be present.
@smallexample
if (a==b)
@{
// nothing
@}
else
@{
a=b;
@}
@end smallexample
@item
expression_statement: expression;
The expression is executed and any side effects, such
@item
return_statement: return expression_opt;
Returns from the function. If the function is void, the expression must
be absent, and if the function is not void the expression must be
present.
@item
expression: variable OR integer_constant OR expression+expression OR expression-expression
OR expression==expression OR (expression) OR variable=expression OR function_call
An expression can be a constant or a variable reference or a
function_call. Expressions can be combined as a sum of two expressions
or the difference of two expressions, or an equality test of two
expresions. An assignment is also an expression. Expresions and operator
precedence work as in C.
@item
function_call: function_name (comma_separated_expressions)
This invokes the function, passing to it the values of the expressions
as actual parameters.
@end itemize
@cindex compilers
@node Compiler Overview, TREELANG and GCC, Parsing Syntax, Top
@chapter Compiler Overview
treelang is run as part of the GCC compiler.
@itemize @bullet
@cindex source code
@cindex file, source
@cindex code, source
@cindex source file
@item
It reads a user's program, stored in a file and containing instructions
written in the appropriate language (Treelang, C, and so on). This file
contains @dfn{source code}.
@cindex translation of user programs
@cindex machine code
@cindex code, machine
@cindex mistakes
@item
It translates the user's program into instructions a computer can carry
out more quickly than it takes to translate the instructions in the
first place. These instructions are called @dfn{machine code}---code
designed to be efficiently translated and processed by a machine such as
a computer. Humans usually aren't as good writing machine code as they
are at writing Treelang or C, because it is easy to make tiny mistakes
writing machine code. When writing Treelang or C, it is easy to make
big mistakes. But you can only make one mistake, because the compiler
stops after it finds any problem.
@cindex debugger
@cindex bugs, finding
@cindex @code{gdb}, command
@cindex commands, @code{gdb}
@item
It provides information in the generated machine code
that can make it easier to find bugs in the program
(using a debugging tool, called a @dfn{debugger},
such as @code{gdb}).
@cindex libraries
@cindex linking
@cindex @code{ld} command
@cindex commands, @code{ld}
@item
It locates and gathers machine code already generated to perform actions
requested by statements in the user's program. This machine code is
organized into @dfn{libraries} and is located and gathered during the
@dfn{link} phase of the compilation process. (Linking often is thought
of as a separate step, because it can be directly invoked via the
@code{ld} command. However, the @code{gcc} command, as with most
compiler commands, automatically performs the linking step by calling on
@code{ld} directly, unless asked to not do so by the user.)
@cindex language, incorrect use of
@cindex incorrect use of language
@item
It attempts to diagnose cases where the user's program contains
incorrect usages of the language. The @dfn{diagnostics} produced by the
compiler indicate the problem and the location in the user's source file
where the problem was first noticed. The user can use this information
to locate and fix the problem.
The compiler stops after the first error. There are no plans to fix
this, ever, as it would vastly complicate the implementation of treelang
to little or no benefit.
@cindex diagnostics, incorrect
@cindex incorrect diagnostics
@cindex error messages, incorrect
@cindex incorrect error messages
(Sometimes an incorrect usage of the language leads to a situation where
the compiler can not make any sense of what it reads---while a human
might be able to---and thus ends up complaining about an incorrect
``problem'' it encounters that, in fact, reflects a misunderstanding of
the programmer's intention.)
@cindex warnings
@cindex questionable instructions
@item
There are no warnings in treelang. A program is either correct or in
error.
@end itemize
@cindex components of treelang
@cindex @code{treelang}, components of
@code{treelang} consists of several components:
@cindex @code{gcc}, command
@cindex commands, @code{gcc}
@itemize @bullet
@item
A modified version of the @code{gcc} command, which also might be
installed as the system's @code{cc} command.
(In many cases, @code{cc} refers to the
system's ``native'' C compiler, which
might be a non-GNU compiler, or an older version
of @code{GCC} considered more stable or that is
used to build the operating system kernel.)
@cindex @code{treelang}, command
@cindex commands, @code{treelang}
@item
The @code{treelang} command itself.
@item
The @code{libc} run-time library. This library contains the machine
code needed to support capabilities of the Treelang language that are
not directly provided by the machine code generated by the
@code{treelang} compilation phase. This is the same library that the
main c compiler uses (libc).
@cindex @code{tree1}, program
@cindex programs, @code{tree1}
@cindex assembler
@cindex @code{as} command
@cindex commands, @code{as}
@cindex assembly code
@cindex code, assembly
@item
The compiler itself, is internally named @code{tree1}.
Note that @code{tree1} does not generate machine code directly---it
generates @dfn{assembly code} that is a more readable form
of machine code, leaving the conversion to actual machine code
to an @dfn{assembler}, usually named @code{as}.
@end itemize
@code{GCC} is often thought of as ``the C compiler'' only,
but it does more than that.
Based on command-line options and the names given for files
on the command line, @code{gcc} determines which actions to perform, including
preprocessing, compiling (in a variety of possible languages), assembling,
and linking.
@cindex driver, gcc command as
@cindex @code{gcc}, command as driver
@cindex executable file
@cindex files, executable
@cindex cc1 program
@cindex programs, cc1
@cindex preprocessor
@cindex cpp program
@cindex programs, cpp
For example, the command @samp{gcc foo.c} @dfn{drives} the file
@file{foo.c} through the preprocessor @code{cpp}, then
the C compiler (internally named
@code{cc1}), then the assembler (usually @code{as}), then the linker
(@code{ld}), producing an executable program named @file{a.out} (on
UNIX systems).
@cindex treelang program
@cindex programs, treelang
As another example, the command @samp{gcc foo.tree} would do much the
same as @samp{gcc foo.c}, but instead of using the C compiler named
@code{cc1}, @code{gcc} would use the treelang compiler (named
@code{tree1}). However there is no preprocessor for treelang.
@cindex @code{tree1}, program
@cindex programs, @code{tree1}
In a GNU Treelang installation, @code{gcc} recognizes Treelang source
files by name just like it does C and C++ source files. It knows to use
the Treelang compiler named @code{tree1}, instead of @code{cc1} or
@code{cc1plus}, to compile Treelang files. If a file's name ends in
@code{.tree} then GCC knows that the program is written in treelang. You
can also manually override the language.
@cindex @code{gcc}, not recognizing Treelang source
@cindex unrecognized file format
@cindex file format not recognized
Non-Treelang-related operation of @code{gcc} is generally
unaffected by installing the GNU Treelang version of @code{gcc}.
However, without the installed version of @code{gcc} being the
GNU Treelang version, @code{gcc} will not be able to compile
and link Treelang programs.
@cindex printing version information
@cindex version information, printing
The command @samp{gcc -v x.tree} where @samp{x.tree} is a file which
must exist but whose contents are ignored, is a quick way to display
version information for the various programs used to compile a typical
Treelang source file.
The @code{tree1} program represents most of what is unique to GNU
Treelang; @code{tree1} is a combination of two rather large chunks of
code.
@cindex GCC Back End (GBE)
@cindex GBE
@cindex @code{GCC}, back end
@cindex back end, GCC
@cindex code generator
One chunk is the so-called @dfn{GNU Back End}, or GBE,
which knows how to generate fast code for a wide variety of processors.
The same GBE is used by the C, C++, and Treelang compiler programs @code{cc1},
@code{cc1plus}, and @code{tree1}, plus others.
Often the GBE is referred to as the ``GCC back end'' or
even just ``GCC''---in this manual, the term GBE is used
whenever the distinction is important.
@cindex GNU Treelang Front End (TFE)
@cindex tree1
@cindex @code{treelang}, front end
@cindex front end, @code{treelang}
The other chunk of @code{tree1} is the majority of what is unique about
GNU Treelang---the code that knows how to interpret Treelang programs to
determine what they are intending to do, and then communicate that
knowledge to the GBE for actual compilation of those programs. This
chunk is called the @dfn{Treelang Front End} (TFE). The @code{cc1} and
@code{cc1plus} programs have their own front ends, for the C and C++
languages, respectively. These fronts ends are responsible for
diagnosing incorrect usage of their respective languages by the programs
the process, and are responsible for most of the warnings about
questionable constructs as well. (The GBE in principle handles
producing some warnings, like those concerning possible references to
undefined variables, but these warnings should not occur in treelang
programs as the front end is meant to pick them up first).
Because so much is shared among the compilers for various languages,
much of the behavior and many of the user-selectable options for these
compilers are similar.
For example, diagnostics (error messages and
warnings) are similar in appearance; command-line
options like @samp{-Wall} have generally similar effects; and the quality
of generated code (in terms of speed and size) is roughly similar
(since that work is done by the shared GBE).
@node TREELANG and GCC, Compiler, Compiler Overview, Top
@chapter Compile Treelang, C, or Other Programs
@cindex compiling programs
@cindex programs, compiling
@cindex @code{gcc}, command
@cindex commands, @code{gcc}
A GNU Treelang installation includes a modified version of the @code{gcc}
command.
In a non-Treelang installation, @code{gcc} recognizes C, C++,
and Objective-C source files.
In a GNU Treelang installation, @code{gcc} also recognizes Treelang source
files and accepts Treelang-specific command-line options, plus some
command-line options that are designed to cater to Treelang users
but apply to other languages as well.
@xref{G++ and GCC,,Compile C; C++; or Objective-C,GCC,Using and Porting GCC},
for information on the way different languages are handled
by the GCC compiler (@code{gcc}).
You can use this, combined with the output of the @samp{GCC -v x.tree}
command to get the options applicable to treelang. Treelang programs
must end with the suffix @samp{.tree}.
@cindex preprocessor
Treelang programs are not by default run through the C
preprocessor by @code{gcc}. There is no reason why they cannot be run through the
preprocessor manually, but you would need to prevent the preprocessor
from generating #line directives, using the @samp{-P} option, otherwise
tree1 will not accept the input.
@node Compiler, Other Languages, TREELANG and GCC, Top
@chapter The GNU Treelang Compiler
The GNU Treelang compiler, @code{treelang}, supports programs written
in the GNU Treelang language.
@node Other Languages, treelang internals, Compiler, Top
@chapter Other Languages
@menu
* Interoperating with C and C++::
@end menu
@node Interoperating with C and C++, , Other Languages, Other Languages
@section Tools and advice for interoperating with C and C++
The output of treelang programs looks like C program code to the linker
and everybody else, so you should be able to freely mix treelang and C
(and C++) code, with one proviso.
C promotes small integer types to 'int' when used as function parameters and
return values. The treelang compiler does not do this, so if you want to interface
to C, you need to specify the promoted value, not the nominal value.
@ifset INTERNALS
@node treelang internals, Open Questions, Other Languages, Top
@chapter treelang internals
@menu
* treelang files::
* treelang compiler interfaces::
* Hints and tips::
@end menu
@node treelang files, treelang compiler interfaces, treelang internals, treelang internals
@section treelang files
To create a compiler that integrates into GCC, you need create many
files. Some of the files are integrated into the main GCC makefile, to
build the various parts of the compiler and to run the test
suite. Others are incorporated into various GCC programs such as
GCC.c. Finally you must provide the actual programs comprising your
compiler.
@cindex files
The files are:
@enumerate 1
@item
COPYING. This is the copyright file, assuming you are going to use the
GNU General Public Licence. You probably need to use the GPL because if
you use the GCC back end your program and the back end are one program,
and the back end is GPLed.
This need not be present if the language is incorporated into the main
GCC tree, as the main GCC directory has this file.
@item
COPYING.LIB. This is the copyright file for those parts of your program
that are not to be covered by the GPL, but are instead to be covered by
the LGPL (Library or Lesser GPL). This licence may be appropriate for
the library routines associated with your compiler. These are the
routines that are linked with the @emph{output} of the compiler. Using
the LGPL for these programs allows programs written using your compiler
to be closed source. For example LIBC is under the LGPL.
This need not be present if the language is incorporated into the main
GCC tree, as the main GCC directory has this file.
@item
ChangeLog. Record all the changes to your compiler. Use the same format
as used in treelang as it is supported by an emacs editing mode and is
part of the FSF coding standard. Normally each directory has its own
changelog. The FSF standard allows but does not require a meaningful
comment on why the changes were made, above and beyond @emph{why} they
were made. In the author's opinion it is useful to provide this
information.
@item
treelang.texi. The manual, written in texinfo. Your manual would have a
different file name. You need not write it in texinfo if you don't want
do, but a lot of GNU software does use texinfo.
@cindex Make-lang.in
@item
Make-lang.in. This file is part of the make file which in incorporated
with the GCC make file skeleton (Makefile.in in the GCC directory) to
make Makefile, as part of the configuration process.
Makefile in turn is the main instruction to actually build
everything. The build instructions are held in the main GCC manual and
web site so they are not repeated here.
There are some comments at the top which will help you understand what
you need to do.
There are make commands to build things, remove generated files with
various degrees of thoroughness, count the lines of code (so you know
how much progress you are making), build info and html files from the
texinfo source, run the tests etc.
@item
README. Just a brief informative text file saying what is in this
directory.
@cindex config-lang.in
@item
config-lang.in. This file is read by the configuration progress and must
be present. You specify the name of your language, the name(s) of the
compiler(s) incouding preprocessors you are going to build, whether any,
usually generated, files should be excluded from diffs (ie when making
diff files to send in patches). Whether the equate 'stagestuff' is used
is unknown (???).
@cindex lang-options
@item
lang-options. This file is included into GCC.c, the main GCC driver, and
tells it what options your language supports. This is only used to
display help (is this true ???).
@cindex lang-specs
@item
lang-specs. This file is also included in GCC.c. It tells GCC.c when to
call your programs and what options to send them. The mini-language
'specs' is documented in the source of GCC.c. Do not attempt to write a
specs file from scratch - use an existing one as the base and enhance
it.
@item
Your texi files. Texinfo can be used to build documentation in HTML,
info, dvi and postscript formats. It is a tagged language, is documented
in its own manual, and has its own emacs mode.
@item
Your programs. The relationships between all the programs are explained
in the next section. You need to write or use the following programs:
@itemize @bullet
@item
lexer. This breaks the input into words and passes these to the
parser. This is lex.l in treelang, which is passed through flex, a lex
variant, to produce C code lex.c. Note there is a school of thought that
says real men hand code their own lexers, however you may prefer to
write far less code and use flex, as was done with treelang.
@item
parser. This breaks the program into recognizable constructs such as
expressions, statements etc. This is parse.y in treelang, which is
passed through bison, which is a yacc variant, to produce C code parse.c.
@item
back end interface. This interfaces to the code generation back end. In
treelang, this is tree1.c which mainly interfaces to toplev.c and
treetree.c which mainly interfaces to everything else. Many languages
mix up the back end interface with the parser, as in the C compiler for
example. It is a matter of taste which way to do it, but with treelang
it is separated out to make the back end interface cleaner and easier to
understand.
@item
header files. For function prototypes and common data items. One point
to note here is that bison can generate a header files with all the
numbers is has assigned to the keywords and symbols, and you can include
the same header in your lexer. This technique is demonstrated in
treelang.
@item
compiler main file. GCC comes with a program toplev.c which is a
perfectly serviceable main program for your compiler. treelang uses
toplev.c but other languages have been known to replace it with their
own main program. Again this is a matter of taste and how much code you
want to write.
@end itemize
@end enumerate
@node treelang compiler interfaces, Hints and tips, treelang files, treelang internals
@section treelang compiler interfaces
@cindex driver
@cindex toplev.c
@menu
* treelang driver::
* treelang main compiler::
@end menu
@node treelang driver, treelang main compiler, treelang compiler interfaces, treelang compiler interfaces
@subsection treelang driver
The GCC compiler consists of a driver, which then executes the various
compiler phases based on the instructions in the specs files.
Typically a program's language will be identified from its suffix (eg
.tree) for treelang programs.
The driver (gcc.c) will then drive (exec) in turn a preprocessor, the main
compiler, the assembler and the link editor. Options to GCC allow you to
override all of this. In the case of treelang programs there is no
preprocessor, and mostly these days the C preprocessor is run within the
main C compiler rather than as a separate process, apparently for reasons of speed.
You will be using the standard assembler and linkage editor so these are
ignored from now on.
You have to write your own preprocessor if you want one. This is usually
totally language specific. The main point to be aware of is to ensure
that you find some way to pass file name and line number information
through to the main compiler so that it can tell the back end this
information and so the debugger can find the right source line for each
piece of code. That is all there is to say about the preprocessor except
that the preprocessor will probably not be the slowest part of the
compiler and will probably not use the most memory so don't waste too
much time tuning it until you know you need to do so.
@node treelang main compiler, , treelang driver, treelang compiler interfaces
@subsection treelang main compiler
The main compiler for treelang consists of toplev.c from the main GCC
compiler, the parser, lexer and back end interface routines, and the
back end routines themselves, of which there are many.
toplev.c does a lot of work for you and you should almost certainly use it,
Writing this code is the hard part of creating a compiler using GCC. The
back end interface documentation is incomplete and the interface is
complex.
There are three main aspects to interfacing to the other GCC code.
@menu
* Interfacing to toplev.c::
* Interfacing to the garbage collection::
* Interfacing to the code generation code. ::
@end menu
@node Interfacing to toplev.c, Interfacing to the garbage collection, treelang main compiler, treelang main compiler
@subsubsection Interfacing to toplev.c
In treelang this is handled mainly in tree1.c
and partly in treetree.c. Peruse toplev.c for details of what you need
to do.
@node Interfacing to the garbage collection, Interfacing to the code generation code. , Interfacing to toplev.c, treelang main compiler
@subsubsection Interfacing to the garbage collection
Interfacing to the garbage collection. In treelang this is mainly in
tree1.c.
Memory allocation in the compiler should be done using the ggc_alloc and
kindred routines in ggc*.*. At the end of every 'function' in your language, toplev.c calls
the garbage collection several times. The garbage collection calls mark
routines which go through the memory which is still used, telling the
garbage collection not to free it. Then all the memory not used is
freed.
What this means is that you need a way to hook into this marking
process. This is done by calling ggc_add_root. This provides the address
of a callback routine which will be called duing garbage collection and
which can call ggc_mark to save the storage. If storage is only
used within the parsing of a function, you do not need to provide a way
to mark it.
Note that you can also call ggc_mark_tree to mark any of the back end
internal 'tree' nodes. This routine will follow the branches of the
trees and mark all the subordinate structures. This is useful for
example when you have created a variable declaaration that will be used
across multiple functions, or for a function declaration (from a
prototype) that may be used later on. See the next item for more on the
tree nodes.
@node Interfacing to the code generation code. , , Interfacing to the garbage collection, treelang main compiler
@subsubsection Interfacing to the code generation code.
In treelang this is done in treetree.c. A typedef called 'tree' which is
defined in tree.h and tree.def in the GCC directory and largely
implemented in tree.c and stmt.c forms the basic interface to the
compiler back end.
In general you call various tree routines to generate code, either
directly or through toplev.c. You build up data structures and
expressions in similar ways.
You can read some documentation on this which can be found via the GCC
main web page. In particular, the documentation produced by Joachim
Nadler and translated by Tim Josling can be quite useful. the C compiler
also has documentation in the main GCC manual (particularly the current
CVS version) which is useful on a lot of the details.
In time it is hoped to enhance this document to provide a more
comprehensive overview of this topic. The main gap is in explaining how
it all works together.
@node Hints and tips, , treelang compiler interfaces, treelang internals
@section Hints and tips
@itemize @bullet
@item
TAGS: Use the make ETAGS commands to create TAGS files which can be used in
emacs to jump to any symbol quickly.
@item
GREP: grep is also a useful way to find all uses of a symbol.
@item
TREE: The main routines to look at are tree.h and tree.def. You will
probably want a hardcopy of these.
@item
SAMPLE: look at the sample interfacing code in treetree.c. You can use
gdb to trace through the code and learn about how it all works.
@item
GDB: the GCC back end works well with gdb. It traps abort() and allows
you to trace back what went wrong.
@item
Error Checking: The compiler back end does some error and consistency
checking. Often the result of an error is just no code being
generated. You will then need to trace through and find out what is
going wrong. The rtl dump files can help here also.
@item
rtl dump files: The main compiler documents these files which are dumps
of the rtl (intermediate code) which is manipulated doing the code
generation process. This can provide useful clues about what is going
wrong. The rtl 'language' is documented in the main GCC manual.
@end itemize
@end ifset
@node Open Questions, Bugs, treelang internals, Top
@chapter Open Questions
If you know GCC well, please consider looking at the file treetree.c and
resolving any questions marked "???".
@node Bugs, Service, Open Questions, Top
@chapter Reporting Bugs
@cindex bugs
@cindex reporting bugs
You can report bugs to @email{@value{email-bugs}}. Please make
sure bugs are real before reporting them. Follow the guidelines in the
main GCC manual for submitting bug reports.
@menu
* Sending Patches::
@end menu
@node Sending Patches, , Bugs, Bugs
@section Sending Patches for GNU Treelang
If you would like to write bug fixes or improvements for the GNU
Treelang compiler, that is very helpful. Send suggested fixes to
@email{@value{email-patches}}.
@node Service, Projects, Bugs, Top
@chapter How To Get Help with GNU Treelang
If you need help installing, using or changing GNU Treelang, there are two
ways to find it:
@itemize @bullet
@item
Look in the service directory for someone who might help you for a fee.
The service directory is found in the file named @file{SERVICE} in the
GCC distribution.
@item
Send a message to @email{@value{email-general}}.
@end itemize
@end ifset
@ifset INTERNALS
@node Projects, Index, Service, Top
@chapter Projects
@cindex projects
If you want to contribute to @code{treelang} by doing research,
design, specification, documentation, coding, or testing,
the following information should give you some ideas.
Send a message to @email{@value{email-general}} if you plan to add a
feature.
The main requirement for treelang is to add features and to add
documentation. Features are things that the GCC back end can do but
which are not reflected in treelang. Examples include structures,
unions, pointers, arrays.
@end ifset
@node Index, , Projects, Top
@unnumbered Index
@printindex cp
@summarycontents
@contents
@bye
/*
TREELANG Compiler back end interface (treetree.c)
Called by the parser.
If you want a working example of how to write a front end to GCC,
you are in the right place.
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
2001, 2002 Free Software Foundation, Inc.
This code is based on toy.c written by Richard Kenner.
It was later modified by Jonathan Bartlett whose changes have all
been removed (by Tim Josling).
Various bits and pieces were cloned from the GCC main tree, as
GCC evolved, for COBOLForGCC, by Tim Josling.
It was adapted to TREELANG by Tim Josling 2001.
---------------------------------------------------------------------------
This program 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 2, or (at your option) any
later version.
This program 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 this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding!
---------------------------------------------------------------------------
*/
/*
Assumption: garbage collection is never called implicitly. It will
not be called 'at any time' when short of memory. It will only be
called explicitly at the end of each function. This removes the
need for a *lot* of bother to ensure everything is in the mark trees
at all times. */
/* Note it is OK to use GCC extensions such as long long in a compiler front end.
This is because the GCC front ends are built using GCC. */
/* Standard/OS headers. */
#include <stdlib.h>
#include <unistd.h>
#include "safe-ctype.h"
#include <errno.h>
#include <stdarg.h>
#include <limits.h>
#include <string.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
/* GCC headers. */
#include "ansidecl.h"
#include "config.h"
#include "system.h"
#include "tree.h"
#include "flags.h"
#include "output.h"
#include "c-lex.h"
#include "c-tree.h"
#include "rtl.h"
#include "tm_p.h"
#include "ggc.h"
#include "toplev.h"
#include "varray.h"
#include "langhooks-def.h"
#include "langhooks.h"
#include "treetree.h"
extern int option_main;
extern char **file_names;
/* Flags etc required by c code. */
int warn_format = 0;
int warn_format_y2k = 0;
int warn_format_extra_args = 0;
int warn_format_nonliteral = 0;
int warn_format_security = 0;
/* The front end language hooks (addresses of code for this front
end). Mostly just use the C routines. */
#undef LANG_HOOKS_TRUTHVALUE_CONVERSION
#define LANG_HOOKS_TRUTHVALUE_CONVERSION c_common_truthvalue_conversion
#undef LANG_HOOKS_MARK_ADDRESSABLE
#define LANG_HOOKS_MARK_ADDRESSABLE c_mark_addressable
#undef LANG_HOOKS_SIGNED_TYPE
#define LANG_HOOKS_SIGNED_TYPE c_common_signed_type
#undef LANG_HOOKS_UNSIGNED_TYPE
#define LANG_HOOKS_UNSIGNED_TYPE c_common_unsigned_type
#undef LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE
#define LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE c_common_signed_or_unsigned_type
#undef LANG_HOOKS_TYPE_FOR_MODE
#define LANG_HOOKS_TYPE_FOR_MODE c_common_type_for_mode
#undef LANG_HOOKS_TYPE_FOR_SIZE
#define LANG_HOOKS_TYPE_FOR_SIZE c_common_type_for_size
#undef LANG_HOOKS_PARSE_FILE
#define LANG_HOOKS_PARSE_FILE treelang_parse_file
/* Hook routines and data unique to treelang. */
#undef LANG_HOOKS_INIT
#define LANG_HOOKS_INIT treelang_init
#undef LANG_HOOKS_NAME
#define LANG_HOOKS_NAME "GNU treelang"
#undef LANG_HOOKS_FINISH
#define LANG_HOOKS_FINISH treelang_finish
#undef LANG_HOOKS_DECODE_OPTION
#define LANG_HOOKS_DECODE_OPTION treelang_decode_option
const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
/* Tree code type/name/code tables. */
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
const char tree_code_type[] = {
#include "tree.def"
'x'
};
#undef DEFTREECODE
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
const unsigned char tree_code_length[] = {
#include "tree.def"
0
};
#undef DEFTREECODE
#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
const char *const tree_code_name[] = {
#include "tree.def"
"@@dummy"
};
#undef DEFTREECODE
/* Number of bits in int and char - accessed by front end. */
unsigned int tree_code_int_size = 0;
unsigned int tree_code_char_size = 0;
/* In this case there is very little to keep between functions - we
keep the symbol table only and the things that hang off that - see
tree1.c. Garbage collection is only invoked when we call
rest_of_compilation at the end of a function. */
#define ADDROOT(where) ggc_add_root (&where, 1, /* Unused size. */ sizeof (void*), \
tree_ggc_storage_always_used);
/* Return the tree stuff for this type TYPE_NUM. */
tree
tree_code_get_type (int type_num)
{
switch (type_num)
{
case SIGNED_CHAR:
return signed_char_type_node;
case UNSIGNED_CHAR:
return unsigned_char_type_node;
case SIGNED_INT:
return integer_type_node;
case UNSIGNED_INT:
return unsigned_type_node;
case VOID_TYPE:
return void_type_node;
default:
abort ();
}
}
/* Output the code for the start of an if statement. The test
expression is EXP (true if not zero), and the stmt occurred at line
LINENO in file FILENAME. */
void
tree_code_if_start (tree exp, unsigned char* filename, int lineno)
{
tree cond_exp;
cond_exp = build (NE_EXPR,
TREE_TYPE (exp),
exp,
build1 (CONVERT_EXPR, TREE_TYPE (exp), integer_zero_node));
emit_line_note ((const char *)filename, lineno); /* Output the line number information. */
expand_start_cond (cond_exp, /* Exit-able if non zero. */ 0);
}
/* Output the code for the else of an if statement. The else occurred
at line LINENO in file FILENAME. */
void
tree_code_if_else (unsigned char* filename, int lineno)
{
emit_line_note ((const char *)filename, lineno); /* Output the line number information. */
expand_start_else ();
}
/* Output the code for the end_if an if statement. The end_if (final brace) occurred
at line LINENO in file FILENAME. */
void
tree_code_if_end (unsigned char* filename, int lineno)
{
emit_line_note ((const char *)filename, lineno); /* Output the line number information. */
expand_end_cond ();
}
/* Create a function. The prototype name is NAME, storage class is
STORAGE_CLASS, type of return variable is RET_TYPE, parameter lists
is PARMS, returns decl for this function. */
tree
tree_code_create_function_prototype (unsigned char* chars,
unsigned int storage_class,
unsigned int ret_type,
struct tree_parameter_list* parms,
unsigned char* filename,
int lineno)
{
tree id;
struct tree_parameter_list* parm;
tree type_list = NULL_TREE;
tree type_node;
tree fn_type;
tree fn_decl;
/* Build the type. */
id = get_identifier ((const char*)chars);
for (parm = parms; parm; parm = parm->next)
{
type_node = get_type_for_numeric_type (parm->type);
type_list = tree_cons (NULL_TREE, type_node, type_list);
}
/* Last parm if null indicates fixed length list (as opposed to
printf style va_* list). */
type_list = tree_cons (NULL_TREE, void_type_node, type_list);
/* The back end needs them in reverse order. */
type_list = nreverse (type_list);
type_node = get_type_for_numeric_type (ret_type);
fn_type = build_function_type (type_node, type_list);
id = get_identifier ((const char*)chars);
fn_decl = build_decl (FUNCTION_DECL, id, fn_type);
DECL_CONTEXT (fn_decl) = NULL_TREE; /* Nested functions not supported here. */
DECL_SOURCE_FILE (fn_decl) = (const char *)filename;
/* if (lineno > 1000000)
; */ /* Probably the line # is rubbish because someone forgot to set
the line number - and unfortunately impossible line #s are used as
magic flags at various times. The longest known function for
example is about 550,000 lines (it was written in COBOL). */
DECL_SOURCE_LINE (fn_decl) = lineno;
TREE_USED (fn_decl) = 1;
/* Real name (optional). */
SET_DECL_ASSEMBLER_NAME (fn_decl, DECL_NAME (fn_decl));
TREE_PUBLIC (fn_decl) = 0;
DECL_EXTERNAL (fn_decl) = 0;
TREE_STATIC (fn_decl) = 0;
switch (storage_class)
{
case STATIC_STORAGE:
TREE_PUBLIC (fn_decl) = 0;
break;
case EXTERNAL_DEFINITION_STORAGE:
TREE_PUBLIC (fn_decl) = 1;
TREE_STATIC (fn_decl) = 0;
DECL_EXTERNAL (fn_decl) = 0;
break;
case EXTERNAL_REFERENCE_STORAGE:
TREE_PUBLIC (fn_decl) = 0;
DECL_EXTERNAL (fn_decl) = 1;
break;
case AUTOMATIC_STORAGE:
default:
abort ();
}
/* Process declaration of function defined elsewhere. */
rest_of_decl_compilation (fn_decl, NULL, 1, 0);
return fn_decl;
}
/* Output code for start of function; the decl of the function is in
PREV_SAVED (as created by tree_code_create_function_prototype),
the function is at line number LINENO in file FILENAME. The
parameter details are in the lists PARMS. Returns nothing. */
void
tree_code_create_function_initial (tree prev_saved,
unsigned char* filename,
int lineno,
struct tree_parameter_list* parms)
{
tree fn_decl;
tree param_decl;
tree next_param;
tree first_param;
tree parm_decl;
tree parm_list;
tree resultdecl;
struct tree_parameter_list* this_parm;
struct tree_parameter_list* parm;
fn_decl = prev_saved;
if (!fn_decl)
abort ();
/* Output message if not -quiet. */
announce_function (fn_decl);
/* This has something to do with forcing output also. */
pushdecl (fn_decl);
/* Set current function for error msgs etc. */
current_function_decl = fn_decl;
DECL_INITIAL (fn_decl) = error_mark_node;
DECL_SOURCE_FILE (fn_decl) = (const char *)filename;
DECL_SOURCE_LINE (fn_decl) = lineno;
/* Prepare creation of rtl for a new function. */
resultdecl = DECL_RESULT (fn_decl) = build_decl (RESULT_DECL, NULL_TREE, TREE_TYPE (TREE_TYPE (fn_decl)));
DECL_CONTEXT (DECL_RESULT (fn_decl)) = fn_decl;
DECL_SOURCE_FILE (resultdecl) = (const char *)filename;
DECL_SOURCE_LINE (resultdecl) = lineno;
/* Work out the size. ??? is this needed. */
layout_decl (DECL_RESULT (fn_decl), 0);
/* Make the argument variable decls. */
parm_list = NULL_TREE;
for (parm = parms; parm; parm = parm->next)
{
parm_decl = build_decl (PARM_DECL, get_identifier ((const char*) (parm->variable_name)),
get_type_for_numeric_type (parm->type));
/* Some languages have different nominal and real types. */
DECL_ARG_TYPE (parm_decl) = TREE_TYPE (parm_decl);
if (!DECL_ARG_TYPE (parm_decl))
abort ();
if (!fn_decl)
abort ();
DECL_CONTEXT (parm_decl) = fn_decl;
DECL_SOURCE_FILE (parm_decl) = (const char *)filename;
DECL_SOURCE_LINE (parm_decl) = lineno;
parm_list = chainon (parm_decl, parm_list);
}
/* Back into reverse order as the back end likes them. */
parm_list = nreverse (parm_list);
DECL_ARGUMENTS (fn_decl) = parm_list;
/* Save the decls for use when the args are referred to. */
for (param_decl = DECL_ARGUMENTS (fn_decl),
this_parm = parms;
param_decl;
param_decl = TREE_CHAIN (param_decl),
this_parm = this_parm->next)
{
if (!this_parm)
abort (); /* Too few. */
*this_parm->where_to_put_var_tree = param_decl;
}
if (this_parm)
abort (); /* Too many. */
/* Output the decl rtl (not the rtl for the function code). ???.
If the function is not defined in this file, when should you
execute this? */
make_decl_rtl (fn_decl, NULL);
/* Use filename/lineno from above. */
init_function_start (fn_decl, (const char *)filename, lineno);
/* Create rtl for startup code of function, such as saving registers. */
expand_function_start (fn_decl, 0);
/* Function.c requires a push at the start of the function. that
looks like a bug to me but let's make it happy. */
(*lang_hooks.decls.pushlevel) (0);
/* Create rtl for the start of a new scope. */
expand_start_bindings (2);
/* Put the parameters into the symbol table. */
for (first_param = param_decl = nreverse (DECL_ARGUMENTS (fn_decl));
param_decl;
param_decl = next_param)
{
next_param = TREE_CHAIN (param_decl);
TREE_CHAIN (param_decl) = NULL;
/* layout_decl (param_decl, 0); Already done in build_decl tej 13/4/2002. */
pushdecl (param_decl);
if (DECL_CONTEXT (param_decl) != current_function_decl)
abort ();
}
/* Store back the PARM_DECL nodes. They appear in the right order. */
DECL_ARGUMENTS (fn_decl) = getdecls ();
/* Force it to be output, else may be solely inlined. */
TREE_ADDRESSABLE (fn_decl) = 1;
/* Stop -O3 from deleting it. */
TREE_USED (fn_decl) = 1;
/* Add a new level to the debugger symbol table. */
(*lang_hooks.decls.pushlevel) (0);
/* Create rtl for the start of a new scope. */
expand_start_bindings (0);
emit_line_note ((const char *)filename, lineno); /* Output the line number information. */
}
/* Wrapup a function contained in file FILENAME, ending at line LINENO. */
void
tree_code_create_function_wrapup (unsigned char* filename,
int lineno)
{
tree block;
tree fn_decl;
fn_decl = current_function_decl;
emit_line_note ((const char *)filename, lineno); /* Output the line number information. */
/* Get completely built level from debugger symbol table. */
block = (*lang_hooks.decls.poplevel) (1, 0, 0);
/* Emit rtl for end of scope. */
expand_end_bindings (block, 0, 1);
/* Emit rtl for end of function. */
expand_function_end ((const char *)filename, lineno, 0);
/* Pop the level. */
block = (*lang_hooks.decls.poplevel) (1, 0, 1);
/* And attach it to the function. */
DECL_INITIAL (fn_decl) = block;
/* Emit rtl for end of scope. */
expand_end_bindings (block, 0, 1);
/* Call optimization and convert optimized rtl to assembly code. */
rest_of_compilation (fn_decl);
/* We are not inside of any scope now. */
current_function_decl = NULL_TREE;
}
/*
Create a variable.
The storage class is STORAGE_CLASS (eg LOCAL).
The name is CHARS/LENGTH.
The type is EXPRESSION_TYPE (eg UNSIGNED_TYPE).
The init tree is INIT.
*/
tree
tree_code_create_variable (unsigned int storage_class,
unsigned char* chars,
unsigned int length,
unsigned int expression_type,
tree init,
unsigned char* filename,
int lineno)
{
tree var_type;
tree var_id;
tree var_decl;
/* 1. Build the type. */
var_type = get_type_for_numeric_type (expression_type);
/* 2. Build the name. */
if (chars[length] != 0)
abort (); /* Should be null terminated. */
var_id = get_identifier ((const char*)chars);
/* 3. Build the decl and set up init. */
var_decl = build_decl (VAR_DECL, var_id, var_type);
/* 3a. Initialization. */
if (init)
DECL_INITIAL (var_decl) = build1 (CONVERT_EXPR, var_type, init);
else
DECL_INITIAL (var_decl) = NULL_TREE;
/* 4. Compute size etc. */
layout_decl (var_decl, 0);
if (TYPE_SIZE (var_type) == 0)
abort (); /* Did not calculate size. */
DECL_CONTEXT (var_decl) = current_function_decl;
DECL_SOURCE_FILE (var_decl) = (const char *)filename;
DECL_SOURCE_LINE (var_decl) = lineno;
/* Set the storage mode and whether only visible in the same file. */
switch (storage_class)
{
case STATIC_STORAGE:
TREE_STATIC (var_decl) = 1;
TREE_PUBLIC (var_decl) = 0;
break;
case AUTOMATIC_STORAGE:
TREE_STATIC (var_decl) = 0;
TREE_PUBLIC (var_decl) = 0;
break;
case EXTERNAL_DEFINITION_STORAGE:
TREE_STATIC (var_decl) = 0;
TREE_PUBLIC (var_decl) = 1;
break;
case EXTERNAL_REFERENCE_STORAGE:
DECL_EXTERNAL (var_decl) = 1;
TREE_PUBLIC (var_decl) = 0;
break;
default:
abort ();
}
/* This should really only be set if the variable is used. */
TREE_USED (var_decl) = 1;
/* Expand declaration and initial value if any. */
if (TREE_STATIC (var_decl))
rest_of_decl_compilation (var_decl, 0, 0, 0);
else
{
expand_decl (var_decl);
if (DECL_INITIAL (var_decl))
expand_decl_init (var_decl);
}
return pushdecl (copy_node (var_decl));
}
/* Generate code for return statement. Type is in TYPE, expression
is in EXP if present. */
void
tree_code_generate_return (tree type, tree exp)
{
tree setret;
tree param;
for (param = DECL_ARGUMENTS (current_function_decl);
param;
param = TREE_CHAIN (param))
{
if (DECL_CONTEXT (param) != current_function_decl)
abort ();
}
if (exp)
{
setret = build (MODIFY_EXPR, type, DECL_RESULT (current_function_decl),
build1 (CONVERT_EXPR, type, exp));
TREE_SIDE_EFFECTS (setret) = 1;
TREE_USED (setret) = 1;
expand_expr_stmt (setret);
}
expand_return (DECL_RESULT (current_function_decl));
}
/* Output the code for this expression statement CODE. */
void
tree_code_output_expression_statement (tree code,
unsigned char* filename, int lineno)
{
/* Output the line number information. */
emit_line_note ((const char *)filename, lineno);
TREE_USED (code) = 1;
TREE_SIDE_EFFECTS (code) = 1;
expand_expr_stmt (code);
}
/* Return a tree for a constant integer value in the token TOK. No
size checking is done. */
tree
tree_code_get_integer_value (unsigned char* chars, unsigned int length)
{
long long int val = 0;
unsigned int ix;
unsigned int start = 0;
int negative = 1;
switch (chars[0])
{
case (unsigned char)'-':
negative = -1;
start = 1;
break;
case (unsigned char)'+':
start = 1;
break;
default:
break;
}
for (ix = start; ix < length; ix++)
val = val * 10 + chars[ix] - (unsigned char)'0';
val = val*negative;
return build_int_2 (val & 0xffffffff, (val >> 32) & 0xffffffff);
}
/* Return the tree for an expresssion, type EXP_TYPE (see treetree.h)
with tree type TYPE and with operands1 OP1, OP2 (maybe), OP3 (maybe). */
tree
tree_code_get_expression (unsigned int exp_type,
tree type, tree op1, tree op2, tree op3 ATTRIBUTE_UNUSED)
{
tree ret1;
int operator;
switch (exp_type)
{
case EXP_ASSIGN:
if (!op1 || !op2)
abort ();
operator = MODIFY_EXPR;
ret1 = build (operator, type,
op1,
build1 (CONVERT_EXPR, type, op2));
break;
case EXP_PLUS:
operator = PLUS_EXPR;
goto binary_expression;
case EXP_MINUS:
operator = MINUS_EXPR;
goto binary_expression;
case EXP_EQUALS:
operator = EQ_EXPR;
goto binary_expression;
/* Expand a binary expression. Ensure the operands are the right type. */
binary_expression:
if (!op1 || !op2)
abort ();
ret1 = build (operator, type,
build1 (CONVERT_EXPR, type, op1),
build1 (CONVERT_EXPR, type, op2));
break;
/* Reference to a variable. This is dead easy, just return the
decl for the variable. If the TYPE is different than the
variable type, convert it. */
case EXP_REFERENCE:
if (!op1)
abort ();
if (type == TREE_TYPE (op1))
ret1 = op1;
else
ret1 = build1 (CONVERT_EXPR, type, op1);
break;
case EXP_FUNCTION_INVOCATION:
if (!op1 || !op2)
abort ();
{
tree fun_ptr;
fun_ptr = build1 (ADDR_EXPR, build_pointer_type (type), op1);
ret1 = build (CALL_EXPR, type, fun_ptr, nreverse (op2));
}
break;
default:
abort ();
}
return ret1;
}
/* Init parameter list and return empty list. */
tree
tree_code_init_parameters (void)
{
return NULL_TREE;
}
/* Add a parameter EXP whose expression type is EXP_PROTO to list
LIST, returning the new list. */
tree
tree_code_add_parameter (tree list, tree proto_exp, tree exp)
{
tree new_exp;
new_exp = tree_cons (NULL_TREE,
build1 (CONVERT_EXPR, TREE_TYPE (proto_exp), exp),
NULL_TREE);
if (!list)
return new_exp;
return chainon (new_exp, list);
}
/* Get the tree type for this type whose number is NUMERIC_TYPE. */
tree
get_type_for_numeric_type (unsigned int numeric_type)
{
int size1;
int sign1;
switch (numeric_type)
{
case VOID_TYPE:
return void_type_node;
case SIGNED_INT:
size1 = tree_code_int_size;
sign1 = 1;
break;
case UNSIGNED_INT:
size1 = tree_code_int_size;
sign1 = 0;
break;
case SIGNED_CHAR:
size1 = tree_code_char_size;
sign1 = 1;
break;
case UNSIGNED_CHAR:
size1 = tree_code_char_size;
sign1 = 0;
break;
default:
abort ();
}
return tree_code_get_numeric_type (size1, sign1);
}
/* Return tree representing a numeric type of size SIZE1 bits and
signed if SIGN1 != 0. */
tree
tree_code_get_numeric_type (unsigned int size1, unsigned int sign1)
{
tree ret1;
if (size1 == tree_code_int_size)
{
if (sign1)
ret1 = integer_type_node;
else
ret1 = unsigned_type_node;
}
else
if (size1 == tree_code_char_size)
{
if (sign1)
ret1 = signed_char_type_node;
else
ret1 = unsigned_char_type_node;
}
else
abort ();
return ret1;
}
/* Garbage Collection. */
/* Callback to mark storage M as used always. */
void
tree_ggc_storage_always_used (void * m)
{
void **mm; /* Actually M is a pointer to a pointer to the memory. */
mm = (void**)m;
if (*mm)
ggc_mark (*mm);
}
/* Following from c-lang.c. */
/* Tell the c code we are not objective C. */
int
maybe_objc_comptypes (tree lhs ATTRIBUTE_UNUSED,
tree rhs ATTRIBUTE_UNUSED,
int reflexive ATTRIBUTE_UNUSED)
{
return -1;
}
/* Used by c-typeck.c (build_external_ref), but only for objc. */
tree
lookup_objc_ivar (tree id ATTRIBUTE_UNUSED)
{
return 0;
}
/* Dummy routines called from c code. Save copying c-decl.c, c-common.c etc. */
void
check_function_format (int *status ATTRIBUTE_UNUSED,
tree attrs ATTRIBUTE_UNUSED,
tree params ATTRIBUTE_UNUSED)
{
return;
}
/* Tell the c code we are not objective C. */
tree
maybe_building_objc_message_expr ()
{
return 0;
}
/* Should not be called for treelang. */
tree
build_stmt VPARAMS ((enum tree_code code ATTRIBUTE_UNUSED, ...))
{
abort ();
}
/* Should not be called for treelang. */
tree
add_stmt (tree t ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
tree
build_return_stmt (tree expr ATTRIBUTE_UNUSED)
{
abort ();
}
/* C warning, ignore. */
void
pedwarn_c99 VPARAMS ((const char *msgid ATTRIBUTE_UNUSED, ...))
{
return;
}
/* Should not be called for treelang. */
tree
build_case_label (tree low_value ATTRIBUTE_UNUSED,
tree high_value ATTRIBUTE_UNUSED,
tree label_decl ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
void
emit_local_var (tree decl ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
void
expand_stmt (tree t ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
cpp_reader *
cpp_create_reader (enum c_lang lang ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
void
cpp_post_options (cpp_reader *pfile ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
void
cpp_preprocess_file (cpp_reader *pfile ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
const char *
init_c_lex (const char *filename ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
void init_pragma (void);
void
init_pragma ()
{
abort ();
}
/* Should not be called for treelang. */
void
cpp_finish (cpp_reader *pfile ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
unsigned int
cpp_errors (cpp_reader *pfile ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
tree
handle_format_attribute (tree *node ATTRIBUTE_UNUSED,
tree name ATTRIBUTE_UNUSED,
tree args ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED,
bool *no_add_attrs ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
tree
handle_format_arg_attribute (tree *node ATTRIBUTE_UNUSED,
tree name ATTRIBUTE_UNUSED,
tree args ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED,
bool *no_add_attrs ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
int
cpp_handle_option (cpp_reader *pfile ATTRIBUTE_UNUSED,
int argc ATTRIBUTE_UNUSED,
char **argv ATTRIBUTE_UNUSED,
int ignore ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
void
set_Wformat (int setting ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
void
maybe_objc_check_decl (tree decl ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
void
gen_aux_info_record (tree fndecl ATTRIBUTE_UNUSED,
int is_definition ATTRIBUTE_UNUSED,
int is_implicit ATTRIBUTE_UNUSED,
int is_prototyped ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang, but it is. */
void
c_parse_init ()
{
return;
}
/* Should not be called for treelang. */
void maybe_apply_pragma_weak (tree decl);
void
maybe_apply_pragma_weak (tree decl ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
void
add_decl_stmt (tree decl ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
tree
maybe_apply_renaming_pragma (tree decl, tree asmname);
/* Should not be called for treelang. */
tree
maybe_apply_renaming_pragma (tree decl ATTRIBUTE_UNUSED, tree asmname ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
void
begin_stmt_tree (tree *t ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
void
finish_stmt_tree (tree *t ATTRIBUTE_UNUSED)
{
abort ();
}
/* Should not be called for treelang. */
int
defer_fn (tree fn ATTRIBUTE_UNUSED)
{
abort ();
}
/* Create the predefined scalar types of C,
and some nodes representing standard constants (0, 1, (void *) 0).
Initialize the global binding level.
Make definitions for built-in primitive functions. */
/* `unsigned long' is the standard type for sizeof.
Note that stddef.h uses `unsigned long',
and this must agree, even if long and int are the same size. */
/* This variable keeps a table for types for each precision so that we
only allocate each of them once. Signed and unsigned types are
kept separate. */
tree integer_types[itk_none] = { NULL_TREE};
/* The reserved keyword table. */
struct resword
{
const char *word;
ENUM_BITFIELD(rid) rid : 16;
unsigned int disable : 16;
};
static const struct resword reswords[] =
{
{ "_Bool", RID_BOOL, 0 },
{ "_Complex", RID_COMPLEX, 0 },
{ "__FUNCTION__", RID_FUNCTION_NAME, 0 },
{ "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 },
{ "__alignof", RID_ALIGNOF, 0 },
{ "__alignof__", RID_ALIGNOF, 0 },
{ "__asm", RID_ASM, 0 },
{ "__asm__", RID_ASM, 0 },
{ "__attribute", RID_ATTRIBUTE, 0 },
{ "__attribute__", RID_ATTRIBUTE, 0 },
{ "__bounded", RID_BOUNDED, 0 },
{ "__bounded__", RID_BOUNDED, 0 },
{ "__builtin_choose_expr", RID_CHOOSE_EXPR, 0 },
{ "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, 0 },
{ "__builtin_va_arg", RID_VA_ARG, 0 },
{ "__complex", RID_COMPLEX, 0 },
{ "__complex__", RID_COMPLEX, 0 },
{ "__const", RID_CONST, 0 },
{ "__const__", RID_CONST, 0 },
{ "__extension__", RID_EXTENSION, 0 },
{ "__func__", RID_C99_FUNCTION_NAME, 0 },
{ "__imag", RID_IMAGPART, 0 },
{ "__imag__", RID_IMAGPART, 0 },
{ "__inline", RID_INLINE, 0 },
{ "__inline__", RID_INLINE, 0 },
{ "__label__", RID_LABEL, 0 },
{ "__ptrbase", RID_PTRBASE, 0 },
{ "__ptrbase__", RID_PTRBASE, 0 },
{ "__ptrextent", RID_PTREXTENT, 0 },
{ "__ptrextent__", RID_PTREXTENT, 0 },
{ "__ptrvalue", RID_PTRVALUE, 0 },
{ "__ptrvalue__", RID_PTRVALUE, 0 },
{ "__real", RID_REALPART, 0 },
{ "__real__", RID_REALPART, 0 },
{ "__restrict", RID_RESTRICT, 0 },
{ "__restrict__", RID_RESTRICT, 0 },
{ "__signed", RID_SIGNED, 0 },
{ "__signed__", RID_SIGNED, 0 },
{ "__typeof", RID_TYPEOF, 0 },
{ "__typeof__", RID_TYPEOF, 0 },
{ "__unbounded", RID_UNBOUNDED, 0 },
{ "__unbounded__", RID_UNBOUNDED, 0 },
{ "__volatile", RID_VOLATILE, 0 },
{ "__volatile__", RID_VOLATILE, 0 },
{ "asm", RID_ASM, 0 },
{ "auto", RID_AUTO, 0 },
{ "break", RID_BREAK, 0 },
{ "case", RID_CASE, 0 },
{ "char", RID_CHAR, 0 },
{ "const", RID_CONST, 0 },
{ "continue", RID_CONTINUE, 0 },
{ "default", RID_DEFAULT, 0 },
{ "do", RID_DO, 0 },
{ "double", RID_DOUBLE, 0 },
{ "else", RID_ELSE, 0 },
{ "enum", RID_ENUM, 0 },
{ "extern", RID_EXTERN, 0 },
{ "float", RID_FLOAT, 0 },
{ "for", RID_FOR, 0 },
{ "goto", RID_GOTO, 0 },
{ "if", RID_IF, 0 },
{ "inline", RID_INLINE, 0 },
{ "int", RID_INT, 0 },
{ "long", RID_LONG, 0 },
{ "register", RID_REGISTER, 0 },
{ "restrict", RID_RESTRICT, 0 },
{ "return", RID_RETURN, 0 },
{ "short", RID_SHORT, 0 },
{ "signed", RID_SIGNED, 0 },
{ "sizeof", RID_SIZEOF, 0 },
{ "static", RID_STATIC, 0 },
{ "struct", RID_STRUCT, 0 },
{ "switch", RID_SWITCH, 0 },
{ "typedef", RID_TYPEDEF, 0 },
{ "typeof", RID_TYPEOF, 0 },
{ "union", RID_UNION, 0 },
{ "unsigned", RID_UNSIGNED, 0 },
{ "void", RID_VOID, 0 },
{ "volatile", RID_VOLATILE, 0 },
{ "while", RID_WHILE, 0 },
};
#define N_reswords (sizeof reswords / sizeof (struct resword))
/* Init enough to allow the C decl code to work, then clean up
afterwards. */
void
treelang_init_decl_processing ()
{
unsigned int i;
tree id;
/* It is not necessary to register ridpointers as a GC root, because
all the trees it points to are permanently interned in the
get_identifier hash anyway. */
ridpointers = (tree *) xcalloc ((int) RID_MAX, sizeof (tree));
for (i = 0; i < N_reswords; i++)
{
id = get_identifier (reswords[i].word);
C_RID_CODE (id) = reswords[i].rid;
C_IS_RESERVED_WORD (id) = 1;
ridpointers [(int) reswords[i].rid] = id;
}
c_init_decl_processing ();
/* ix86_return_pops_args takes the type of these so need to patch
their own type as themselves. */
for (i = 0; i < itk_none; i++)
{
if (integer_types[i])
TREE_TYPE (integer_types [i]) = integer_types[i];
}
/* Probably these ones too. */
TREE_TYPE (float_type_node) = float_type_node;
TREE_TYPE (double_type_node) = double_type_node;
TREE_TYPE (long_double_type_node) = long_double_type_node;
}
/* Save typing debug_tree all the time. Dump a tree T pretty and
concise. */
void dt (tree t);
void
dt (tree t)
{
debug_tree (t);
}
/*
TREELANG Compiler definitions for interfacing to treetree.c
(compiler back end interface).
Copyright (C) 1986, 87, 89, 92-96, 1997, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This program 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 2, or (at your option) any
later version.
This program 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 this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding!
---------------------------------------------------------------------------
Written by Tim Josling 1999, 2000, 2001, based in part on other
parts of the GCC compiler.
*/
/* Parameter list passed to back end. */
struct tree_parameter_list
{
struct tree_parameter_list* next; /* Next entry. */
int type; /* See numeric types below. */
unsigned char* variable_name; /* Name. */
tree* where_to_put_var_tree; /* Where to save decl. */
};
tree tree_code_init_parameters (void);
tree tree_code_add_parameter (tree list, tree proto_exp, tree exp);
tree tree_code_get_integer_value (unsigned char *chars, unsigned int length);
void tree_code_generate_return (tree type, tree exp);
void tree_ggc_storage_always_used (void *m);
tree tree_code_get_expression (unsigned int exp_type, tree type, tree op1, tree op2, tree op3);
tree tree_code_get_numeric_type (unsigned int size1, unsigned int sign1);
void tree_code_create_function_initial (tree prev_saved,
unsigned char* filename, int lineno,
struct tree_parameter_list* parms);
void tree_code_create_function_wrapup (unsigned char* filename, int lineno);
tree tree_code_create_function_prototype (unsigned char* chars,
unsigned int storage_class,
unsigned int ret_type,
struct tree_parameter_list* parms,
unsigned char* filename,
int lineno);
tree tree_code_create_variable (unsigned int storage_class,
unsigned char* chars,
unsigned int length,
unsigned int expression_type,
tree init,
unsigned char* filename,
int lineno);
void tree_code_output_expression_statement (tree code, unsigned char* filename, int lineno);
tree get_type_for_numeric_type (unsigned int numeric_type);
void tree_code_if_start (tree exp, unsigned char* filename, int lineno);
void tree_code_if_else (unsigned char* filename, int lineno);
void tree_code_if_end (unsigned char* filename, int lineno);
tree tree_code_get_type (int type_num);
void treelang_init_decl_processing (void);
void treelang_finish (void);
const char * treelang_init (const char* filename);
int treelang_decode_option (int, char **);
void treelang_parse_file (int debug_flag);
void push_var_level (void);
void pop_var_level (void);
/* Storage modes. */
#define STATIC_STORAGE 0
#define AUTOMATIC_STORAGE 1
#define EXTERNAL_REFERENCE_STORAGE 2
#define EXTERNAL_DEFINITION_STORAGE 3
/* Numeric types. */
#define SIGNED_CHAR 1
#define UNSIGNED_CHAR 2
#define SIGNED_INT 3
#define UNSIGNED_INT 4
#define VOID_TYPE 5
#define EXP_PLUS 0 /* Addition expression. */
#define EXP_REFERENCE 1 /* Variable reference. */
#define EXP_ASSIGN 2 /* Assignment. */
#define EXP_FUNCTION_INVOCATION 3 /* Call function. */
#define EXP_MINUS 4 /* Subtraction. */
#define EXP_EQUALS 5 /* Equality test. */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment