/* TREELANG Compiler almost main (tree1)
|
/* TREELANG Compiler almost main (tree1)
|
Called by GCC's toplev.c
|
Called by GCC's toplev.c
|
|
|
Copyright (C) 1986, 87, 89, 92-96, 1997, 1999, 2000, 2001, 2002, 2003, 2004,
|
Copyright (C) 1986, 87, 89, 92-96, 1997, 1999, 2000, 2001, 2002, 2003, 2004,
|
2007 Free Software Foundation, Inc.
|
2007 Free Software Foundation, Inc.
|
|
|
This program is free software; you can redistribute it and/or modify it
|
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
|
under the terms of the GNU General Public License as published by the
|
Free Software Foundation; either version 3, or (at your option) any
|
Free Software Foundation; either version 3, or (at your option) any
|
later version.
|
later version.
|
|
|
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
GNU General Public License for more details.
|
GNU General Public License for more details.
|
|
|
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
along with this program; see the file COPYING3. If not see
|
along with this program; see the file COPYING3. If not see
|
<http://www.gnu.org/licenses/>.
|
<http://www.gnu.org/licenses/>.
|
|
|
In other words, you are welcome to use, share and improve this program.
|
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
|
You are forbidden to forbid anyone else to use, share and improve
|
what you give them. Help stamp out software-hoarding!
|
what you give them. Help stamp out software-hoarding!
|
|
|
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
|
|
Written by Tim Josling 1999, 2000, 2001, based in part on other
|
Written by Tim Josling 1999, 2000, 2001, based in part on other
|
parts of the GCC compiler. */
|
parts of the GCC compiler. */
|
|
|
#include "config.h"
|
#include "config.h"
|
#include "system.h"
|
#include "system.h"
|
#include "coretypes.h"
|
#include "coretypes.h"
|
#include "tm.h"
|
#include "tm.h"
|
#include "flags.h"
|
#include "flags.h"
|
#include "toplev.h"
|
#include "toplev.h"
|
#include "version.h"
|
#include "version.h"
|
|
|
#include "ggc.h"
|
#include "ggc.h"
|
#include "tree.h"
|
#include "tree.h"
|
#include "cgraph.h"
|
#include "cgraph.h"
|
#include "diagnostic.h"
|
#include "diagnostic.h"
|
|
|
#include "treelang.h"
|
#include "treelang.h"
|
#include "treetree.h"
|
#include "treetree.h"
|
#include "opts.h"
|
#include "opts.h"
|
#include "options.h"
|
#include "options.h"
|
|
|
extern int yyparse (void);
|
extern int yyparse (void);
|
|
|
/* Linked list of symbols - all must be unique in treelang. */
|
/* Linked list of symbols - all must be unique in treelang. */
|
|
|
static GTY(()) struct prod_token_parm_item *symbol_table = NULL;
|
static GTY(()) struct prod_token_parm_item *symbol_table = NULL;
|
|
|
/* Language for usage for messages. */
|
/* Language for usage for messages. */
|
|
|
const char *const language_string = "TREELANG - sample front end for GCC ";
|
const char *const language_string = "TREELANG - sample front end for GCC ";
|
|
|
/* Local prototypes. */
|
/* Local prototypes. */
|
|
|
void version (void);
|
void version (void);
|
|
|
/* Global variables. */
|
/* Global variables. */
|
|
|
extern struct cbl_tree_struct_parse_tree_top* parse_tree_top;
|
extern struct cbl_tree_struct_parse_tree_top* parse_tree_top;
|
|
|
/*
|
/*
|
Options.
|
Options.
|
*/
|
*/
|
|
|
/* Trace the parser. */
|
/* Trace the parser. */
|
unsigned int option_parser_trace = 0;
|
unsigned int option_parser_trace = 0;
|
|
|
/* Trace the lexical analysis. */
|
/* Trace the lexical analysis. */
|
|
|
unsigned int option_lexer_trace = 0;
|
unsigned int option_lexer_trace = 0;
|
|
|
/* Warning levels. */
|
/* Warning levels. */
|
|
|
/* Local variables. */
|
/* Local variables. */
|
|
|
/* This is 1 if we have output the version string. */
|
/* This is 1 if we have output the version string. */
|
|
|
static int version_done = 0;
|
static int version_done = 0;
|
|
|
/* Variable nesting level. */
|
/* Variable nesting level. */
|
|
|
static unsigned int work_nesting_level = 0;
|
static unsigned int work_nesting_level = 0;
|
|
|
/* Prepare to handle switches. */
|
/* Prepare to handle switches. */
|
unsigned int
|
unsigned int
|
treelang_init_options (unsigned int argc ATTRIBUTE_UNUSED,
|
treelang_init_options (unsigned int argc ATTRIBUTE_UNUSED,
|
const char **argv ATTRIBUTE_UNUSED)
|
const char **argv ATTRIBUTE_UNUSED)
|
{
|
{
|
return CL_Treelang;
|
return CL_Treelang;
|
}
|
}
|
|
|
/* Process a switch - called by opts.c. */
|
/* Process a switch - called by opts.c. */
|
int
|
int
|
treelang_handle_option (size_t scode, const char *arg ATTRIBUTE_UNUSED,
|
treelang_handle_option (size_t scode, const char *arg ATTRIBUTE_UNUSED,
|
int value)
|
int value)
|
{
|
{
|
enum opt_code code = (enum opt_code) scode;
|
enum opt_code code = (enum opt_code) scode;
|
|
|
switch (code)
|
switch (code)
|
{
|
{
|
case OPT_v:
|
case OPT_v:
|
if (!version_done)
|
if (!version_done)
|
{
|
{
|
fputs (language_string, stdout);
|
fputs (language_string, stdout);
|
fputs (version_string, stdout);
|
fputs (version_string, stdout);
|
fputs ("\n", stdout);
|
fputs ("\n", stdout);
|
version_done = 1;
|
version_done = 1;
|
}
|
}
|
break;
|
break;
|
|
|
case OPT_y:
|
case OPT_y:
|
option_lexer_trace = 1;
|
option_lexer_trace = 1;
|
option_parser_trace = 1;
|
option_parser_trace = 1;
|
break;
|
break;
|
|
|
case OPT_fparser_trace:
|
case OPT_fparser_trace:
|
option_parser_trace = value;
|
option_parser_trace = value;
|
break;
|
break;
|
|
|
case OPT_flexer_trace:
|
case OPT_flexer_trace:
|
option_lexer_trace = value;
|
option_lexer_trace = value;
|
break;
|
break;
|
|
|
default:
|
default:
|
gcc_unreachable ();
|
gcc_unreachable ();
|
}
|
}
|
|
|
return 1;
|
return 1;
|
}
|
}
|
|
|
/* Language dependent parser setup. */
|
/* Language dependent parser setup. */
|
|
|
bool
|
bool
|
treelang_init (void)
|
treelang_init (void)
|
{
|
{
|
#ifndef USE_MAPPED_LOCATION
|
#ifndef USE_MAPPED_LOCATION
|
input_filename = main_input_filename;
|
input_filename = main_input_filename;
|
#else
|
#else
|
linemap_add (&line_table, LC_ENTER, false, main_input_filename, 1);
|
linemap_add (&line_table, LC_ENTER, false, main_input_filename, 1);
|
#endif
|
#endif
|
|
|
/* This error will not happen from GCC as it will always create a
|
/* This error will not happen from GCC as it will always create a
|
fake input file. */
|
fake input file. */
|
if (!input_filename || input_filename[0] == ' ' || !input_filename[0])
|
if (!input_filename || input_filename[0] == ' ' || !input_filename[0])
|
{
|
{
|
if (!version_done)
|
if (!version_done)
|
{
|
{
|
fprintf (stderr, "No input file specified, try --help for help\n");
|
fprintf (stderr, "No input file specified, try --help for help\n");
|
exit (1);
|
exit (1);
|
}
|
}
|
|
|
return false;
|
return false;
|
}
|
}
|
|
|
yyin = fopen (input_filename, "r");
|
yyin = fopen (input_filename, "r");
|
if (!yyin)
|
if (!yyin)
|
{
|
{
|
fprintf (stderr, "Unable to open input file %s\n", input_filename);
|
fprintf (stderr, "Unable to open input file %s\n", input_filename);
|
exit (1);
|
exit (1);
|
}
|
}
|
|
|
#ifdef USE_MAPPED_LOCATION
|
#ifdef USE_MAPPED_LOCATION
|
linemap_add (&line_table, LC_RENAME, false, "<built-in>", 1);
|
linemap_add (&line_table, LC_RENAME, false, "<built-in>", 1);
|
linemap_line_start (&line_table, 0, 1);
|
linemap_line_start (&line_table, 0, 1);
|
#endif
|
#endif
|
|
|
/* Init decls, etc. */
|
/* Init decls, etc. */
|
treelang_init_decl_processing ();
|
treelang_init_decl_processing ();
|
|
|
return true;
|
return true;
|
}
|
}
|
|
|
/* Language dependent wrapup. */
|
/* Language dependent wrapup. */
|
|
|
void
|
void
|
treelang_finish (void)
|
treelang_finish (void)
|
{
|
{
|
fclose (yyin);
|
fclose (yyin);
|
}
|
}
|
|
|
/* Parse a file. Debug flag doesn't seem to work. */
|
/* Parse a file. Debug flag doesn't seem to work. */
|
|
|
void
|
void
|
treelang_parse_file (int debug_flag ATTRIBUTE_UNUSED)
|
treelang_parse_file (int debug_flag ATTRIBUTE_UNUSED)
|
{
|
{
|
#ifdef USE_MAPPED_LOCATION
|
#ifdef USE_MAPPED_LOCATION
|
source_location s;
|
source_location s;
|
linemap_add (&line_table, LC_RENAME, false, main_input_filename, 1);
|
linemap_add (&line_table, LC_RENAME, false, main_input_filename, 1);
|
s = linemap_line_start (&line_table, 1, 80);
|
s = linemap_line_start (&line_table, 1, 80);
|
input_location = s;
|
input_location = s;
|
#else
|
#else
|
input_line = 1;
|
input_line = 1;
|
#endif
|
#endif
|
|
|
treelang_debug ();
|
treelang_debug ();
|
yyparse ();
|
yyparse ();
|
cgraph_finalize_compilation_unit ();
|
cgraph_finalize_compilation_unit ();
|
#ifdef USE_MAPPED_LOCATION
|
#ifdef USE_MAPPED_LOCATION
|
linemap_add (&line_table, LC_LEAVE, false, NULL, 0);
|
linemap_add (&line_table, LC_LEAVE, false, NULL, 0);
|
#endif
|
#endif
|
cgraph_optimize ();
|
cgraph_optimize ();
|
}
|
}
|
|
|
/* Allocate SIZE bytes and clear them. Not to be used for strings
|
/* Allocate SIZE bytes and clear them. Not to be used for strings
|
which must go in stringpool. */
|
which must go in stringpool. */
|
|
|
void *
|
void *
|
my_malloc (size_t size)
|
my_malloc (size_t size)
|
{
|
{
|
void *mem;
|
void *mem;
|
mem = ggc_alloc (size);
|
mem = ggc_alloc (size);
|
if (!mem)
|
if (!mem)
|
{
|
{
|
fprintf (stderr, "\nOut of memory\n");
|
fprintf (stderr, "\nOut of memory\n");
|
abort ();
|
abort ();
|
}
|
}
|
memset (mem, 0, size);
|
memset (mem, 0, size);
|
return mem;
|
return mem;
|
}
|
}
|
|
|
/* Look up a name in PROD->SYMBOL_TABLE_NAME in the symbol table;
|
/* 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,
|
return the symbol table entry from the symbol table if found there,
|
else 0. */
|
else 0. */
|
|
|
struct prod_token_parm_item*
|
struct prod_token_parm_item*
|
lookup_tree_name (struct prod_token_parm_item *prod)
|
lookup_tree_name (struct prod_token_parm_item *prod)
|
{
|
{
|
struct prod_token_parm_item *this;
|
struct prod_token_parm_item *this;
|
struct prod_token_parm_item *this_tok;
|
struct prod_token_parm_item *this_tok;
|
struct prod_token_parm_item *tok;
|
struct prod_token_parm_item *tok;
|
|
|
sanity_check (prod);
|
sanity_check (prod);
|
|
|
tok = SYMBOL_TABLE_NAME (prod);
|
tok = SYMBOL_TABLE_NAME (prod);
|
sanity_check (tok);
|
sanity_check (tok);
|
|
|
for (this = symbol_table; this; this = this->tp.pro.next)
|
for (this = symbol_table; this; this = this->tp.pro.next)
|
{
|
{
|
sanity_check (this);
|
sanity_check (this);
|
this_tok = this->tp.pro.main_token;
|
this_tok = this->tp.pro.main_token;
|
sanity_check (this_tok);
|
sanity_check (this_tok);
|
if (tok->tp.tok.length != this_tok->tp.tok.length)
|
if (tok->tp.tok.length != this_tok->tp.tok.length)
|
continue;
|
continue;
|
if (memcmp (tok->tp.tok.chars, this_tok->tp.tok.chars,
|
if (memcmp (tok->tp.tok.chars, this_tok->tp.tok.chars,
|
this_tok->tp.tok.length))
|
this_tok->tp.tok.length))
|
continue;
|
continue;
|
|
|
if (option_parser_trace)
|
if (option_parser_trace)
|
fprintf (stderr, "Found symbol %s (%i:%i) as %i \n",
|
fprintf (stderr, "Found symbol %s (%i:%i) as %i \n",
|
tok->tp.tok.chars, LOCATION_LINE (tok->tp.tok.location),
|
tok->tp.tok.chars, LOCATION_LINE (tok->tp.tok.location),
|
tok->tp.tok.charno, NUMERIC_TYPE (this));
|
tok->tp.tok.charno, NUMERIC_TYPE (this));
|
return this;
|
return this;
|
}
|
}
|
|
|
if (option_parser_trace)
|
if (option_parser_trace)
|
fprintf (stderr, "Not found symbol %s (%i:%i) as %i \n",
|
fprintf (stderr, "Not found symbol %s (%i:%i) as %i \n",
|
tok->tp.tok.chars, LOCATION_LINE (tok->tp.tok.location),
|
tok->tp.tok.chars, LOCATION_LINE (tok->tp.tok.location),
|
tok->tp.tok.charno, tok->type);
|
tok->tp.tok.charno, tok->type);
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
/* Insert name PROD into the symbol table. Return 1 if duplicate, 0 if OK. */
|
/* Insert name PROD into the symbol table. Return 1 if duplicate, 0 if OK. */
|
|
|
int
|
int
|
insert_tree_name (struct prod_token_parm_item *prod)
|
insert_tree_name (struct prod_token_parm_item *prod)
|
{
|
{
|
struct prod_token_parm_item *tok;
|
struct prod_token_parm_item *tok;
|
tok = SYMBOL_TABLE_NAME (prod);
|
tok = SYMBOL_TABLE_NAME (prod);
|
sanity_check (prod);
|
sanity_check (prod);
|
if (lookup_tree_name (prod))
|
if (lookup_tree_name (prod))
|
{
|
{
|
error ("%HDuplicate name %q.*s.", &tok->tp.tok.location,
|
error ("%HDuplicate name %q.*s.", &tok->tp.tok.location,
|
tok->tp.tok.length, tok->tp.tok.chars);
|
tok->tp.tok.length, tok->tp.tok.chars);
|
return 1;
|
return 1;
|
}
|
}
|
prod->tp.pro.next = symbol_table;
|
prod->tp.pro.next = symbol_table;
|
NESTING_LEVEL (prod) = work_nesting_level;
|
NESTING_LEVEL (prod) = work_nesting_level;
|
symbol_table = prod;
|
symbol_table = prod;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Create a struct productions of type TYPE, main token MAIN_TOK. */
|
/* Create a struct productions of type TYPE, main token MAIN_TOK. */
|
|
|
struct prod_token_parm_item *
|
struct prod_token_parm_item *
|
make_production (int type, struct prod_token_parm_item *main_tok)
|
make_production (int type, struct prod_token_parm_item *main_tok)
|
{
|
{
|
struct prod_token_parm_item *prod;
|
struct prod_token_parm_item *prod;
|
prod = my_malloc (sizeof (struct prod_token_parm_item));
|
prod = my_malloc (sizeof (struct prod_token_parm_item));
|
prod->category = production_category;
|
prod->category = production_category;
|
prod->type = type;
|
prod->type = type;
|
prod->tp.pro.main_token = main_tok;
|
prod->tp.pro.main_token = main_tok;
|
return prod;
|
return prod;
|
}
|
}
|
|
|
/* Abort if ITEM is not a valid structure, based on 'category'. */
|
/* Abort if ITEM is not a valid structure, based on 'category'. */
|
|
|
void
|
void
|
sanity_check (struct prod_token_parm_item *item)
|
sanity_check (struct prod_token_parm_item *item)
|
{
|
{
|
switch (item->category)
|
switch (item->category)
|
{
|
{
|
case token_category:
|
case token_category:
|
case production_category:
|
case production_category:
|
case parameter_category:
|
case parameter_category:
|
break;
|
break;
|
|
|
default:
|
default:
|
gcc_unreachable ();
|
gcc_unreachable ();
|
}
|
}
|
}
|
}
|
|
|
/* New garbage collection regime see gty.texi. */
|
/* New garbage collection regime see gty.texi. */
|
#include "gt-treelang-tree1.h"
|
#include "gt-treelang-tree1.h"
|
/*#include "gt-treelang-treelang.h"*/
|
/*#include "gt-treelang-treelang.h"*/
|
#include "gtype-treelang.h"
|
#include "gtype-treelang.h"
|
|
|