diff options
-rw-r--r-- | gcc/testsuite/lib/treelang.exp | 20 | ||||
-rw-r--r-- | gcc/testsuite/treelang/ChangeLog | 40 | ||||
-rw-r--r-- | gcc/testsuite/treelang/Makefile.in | 9 | ||||
-rw-r--r-- | gcc/testsuite/treelang/a01gcci01.c | 19 | ||||
-rw-r--r-- | gcc/testsuite/treelang/a01gcci01.tree | 39 | ||||
-rw-r--r-- | gcc/testsuite/treelang/a01gcco01runpgm | 8 | ||||
-rw-r--r-- | gcc/testsuite/treelang/treetests.exp | 289 | ||||
-rw-r--r-- | gcc/treelang/ChangeLog | 24 | ||||
-rw-r--r-- | gcc/treelang/Make-lang.in | 297 | ||||
-rw-r--r-- | gcc/treelang/README | 16 | ||||
-rw-r--r-- | gcc/treelang/config-lang.in | 37 | ||||
-rw-r--r-- | gcc/treelang/lang-options.h | 29 | ||||
-rw-r--r-- | gcc/treelang/lang-specs.h | 63 | ||||
-rw-r--r-- | gcc/treelang/lex.l | 294 | ||||
-rw-r--r-- | gcc/treelang/parse.y | 1001 | ||||
-rw-r--r-- | gcc/treelang/tree1.c | 382 | ||||
-rw-r--r-- | gcc/treelang/treelang.h | 116 | ||||
-rw-r--r-- | gcc/treelang/treelang.texi | 1311 | ||||
-rw-r--r-- | gcc/treelang/treetree.c | 1288 | ||||
-rw-r--r-- | gcc/treelang/treetree.h | 101 |
20 files changed, 5383 insertions, 0 deletions
diff --git a/gcc/testsuite/lib/treelang.exp b/gcc/testsuite/lib/treelang.exp new file mode 100644 index 0000000..e3d6c49 --- /dev/null +++ b/gcc/testsuite/lib/treelang.exp @@ -0,0 +1,20 @@ +# 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 + + diff --git a/gcc/testsuite/treelang/ChangeLog b/gcc/testsuite/treelang/ChangeLog new file mode 100644 index 0000000..d7f7c78 --- /dev/null +++ b/gcc/testsuite/treelang/ChangeLog @@ -0,0 +1,40 @@ +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. + + diff --git a/gcc/testsuite/treelang/Makefile.in b/gcc/testsuite/treelang/Makefile.in new file mode 100644 index 0000000..908131b --- /dev/null +++ b/gcc/testsuite/treelang/Makefile.in @@ -0,0 +1,9 @@ +# Copyright (C) 2001, 2002 Free Software Foundation, Inc. + +all: + +clean: + -rm -f *.o *.diff *~ *.bad core *.x + +distclean: clean + -rm -f Makefile config.status diff --git a/gcc/testsuite/treelang/a01gcci01.c b/gcc/testsuite/treelang/a01gcci01.c new file mode 100644 index 0000000..69ab63d --- /dev/null +++ b/gcc/testsuite/treelang/a01gcci01.c @@ -0,0 +1,19 @@ +/* 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; +} diff --git a/gcc/testsuite/treelang/a01gcci01.tree b/gcc/testsuite/treelang/a01gcci01.tree new file mode 100644 index 0000000..e1e1ac1 --- /dev/null +++ b/gcc/testsuite/treelang/a01gcci01.tree @@ -0,0 +1,39 @@ +// -*- 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; +} + diff --git a/gcc/testsuite/treelang/a01gcco01runpgm b/gcc/testsuite/treelang/a01gcco01runpgm new file mode 100644 index 0000000..3c2c743 --- /dev/null +++ b/gcc/testsuite/treelang/a01gcco01runpgm @@ -0,0 +1,8 @@ +2:2 +7:7 +-1:-1 +1:1 +3:3 +0:0 +1:1 +15:15 diff --git a/gcc/testsuite/treelang/treetests.exp b/gcc/testsuite/treelang/treetests.exp new file mode 100644 index 0000000..10e6f84 --- /dev/null +++ b/gcc/testsuite/treelang/treetests.exp @@ -0,0 +1,289 @@ + +# 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 "" +} + diff --git a/gcc/treelang/ChangeLog b/gcc/treelang/ChangeLog new file mode 100644 index 0000000..18b7e08 --- /dev/null +++ b/gcc/treelang/ChangeLog @@ -0,0 +1,24 @@ +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. + + + diff --git a/gcc/treelang/Make-lang.in b/gcc/treelang/Make-lang.in new file mode 100644 index 0000000..bd6f7e3 --- /dev/null +++ b/gcc/treelang/Make-lang.in @@ -0,0 +1,297 @@ +# 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 diff --git a/gcc/treelang/README b/gcc/treelang/README new file mode 100644 index 0000000..f16eafc --- /dev/null +++ b/gcc/treelang/README @@ -0,0 +1,16 @@ +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 + diff --git a/gcc/treelang/config-lang.in b/gcc/treelang/config-lang.in new file mode 100644 index 0000000..6cf1f45 --- /dev/null +++ b/gcc/treelang/config-lang.in @@ -0,0 +1,37 @@ +# 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" diff --git a/gcc/treelang/lang-options.h b/gcc/treelang/lang-options.h new file mode 100644 index 0000000..2d60c3e --- /dev/null +++ b/gcc/treelang/lang-options.h @@ -0,0 +1,29 @@ +/* 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")}, + + diff --git a/gcc/treelang/lang-specs.h b/gcc/treelang/lang-specs.h new file mode 100644 index 0000000..4bf8e5d --- /dev/null +++ b/gcc/treelang/lang-specs.h @@ -0,0 +1,63 @@ +/* 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 +}, diff --git a/gcc/treelang/lex.l b/gcc/treelang/lex.l new file mode 100644 index 0000000..97b06a6 --- /dev/null +++ b/gcc/treelang/lex.l @@ -0,0 +1,294 @@ +%{ /* -*- 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"); +} + diff --git a/gcc/treelang/parse.y b/gcc/treelang/parse.y new file mode 100644 index 0000000..f0c0cef --- /dev/null +++ b/gcc/treelang/parse.y @@ -0,0 +1,1001 @@ +%{ /* -*- 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; +} diff --git a/gcc/treelang/tree1.c b/gcc/treelang/tree1.c new file mode 100644 index 0000000..5067bea --- /dev/null +++ b/gcc/treelang/tree1.c @@ -0,0 +1,382 @@ + /* + + 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; +} + + diff --git a/gcc/treelang/treelang.h b/gcc/treelang/treelang.h new file mode 100644 index 0000000..a265738 --- /dev/null +++ b/gcc/treelang/treelang.h @@ -0,0 +1,116 @@ +/* + + 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); + diff --git a/gcc/treelang/treelang.texi b/gcc/treelang/treelang.texi new file mode 100644 index 0000000..499f160 --- /dev/null +++ b/gcc/treelang/treelang.texi @@ -0,0 +1,1311 @@ +\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 diff --git a/gcc/treelang/treetree.c b/gcc/treelang/treetree.c new file mode 100644 index 0000000..07cb1a5 --- /dev/null +++ b/gcc/treelang/treetree.c @@ -0,0 +1,1288 @@ +/* + + 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); +} diff --git a/gcc/treelang/treetree.h b/gcc/treelang/treetree.h new file mode 100644 index 0000000..24b72e3 --- /dev/null +++ b/gcc/treelang/treetree.h @@ -0,0 +1,101 @@ +/* + + 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. */ |