Add include-file support to igen.

This commit is contained in:
Andrew Cagney 1997-10-27 06:30:35 +00:00
parent f45dd42b32
commit e2880fadf3
5 changed files with 1356 additions and 425 deletions

View file

@ -1,3 +1,24 @@
Mon Oct 27 15:14:26 1997 Andrew Cagney <cagney@b1.cygnus.com>
* igen.c (main): Change -I option to -I<directory>. Add optional
size to -Ggen-icache option. Add -Gno-... support.
* igen.h (struct _igen_options): Add include field.
* ld-insn.c (enum insn_record_type, insn_type_map): Add
include_record.
(load_insn_table): Call table_push when include record.
* table.c (struct _open table, struct table): Make table object an
indirect ptr to the current table file.
(current_line, new_table_entry, next_line): Make file arg type
open_table.
(table_open): Use table_push.
(table_read): Point variable file at current table, at eof, pop
last open table.
* table.h, table.c (table_push): New function.
Thu Oct 16 11:03:27 1997 Andrew Cagney <cagney@b1.cygnus.com>
* gen-semantics.c (print_semantic_body): Use CIA not

View file

@ -979,15 +979,13 @@ main (int argc,
printf ("\t Set the number of the high (most significant) instruction bit (depreciated).\n");
printf ("\t This option can now be set directly in the instruction table.\n");
printf ("\n");
printf (" -I <icache-size>\n");
printf ("\t Specify size of the cracking instruction cache (default %d instructions).\n",
options.gen.icache_size);
printf ("\t Implies -G icache.\n");
printf (" -I <directory>\n");
printf ("\t Add <directory> to the list of directories searched when opening a file\n");
printf ("\n");
printf (" -M <model-list>\n");
printf ("\t Filter out any instructions that do not support at least one of the listed\n");
printf ("\t models (An instructions with no model information is considered to support\n");
printf ("\n all models.).\n");
printf ("\t all models.).\n");
printf ("\n");
printf (" -N <nr-cpus>\n");
printf ("\t Generate a simulator supporting <nr-cpus>\n");
@ -1020,7 +1018,8 @@ main (int argc,
printf ("\t gen-delayed-branch - need both cia and nia passed around\n");
printf ("\t gen-direct-access - use #defines to directly access values\n");
printf ("\t gen-zero-r<N> - arch assumes GPR(<N>) == 0, keep it that way\n");
printf ("\t gen-icache - generate an instruction cracking cache\n");
printf ("\t gen-icache[=<N> - generate an instruction cracking cache of size <N>\n");
printf ("\t Default size is %d\n", options.gen.icache_size);
printf ("\t gen-insn-in-icache - save original instruction when cracking\n");
printf ("\t gen-multi-sim - generate multiple simulators - one per model\n");
printf ("\t By default, a single simulator that will\n");
@ -1099,8 +1098,13 @@ main (int argc,
break;
case 'I':
options.gen.icache_size = a2i (optarg);
options.gen.icache = 1;
{
table_include **dir = &options.include;
while ((*dir) != NULL)
dir = &(*dir)->next;
(*dir) = ZALLOC (table_include);
(*dir)->dir = strdup (optarg);
}
break;
case 'B':
@ -1213,131 +1217,162 @@ main (int argc,
case 'G':
if (strcmp (optarg, "decode-duplicate") == 0)
{
options.decode.duplicate = 1;
}
else if (strcmp (optarg, "decode-combine") == 0)
{
options.decode.combine = 1;
}
else if (strcmp (optarg, "decode-zero-reserved") == 0)
{
options.decode.zero_reserved = 1;
}
else if (strcmp (optarg, "gen-conditional-issue") == 0)
{
options.gen.conditional_issue = 1;
}
else if (strcmp (optarg, "conditional-issue") == 0)
{
options.gen.conditional_issue = 1;
options.warning (NULL, "Option conditional-issue replaced by gen-conditional-issue\n");
}
else if (strcmp (optarg, "gen-delayed-branch") == 0)
{
options.gen.delayed_branch = 1;
}
else if (strcmp (optarg, "delayed-branch") == 0)
{
options.gen.delayed_branch = 1;
options.warning (NULL, "Option delayed-branch replaced by gen-delayed-branch\n");
}
else if (strcmp (optarg, "gen-direct-access") == 0)
{
options.gen.direct_access = 1;
}
else if (strcmp (optarg, "direct-access") == 0)
{
options.gen.direct_access = 1;
options.warning (NULL, "Option direct-access replaced by gen-direct-access\n");
}
else if (strncmp (optarg, "gen-zero-r", strlen ("gen-zero-r")) == 0)
{
options.gen.zero_reg = 1;
options.gen.zero_reg_nr = atoi (optarg + strlen ("gen-zero-r"));
}
else if (strncmp (optarg, "zero-r", strlen ("zero-r")) == 0)
{
options.gen.zero_reg = 1;
options.gen.zero_reg_nr = atoi (optarg + strlen ("zero-r"));
options.warning (NULL, "Option zero-r<N> replaced by gen-zero-r<N>\n");
}
else if (strcmp (optarg, "gen-icache") == 0)
{
options.gen.icache = 1;
}
else if (strcmp (optarg, "gen-insn-in-icache") == 0)
{
options.gen.insn_in_icache = 1;
}
else if (strcmp (optarg, "gen-multi-sim") == 0)
{
options.gen.multi_sim = 1;
}
else if (strcmp (optarg, "gen-multi-word") == 0)
{
options.gen.multi_word = 1;
}
else if (strcmp (optarg, "gen-semantic-icache") == 0)
{
options.gen.semantic_icache = 1;
}
else if (strcmp (optarg, "gen-slot-verification") == 0)
{
options.gen.slot_verification = 1;
}
else if (strcmp (optarg, "verify-slot") == 0)
{
options.gen.slot_verification = 1;
options.warning (NULL, "Option verify-slot replaced by gen-slot-verification\n");
}
else if (strcmp (optarg, "gen-nia-invalid") == 0)
{
options.gen.nia = nia_is_invalid;
}
else if (strcmp (optarg, "default-nia-minus-one") == 0)
{
options.gen.nia = nia_is_invalid;
options.warning (NULL, "Option default-nia-minus-one replaced by gen-nia-invalid\n");
}
else if (strcmp (optarg, "gen-nia-void") == 0)
{
options.gen.nia = nia_is_void;
}
else if (strcmp (optarg, "trace-combine") == 0)
{
options.trace.combine = 1;
}
else if (strcmp (optarg, "trace-entries") == 0)
{
options.trace.entries = 1;
}
else if (strcmp (optarg, "trace-rule-rejection") == 0)
{
options.trace.rule_rejection = 1;
}
else if (strcmp (optarg, "trace-rule-selection") == 0)
{
options.trace.rule_selection = 1;
}
else if (strcmp (optarg, "jumps") == 0)
{
options.gen.code = generate_jumps;
}
else if (strcmp (optarg, "field-widths") == 0)
{
options.insn_specifying_widths = 1;
}
else if (strcmp (optarg, "omit-line-numbers") == 0)
{
file_references = lf_omit_references;
}
else
error (NULL, "Unknown option %s\n", optarg);
break;
{
int enable_p;
char *argp;
if (strncmp (optarg, "no-", strlen ("no-")) == 0)
{
argp = optarg + strlen ("no-");
enable_p = 0;
}
else if (strncmp (optarg, "!", strlen ("!")) == 0)
{
argp = optarg + strlen ("no-");
enable_p = 0;
}
else
{
argp = optarg;
enable_p = 1;
}
if (strcmp (argp, "decode-duplicate") == 0)
{
options.decode.duplicate = enable_p;
}
else if (strcmp (argp, "decode-combine") == 0)
{
options.decode.combine = enable_p;
}
else if (strcmp (argp, "decode-zero-reserved") == 0)
{
options.decode.zero_reserved = enable_p;
}
else if (strcmp (argp, "gen-conditional-issue") == 0)
{
options.gen.conditional_issue = enable_p;
}
else if (strcmp (argp, "conditional-issue") == 0)
{
options.gen.conditional_issue = enable_p;
options.warning (NULL, "Option conditional-issue replaced by gen-conditional-issue\n");
}
else if (strcmp (argp, "gen-delayed-branch") == 0)
{
options.gen.delayed_branch = enable_p;
}
else if (strcmp (argp, "delayed-branch") == 0)
{
options.gen.delayed_branch = enable_p;
options.warning (NULL, "Option delayed-branch replaced by gen-delayed-branch\n");
}
else if (strcmp (argp, "gen-direct-access") == 0)
{
options.gen.direct_access = enable_p;
}
else if (strcmp (argp, "direct-access") == 0)
{
options.gen.direct_access = enable_p;
options.warning (NULL, "Option direct-access replaced by gen-direct-access\n");
}
else if (strncmp (argp, "gen-zero-r", strlen ("gen-zero-r")) == 0)
{
options.gen.zero_reg = enable_p;
options.gen.zero_reg_nr = atoi (argp + strlen ("gen-zero-r"));
}
else if (strncmp (argp, "zero-r", strlen ("zero-r")) == 0)
{
options.gen.zero_reg = enable_p;
options.gen.zero_reg_nr = atoi (argp + strlen ("zero-r"));
options.warning (NULL, "Option zero-r<N> replaced by gen-zero-r<N>\n");
}
else if (strncmp (argp, "gen-icache", strlen ("gen-icache")) == 0)
{
switch (argp[strlen ("gen-icache")])
{
case '=':
options.gen.icache_size = atoi (argp + strlen ("gen-icache") + 1);
/* fall through */
case '\0':
options.gen.icache = enable_p;
break;
default:
error (NULL, "Expecting -Ggen-icache or -Ggen-icache=<N>\n");
}
}
else if (strcmp (argp, "gen-insn-in-icache") == 0)
{
options.gen.insn_in_icache = enable_p;
}
else if (strcmp (argp, "gen-multi-sim") == 0)
{
options.gen.multi_sim = enable_p;
}
else if (strcmp (argp, "gen-multi-word") == 0)
{
options.gen.multi_word = enable_p;
}
else if (strcmp (argp, "gen-semantic-icache") == 0)
{
options.gen.semantic_icache = enable_p;
}
else if (strcmp (argp, "gen-slot-verification") == 0)
{
options.gen.slot_verification = enable_p;
}
else if (strcmp (argp, "verify-slot") == 0)
{
options.gen.slot_verification = enable_p;
options.warning (NULL, "Option verify-slot replaced by gen-slot-verification\n");
}
else if (strcmp (argp, "gen-nia-invalid") == 0)
{
options.gen.nia = nia_is_invalid;
}
else if (strcmp (argp, "default-nia-minus-one") == 0)
{
options.gen.nia = nia_is_invalid;
options.warning (NULL, "Option default-nia-minus-one replaced by gen-nia-invalid\n");
}
else if (strcmp (argp, "gen-nia-void") == 0)
{
options.gen.nia = nia_is_void;
}
else if (strcmp (argp, "trace-combine") == 0)
{
options.trace.combine = enable_p;
}
else if (strcmp (argp, "trace-entries") == 0)
{
options.trace.entries = enable_p;
}
else if (strcmp (argp, "trace-rule-rejection") == 0)
{
options.trace.rule_rejection = enable_p;
}
else if (strcmp (argp, "trace-rule-selection") == 0)
{
options.trace.rule_selection = enable_p;
}
else if (strcmp (argp, "jumps") == 0)
{
options.gen.code = generate_jumps;
}
else if (strcmp (argp, "field-widths") == 0)
{
options.insn_specifying_widths = enable_p;
}
else if (strcmp (argp, "omit-line-numbers") == 0)
{
file_references = lf_omit_references;
}
else
{
error (NULL, "Unknown option %s\n", optarg);
}
break;
}
case 'i':
isa = load_insn_table (optarg, cache_rules);
if (isa->illegal_insn == NULL)

View file

@ -374,6 +374,7 @@ typedef enum {
function_record,
internal_record,
define_record,
include_record,
model_processor_record,
model_macro_record,
model_data_record,
@ -388,6 +389,7 @@ static const name_map insn_type_map[] = {
{ "compute", compute_record },
{ "scratch", scratch_record },
{ "define", define_record },
{ "include", include_record },
{ "%s", string_function_record },
{ "function", function_record },
{ "internal", internal_record },
@ -744,6 +746,17 @@ load_insn_table (char *file_name,
switch (record_type (record))
{
case include_record:
{
if (record->nr_fields < nr_include_record_fields)
error (record->line,
"Incorrect nr of fields for include record\n");
table_push (file, record->line, options.include,
record->field[include_record_filename_field]);
record = table_read (file);
break;
}
case option_record:
{
if (isa->insns != NULL)
@ -757,7 +770,7 @@ load_insn_table (char *file_name,
/* convert a string function field into an internal function field */
char *name;
if (record->nr_fields < nr_function_fields)
error (record->line, "Incorrect nr of fields for %s record\n");
error (record->line, "Incorrect nr of fields for %%s record\n");
name = NZALLOC (char,
(strlen ("str_")
+ strlen (record->field[function_name_field])
@ -1017,8 +1030,12 @@ load_insn_table (char *file_name,
break;
}
default:
error (record->line, "Unknown entry\n");
case unknown_record:
case define_record:
case code_record:
error (record->line, "Unknown or unexpected entry\n");
}
}
return isa;

608
sim/igen/ld-insn.h Normal file
View file

@ -0,0 +1,608 @@
/* This file is part of the program psim.
Copyright (C) 1994,1995,1996,1997 Andrew Cagney <cagney@highland.com.au>
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, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
typedef unsigned64 insn_uint;
/* Common among most entries:
*/
enum {
record_type_field = 1,
old_record_type_field = 2,
record_filter_flags_field = 2,
};
/* Include:
Include the specified file.
<include> ::=
":" "include"
":" <filter-flags>
":" <filename>
<nl>
;
*/
enum {
include_record_filename_field = 3,
nr_include_record_fields = 4,
};
/* Options:
Valid options are: hi-bit-nr (default 0), insn-bit-size (default
32), insn-specifying-widths (default true), multi-sim (default false).
<option> ::=
":" "option"
":" <filter-flags>
":" <option-name>
":" <option-value>
<nl>
;
<option-name> ::=
"insn-bit-size"
| "insn-specifying-widths"
| "hi-bit-nr"
| "flags-filter"
| "model-filter"
| "multi-sim"
| "format-names"
;
<option-value> ::=
"true"
| "false"
| <integer>
| <list>
;
These update the global options structure. */
enum {
option_name_field = 3,
option_value_field = 4,
nr_option_fields = 5,
};
/* Macro definitions:
<insn-macro> ::=
<expression>
":" "define"
":" <filter-flags>
":"
":" <name>
<nl>
;
Macro define/undef is currently unimplemented. */
/* Functions and internal routins:
<function> ::=
":" "function"
<function-spec>
;
<internal> ::=
":" "internal"
<function-spec>
;
<function-spec> ::=
":" <filter-flags>
":" <typedef>
":" <name>
[ ":" <parameter-list> ]
<nl>
<code-block>
;
*/
enum {
function_typedef_field = 3,
function_name_field = 4,
function_param_field = 5,
nr_function_fields = 5,
};
enum {
old_function_typedef_field = 0,
old_function_type_field = 2,
old_function_name_field = 4,
old_function_param_field = 5,
nr_old_function_fields = 6,
};
typedef struct _function_entry function_entry;
struct _function_entry {
line_ref *line;
filter *flags;
char *type;
char *name;
char *param;
table_entry *code;
int is_internal;
function_entry *next;
};
typedef void function_entry_handler
(lf *file,
function_entry *function,
void *data);
extern void function_entry_traverse
(lf *file,
function_entry *functions,
function_entry_handler *handler,
void *data);
/* cache-macro:
<cache-macro> ::=
":" <macro-type>
":" <filter-flags>
":" <type>
":" <name>
":" <field-name> { "," <field-name> }
":" <expression>
<nl>
;
<cache-macro-type> ::=
"scratch"
| "cache"
| "compute"
;
<name> ::=
<ident>
| <ident> "_is_" <integer>
;
A cache entry is defined (for an instruction) when all
<field-name>s are present as named opcode fields within the
instructions format.
SCRATCH and CACHE macros are defined during the cache fill stage
while CACHE and COMPUTE macros are defined during the instruction
execution stage.
*/
enum {
cache_type_field = 3,
cache_name_field = 4,
cache_original_fields_field = 5,
cache_expression_field = 6,
nr_cache_fields = 7,
};
typedef enum {
scratch_value,
cache_value,
compute_value,
} cache_entry_type;
typedef struct _cache_entry cache_entry;
struct _cache_entry {
line_ref *line;
filter *flags;
cache_entry_type entry_type;
char *name;
filter *original_fields;
char *type;
char *expression;
cache_entry *next;
};
/* Model specs:
<model-processor> ::=
":" "model"
":" <filter-flags>
":" <processor>
":" <long-processor>
":" <function-unit-data>
<nl>
;
<model-macro> ::=
":" "model-macro"
":" <filter-flags>
<nl>
<code-block>
;
<model-data> ::=
":" "model-data"
":" <filter-flags>
<nl>
<code-block>
;
<model-static> ::=
":" "model-static"
<function-spec>
;
<model-internal> ::=
":" "model-internal"
<function-spec>
;
<model-function> ::=
":" "model-internal"
<function-spec>
;
*/
enum {
nr_model_macro_fields = 3,
nr_model_data_fields = 3,
nr_model_static_fields = 6,
nr_model_internal_fields = 6,
nr_model_function_fields = 6,
};
typedef struct _model_data model_data;
struct _model_data {
line_ref *line;
filter *flags;
table_entry *entry;
table_entry *code;
model_data *next;
};
enum {
model_name_field = 3,
model_full_name_field = 4,
model_unit_data_field = 5,
nr_model_processor_fields = 6,
};
typedef struct _model_entry model_entry;
struct _model_entry {
line_ref *line;
filter *flags;
char *name;
char *full_name;
char *unit_data;
model_entry *next;
};
typedef struct _model_table model_table;
struct _model_table {
filter *processors;
int nr_models;
model_entry *models;
model_data *macros;
model_data *data;
function_entry *statics;
function_entry *internals;
function_entry *functions;
};
/* Instruction format:
An instruction is composed of a sequence of N bit instruction
words. Each word broken into a number of instruction fields.
Those fields being constant (ex. an opcode) or variable (register
spec).
<insn-word> ::=
<insn-field> { "," <insn-field> } ;
<insn-word> ::=
( <binary-value-implying-width>
| <field-name-implying-width>
| [ <start-or-width> "." ] <field>
)
{ "!" <excluded-value> }
;
<field> ::=
"*" +
| "/" +
| <field-name>
| "0x" <hex-value>
| "0b" <binary-value>
| "0" <octal-value>
| <integer-value> ;
*/
typedef struct _insn_field_exclusion insn_field_exclusion;
struct _insn_field_exclusion {
char *string;
insn_uint value;
insn_field_exclusion *next;
};
typedef enum {
insn_field_int,
insn_field_reserved,
insn_field_wild,
insn_field_string,
} insn_field_type;
typedef struct _insn_field_entry insn_field_entry;
struct _insn_field_entry {
int first;
int last;
int width;
int word_nr;
insn_field_type type;
insn_uint val_int;
char *pos_string;
char *val_string;
insn_field_exclusion *exclusions;
insn_field_entry *next;
insn_field_entry *prev;
};
typedef struct _insn_bit_entry insn_bit_entry;
struct _insn_bit_entry {
int value;
int mask;
insn_field_entry *field;
};
typedef struct _insn_entry insn_entry; /* forward */
typedef struct _insn_word_entry insn_word_entry;
struct _insn_word_entry {
/* list of sub-fields making up the instruction. bit provides
faster access to the field data for bit N. */
insn_field_entry *first;
insn_field_entry *last;
insn_bit_entry *bit[max_insn_bit_size];
/* set of all the string fields */
filter *field_names;
/* For multi-word instructions, The Nth word (from zero). */
insn_word_entry *next;
};
/* Instruction model:
Provides scheduling data for the code modeling the instruction unit.
<insn-model> ::=
"*" [ <processor> ]
":" <function-unit-data>
<nl>
;
If <processor> is NULL, the model is made the default for this
instruction.
*/
enum {
insn_model_name_field = 0,
insn_model_unit_data_field = 1,
nr_insn_model_fields = 1,
};
typedef struct _insn_model_entry insn_model_entry;
struct _insn_model_entry {
line_ref *line;
insn_entry *insn;
char *name;
char *full_name;
char *unit_data;
insn_model_entry *next;
};
/* Instruction mnemonic:
List of assembler mnemonics for the instruction.
<insn-mnenonic> ::=
"\"" <assembler-mnemonic> "\""
[ ":" <conditional-expression> ]
<nl>
;
*/
enum {
insn_mnemonic_format_field = 0,
insn_mnemonic_condition_field = 1,
nr_insn_mnemonic_fields = 1,
};
typedef struct _insn_mnemonic_entry insn_mnemonic_entry;
struct _insn_mnemonic_entry {
line_ref *line;
insn_entry *insn;
char *format;
char *condition;
insn_mnemonic_entry *next;
};
/* Instruction:
<insn> ::=
<insn-word> { "+" <insn-word> }
":" <format-name>
":" <filter-flags>
":" <options>
":" <name>
<nl>
{ <insn-model> }
{ <insn-mnemonic> }
<code-block>
*/
enum {
insn_word_field = 0,
insn_format_name_field = 1,
insn_filter_flags_field = 2,
insn_options_field = 3,
insn_name_field = 4,
nr_insn_fields = 5,
};
/* typedef struct _insn_entry insn_entry; */
struct _insn_entry {
line_ref *line;
filter *flags; /* filtered by options.filters */
char *format_name;
filter *options;
char *name;
/* the words that make up the instruction. Word provides direct
access to word N. Pseudo instructions can be identified by
nr_words == 0. */
int nr_words;
insn_word_entry *words;
insn_word_entry **word;
/* a set of all the fields from all the words */
filter *field_names;
/* an array of processor models, missing models are NULL! */
int nr_models;
insn_model_entry *models;
insn_model_entry **model;
filter *processors;
/* list of assember formats */
int nr_mnemonics;
insn_mnemonic_entry *mnemonics;
/* code body */
table_entry *code;
insn_entry *next;
};
/* Instruction table:
*/
typedef struct _insn_table insn_table;
struct _insn_table {
cache_entry *caches;
int max_nr_words;
int nr_insns;
insn_entry *insns;
function_entry *functions;
insn_entry *illegal_insn;
model_table *model;
filter *options;
filter *flags;
};
extern insn_table *load_insn_table
(char *file_name,
cache_entry *cache);
typedef void insn_entry_handler
(lf *file,
insn_table *isa,
insn_entry *insn,
void *data);
extern void insn_table_traverse_insn
(lf *file,
insn_table *isa,
insn_entry_handler *handler,
void *data);
/* Printing */
extern void print_insn_words
(lf *file,
insn_entry *insn);
/* Debugging */
void
dump_insn_field
(lf *file,
char *prefix,
insn_field_entry *field,
char *suffix);
void
dump_insn_word_entry
(lf *file,
char *prefix,
insn_word_entry *word,
char *suffix);
void
dump_insn_entry
(lf *file,
char *prefix,
insn_entry *insn,
char *suffix);
void
dump_cache_entries
(lf *file,
char *prefix,
cache_entry *entry,
char *suffix);
void
dump_insn_table
(lf *file,
char *prefix,
insn_table *isa,
char *suffix);

View file

@ -38,348 +38,598 @@
#include <stdlib.h>
#endif
struct _table {
typedef struct _open_table open_table;
struct _open_table {
size_t size;
char *buffer;
char *pos;
int nr_fields;
int nr_model_fields;
int line_nr;
char *file_name;
int current_file_line_offset;
char *current_file_name;
line_ref pseudo_line;
line_ref real_line;
open_table *parent;
table *root;
};
struct _table {
open_table *current;
};
extern table *
table_open(const char *file_name,
int nr_fields,
int nr_model_fields)
static line_ref *
current_line (open_table *file)
{
line_ref *entry = ZALLOC (line_ref);
*entry = file->pseudo_line;
return entry;
}
static table_entry *
new_table_entry (open_table *file,
table_entry_type type)
{
table_entry *entry;
entry = ZALLOC (table_entry);
entry->file = file->root;
entry->line = current_line (file);
entry->type = type;
return entry;
}
static void
set_nr_table_entry_fields (table_entry *entry,
int nr_fields)
{
entry->field = NZALLOC (char*, nr_fields + 1);
entry->nr_fields = nr_fields;
}
void
table_push (table *root,
line_ref *line,
table_include *includes,
const char *file_name)
{
int fd;
struct stat stat_buf;
table *file;
open_table *file;
table_include dummy;
table_include *include = &dummy;
/* dummy up a search of this directory */
dummy.next = includes;
dummy.dir = "";
/* create a file descriptor */
file = ZALLOC(table);
ASSERT(file != NULL);
file->nr_fields = nr_fields;
file->nr_model_fields = nr_model_fields;
file = ZALLOC (open_table);
if (file == NULL)
{
perror (file_name);
exit (1);
}
file->root = root;
file->parent = root->current;
root->current = file;
/* save the file name */
file->file_name = (char*)zalloc(strlen(file_name) + 1);
ASSERT(file->file_name != NULL);
strcpy(file->file_name, file_name);
file->current_file_name = file->file_name;
/* open the file */
fd = open(file->file_name, O_RDONLY, 0);
if (fd < 0) {
perror(file->file_name);
exit (1);
while (1)
{
/* save the file name */
char *dup_name = NZALLOC (char, strlen (include->dir) + strlen (file_name) + 2);
if (dup_name == NULL)
{
perror (file_name);
exit (1);
}
if (include->dir[0] != '\0')
{
strcat (dup_name, include->dir);
strcat (dup_name, "/");
}
strcat (dup_name, file_name);
file->real_line.file_name = dup_name;
file->pseudo_line.file_name = dup_name;
printf ("Trying `%s'\n", dup_name);
/* open the file */
fd = open (dup_name, O_RDONLY, 0);
if (fd >= 0)
break;
/* zfree (dup_name); */
if (include->next == NULL)
{
if (line != NULL)
error (line, "Problem opening file `%s'\n", file_name);
perror (file_name);
exit (1);
}
include = include->next;
}
/* determine the size */
if (fstat(fd, &stat_buf) < 0) {
perror("table_open.fstat");
exit(1);
if (fstat (fd, &stat_buf) < 0) {
perror (file_name);
exit (1);
}
file->size = stat_buf.st_size;
/* allocate this much memory */
file->buffer = (char*)zalloc(file->size+1);
ASSERT(file->buffer != NULL);
file->buffer = (char*) zalloc (file->size + 1);
if (file->buffer == NULL)
{
perror (file_name);
exit (1);
}
file->pos = file->buffer;
/* read it in */
if (read(fd, file->buffer, file->size) < file->size) {
perror(file->file_name);
exit(1);
/* read it all in */
if (read (fd, file->buffer, file->size) < file->size) {
perror (file_name);
exit (1);
}
file->buffer[file->size] = '\0';
/* set the initial line numbering */
file->line_nr = 0;
file->current_file_line_offset = 0;
file->real_line.line_nr = 1; /* specifies current line */
file->pseudo_line.line_nr = 1; /* specifies current line */
/* done */
close(fd);
return file;
close (fd);
}
table *
table_open (const char *file_name)
{
table *root;
/* create a file descriptor */
root = ZALLOC (table);
if (root == NULL)
{
perror (file_name);
exit (1);
}
table_push (root, NULL, NULL, file_name);
return root;
}
char *
skip_spaces (char *chp)
{
while (1)
{
if (*chp == '\0'
|| *chp == '\n'
|| !isspace (*chp))
return chp;
chp++;
}
}
char *
back_spaces (char *start, char *chp)
{
while (1)
{
if (chp <= start
|| !isspace (chp[-1]))
return chp;
chp--;
}
}
char *
skip_digits (char *chp)
{
while (1)
{
if (*chp == '\0'
|| *chp == '\n'
|| !isdigit (*chp))
return chp;
chp++;
}
}
char *
skip_to_separator (char *chp,
char *separators)
{
while (1)
{
char *sep = separators;
while (1)
{
if (*chp == *sep)
return chp;
if (*sep == '\0')
break;
sep++;
}
chp++;
}
}
static char *
skip_to_null (char *chp)
{
return skip_to_separator (chp, "");
}
static char *
skip_to_nl (char * chp)
{
return skip_to_separator (chp, "\n");
}
static void
next_line (open_table *file)
{
file->pos = skip_to_nl (file->pos);
if (*file->pos == '0')
error (&file->pseudo_line, "Missing <nl> at end of line\n");
*file->pos = '\0';
file->pos += 1;
file->real_line.line_nr += 1;
file->pseudo_line.line_nr += 1;
}
extern table_entry *
table_entry_read(table *file)
table_read (table *root)
{
int field;
table_entry *entry;
open_table *file = root->current;
table_entry *entry = NULL;
while(1)
{
/* skip comments/blanks */
while(1) {
/* leading white space */
while (*file->pos != '\0'
&& *file->pos != '\n'
&& isspace(*file->pos))
file->pos++;
/* cpp line nr directive - # <line-nr> "<file>" */
if (file->pos[0] == '#'
&& file->pos[1] == ' '
&& isdigit(file->pos[2])) {
file->pos += strlen("# ");
/* parse the number */
file->current_file_line_offset = atoi(file->pos) - file->line_nr - 2;
/* skip to the file name */
while (file->pos[0] != '0'
&& file->pos[0] != '"'
&& file->pos[0] != '\0')
file->pos++;
if (file->pos[0] != '"') {
error("%s:%d: Missing opening quote",
file->file_name,
file->line_nr);
}
/* parse the file name */
file->pos++;
file->current_file_name = file->pos;
while (file->pos[0] != '"'
&& file->pos[0] != '\0')
file->pos++;
if (file->pos[0] != '"') {
error("%s:%d: Missing closing quote",
file->file_name,
file->line_nr);
}
file->pos[0] = '\0';
file->pos ++;
while (file->pos[0] != '\0'
&& file->pos[0] != '\n')
file->pos[0]++;
if (file->pos[0] != '\n')
error("%s:%d: Missing newline",
file->file_name,
file->line_nr);
}
/* comment - leading // or # - skip */
else if ((file->pos[0] == '/' && file->pos[1] == '/')
|| (file->pos[0] == '#')) {
do {
file->pos++;
} while (*file->pos != '\0' && *file->pos != '\n');
}
/* end of line? */
if (*file->pos == '\n') {
file->pos++;
file->line_nr++;
}
else
break;
}
if (*file->pos == '\0')
return NULL;
/* create this new entry */
entry = (table_entry*)zalloc(sizeof(table_entry)
+ (file->nr_fields + 1) * sizeof(char*));
ASSERT(entry != NULL);
entry->file_name = file->current_file_name;
entry->nr_fields = file->nr_fields;
/* break the line into its colon delimitered fields */
for (field = 0; field < file->nr_fields-1; field++) {
entry->fields[field] = file->pos;
while(*file->pos && *file->pos != ':' && *file->pos != '\n')
file->pos++;
if (*file->pos == ':') {
*file->pos = '\0';
file->pos++;
}
}
/* any trailing stuff not the last field */
ASSERT(field == file->nr_fields-1);
entry->fields[field] = file->pos;
while (*file->pos && *file->pos != '\n') {
file->pos++;
}
if (*file->pos == '\n') {
*file->pos = '\0';
file->pos++;
}
file->line_nr++;
/* If following lines being with a double quote ("), add them to the
list of assembler lines */
{
table_assembler_entry **current = &entry->assembler;
while (*file->pos == '"') {
char *tmpchp;
const char *format;
int strlen_format;
const char *condition;
int strlen_condition;
/* skip over the format string */
format = file->pos;
strlen_format = 0;
do {
if (file->pos[0] == '\\' && file->pos[1] == '"')
file->pos += 2;
else
file->pos += 1;
} while (*file->pos != '\0' && *file->pos != '\n' && *file->pos != '"');
if (*file->pos != '"')
error ("%s:%d: Missing closing quote in assembler line",
file->file_name,
file->line_nr);
file->pos++;
strlen_format = file->pos - format;
/* skip over the boolean condition */
condition = NULL;
strlen_condition = 0;
if (*file->pos == ':')
/* end-of-file? */
while (*file->pos == '\0')
{
file->pos++;
while (isspace(*file->pos) && *file->pos != '\0' && *file->pos != '\n')
file->pos++;
condition = file->pos;
while (*file->pos != '\0' && *file->pos != '\n')
file->pos++;
strlen_condition = file->pos - condition;
if (file->parent != NULL)
{
file = file->parent;
root->current = file;
}
else
return NULL;
}
/* create the new assembler entry */
*current = ZALLOC (table_assembler_entry);
tmpchp = zalloc (strlen_format + 1);
strncpy (tmpchp, format, strlen_format);
(*current)->format = tmpchp;
(*current)->file_name = file->file_name;
(*current)->line_nr = file->line_nr;
if (condition != NULL && strlen_condition > 0)
/* code_block? */
if (*file->pos == '{')
{
tmpchp = zalloc (strlen_condition + 1);
strncpy (tmpchp, condition, strlen_condition);
(*current)->condition = tmpchp;
char *chp;
next_line (file); /* discard leading brace */
entry = new_table_entry (file, table_code_entry);
chp = file->pos;
/* determine how many lines are involved - look for <nl> "}" */
{
int nr_lines = 0;
while (*file->pos != '}')
{
next_line (file);
nr_lines++;
}
set_nr_table_entry_fields (entry, nr_lines);
}
/* now enter each line */
{
int line_nr;
for (line_nr = 0; line_nr < entry->nr_fields; line_nr++)
{
if (strncmp (chp, " ", 2) == 0)
entry->field[line_nr] = chp + 2;
else
entry->field[line_nr] = chp;
chp = skip_to_null (chp) + 1;
}
/* skip trailing brace */
ASSERT (*file->pos == '}');
next_line (file);
}
break;
}
current = &(*current)->next;
/* end of line? */
if (*file->pos != '\n')
error ("%s:%d: Missing eoln in assembler line",
file->file_name,
file->line_nr);
file->pos++;
file->line_nr++;
}
}
/* tab block? */
if (*file->pos == '\t')
{
char *chp = file->pos;
entry = new_table_entry (file, table_code_entry);
/* determine how many lines are involved - look for <nl> !<tab> */
{
int nr_lines = 0;
int nr_blank_lines = 0;
while (1)
{
if (*file->pos == '\t')
{
nr_lines = nr_lines + nr_blank_lines + 1;
nr_blank_lines = 0;
next_line (file);
}
else
{
file->pos = skip_spaces (file->pos);
if (*file->pos != '\n')
break;
nr_blank_lines++;
next_line (file);
}
}
set_nr_table_entry_fields (entry, nr_lines);
}
/* now enter each line */
{
int line_nr;
for (line_nr = 0; line_nr < entry->nr_fields; line_nr++)
{
if (*chp == '\t')
entry->field[line_nr] = chp + 1;
else
entry->field[line_nr] = ""; /* blank */
chp = skip_to_null (chp) + 1;
}
}
break;
}
/* if following lines begin with a star, add them to the model
section. */
while ((file->nr_model_fields > 0) && (*file->pos == '*')) {
table_model_entry *model = (table_model_entry*)zalloc(sizeof(table_model_entry)
+ (file->nr_model_fields + 1) * sizeof(char*));
if (entry->model_last)
entry->model_last->next = model;
else
entry->model_first = model;
entry->model_last = model;
/* cpp directive? */
if (file->pos[0] == '#')
{
char *chp = skip_spaces (file->pos + 1);
/* break the line into its colon delimitered fields */
file->pos++;
for (field = 0; field < file->nr_model_fields-1; field++) {
model->fields[field] = file->pos;
while(*file->pos && *file->pos != ':' && *file->pos != '\n')
file->pos++;
if (*file->pos == ':') {
*file->pos = '\0';
file->pos++;
/* cpp line-nr directive - # <line-nr> "<file>" */
if (isdigit (*chp)
&& *skip_digits (chp) == ' '
&& *skip_spaces (skip_digits (chp)) == '"')
{
int line_nr;
char *file_name;
file->pos = chp;
/* parse the number */
line_nr = atoi(file->pos) - 1;
/* skip to the file name */
while (file->pos[0] != '0'
&& file->pos[0] != '"'
&& file->pos[0] != '\0')
file->pos++;
if (file->pos[0] != '"')
error (&file->real_line, "Missing opening quote in cpp directive\n");
/* parse the file name */
file->pos++;
file_name = file->pos;
while (file->pos[0] != '"'
&& file->pos[0] != '\0')
file->pos++;
if (file->pos[0] != '"')
error (&file->real_line, "Missing closing quote in cpp directive\n");
file->pos[0] = '\0';
file->pos++;
file->pos = skip_to_nl (file->pos);
if (file->pos[0] != '\n')
error (&file->real_line, "Missing newline in cpp directive\n");
file->pseudo_line.file_name = file_name;
file->pseudo_line.line_nr = line_nr;
next_line (file);
continue;
}
/* #define and #undef - not implemented yet */
/* Old style # comment */
next_line (file);
continue;
}
/* blank line or end-of-file? */
file->pos = skip_spaces (file->pos);
if (*file->pos == '\0')
error (&file->pseudo_line, "Missing <nl> at end of file\n");
if (*file->pos == '\n')
{
next_line (file);
continue;
}
/* comment - leading // or # - skip */
if ((file->pos[0] == '/' && file->pos[1] == '/')
|| (file->pos[0] == '#'))
{
next_line (file);
continue;
}
/* colon field */
{
char *chp = file->pos;
entry = new_table_entry (file, table_colon_entry);
next_line (file);
/* figure out how many fields */
{
int nr_fields = 1;
char *tmpch = chp;
while (1)
{
tmpch = skip_to_separator (tmpch, "\\:");
if (*tmpch == '\\')
{
/* eat the escaped character */
char *cp = tmpch;
while (cp[1] != '\0')
{
cp[0] = cp[1];
cp++;
}
cp[0] = '\0';
tmpch++;
}
else if (*tmpch != ':')
break;
else
{
*tmpch = '\0';
tmpch++;
nr_fields++;
}
}
set_nr_table_entry_fields (entry, nr_fields);
}
/* now parse them */
{
int field_nr;
for (field_nr = 0; field_nr < entry->nr_fields; field_nr++)
{
chp = skip_spaces (chp);
entry->field[field_nr] = chp;
chp = skip_to_null (chp);
*back_spaces (entry->field[field_nr], chp) = '\0';
chp++;
}
}
break;
}
}
/* any trailing stuff not the last field */
ASSERT(field == file->nr_model_fields-1);
model->fields[field] = file->pos;
while (*file->pos && *file->pos != '\n') {
file->pos++;
}
if (*file->pos == '\n') {
*file->pos = '\0';
file->pos++;
}
file->line_nr++;
model->line_nr = file->current_file_line_offset + file->line_nr;
}
entry->line_nr = file->current_file_line_offset + file->line_nr;
/* if following lines are tab indented, put in the annex */
if (*file->pos == '\t') {
entry->annex = file->pos;
do {
do {
file->pos++;
} while (*file->pos != '\0' && *file->pos != '\n');
if (*file->pos == '\n') {
char *save_pos = ++file->pos;
int extra_lines = 0;
file->line_nr++;
/* Allow tab indented to have blank lines */
while (*save_pos == '\n') {
save_pos++;
extra_lines++;
}
if (*save_pos == '\t') {
file->pos = save_pos;
file->line_nr += extra_lines;
}
}
} while (*file->pos != '\0' && *file->pos == '\t');
if (file->pos[-1] == '\n')
file->pos[-1] = '\0';
}
else
entry->annex = NULL;
/* return it */
ASSERT (entry == NULL || entry->field[entry->nr_fields] == NULL);
return entry;
}
extern void
dump_table_entry(table_entry *entry,
int indent)
table_print_code (lf *file,
table_entry *entry)
{
printf("(table_entry*)%p\n", entry);
if (entry != NULL) {
int field;
char sep;
sep = ' ';
dumpf(indent, "(fields");
for (field = 0; field < entry->nr_fields; field++) {
printf("%c%s", sep, entry->fields[field]);
sep = ':';
int field_nr;
int nr = 0;
for (field_nr = 0;
field_nr < entry->nr_fields;
field_nr++)
{
char *chp = entry->field[field_nr];
int in_bit_field = 0;
if (*chp == '#')
lf_indent_suppress(file);
while (*chp != '\0')
{
if (chp[0] == '{'
&& !isspace(chp[1])
&& chp[1] != '\0')
{
in_bit_field = 1;
nr += lf_putchr(file, '_');
}
else if (in_bit_field && chp[0] == ':')
{
nr += lf_putchr(file, '_');
}
else if (in_bit_field && *chp == '}')
{
nr += lf_putchr(file, '_');
in_bit_field = 0;
}
else
{
nr += lf_putchr(file, *chp);
}
chp++;
}
if (in_bit_field)
{
line_ref line = *entry->line;
line.line_nr += field_nr;
error (&line, "Bit field brace miss match\n");
}
nr += lf_putchr(file, '\n');
}
printf(")\n");
dumpf(indent, "(line_nr %d)\n", entry->line_nr);
dumpf(indent, "(file_name %s)\n", entry->file_name);
dumpf(indent, "(annex\n%s\n", entry->annex);
dumpf(indent, " )\n");
}
}
extern void
table_entry_print_cpp_line_nr(lf *file,
table_entry *entry)
void
dump_line_ref (lf *file,
char *prefix,
const line_ref *line,
char *suffix)
{
lf_print__external_reference(file, entry->line_nr, entry->file_name);
lf_printf (file, "%s(line_ref*) 0x%lx", prefix, (long) line);
if (line != NULL)
{
lf_indent (file, +1);
lf_printf (file, "\n(line_nr %d)", line->line_nr);
lf_printf (file, "\n(file_name %s)", line->file_name);
lf_indent (file, -1);
}
lf_printf (file, "%s", suffix);
}
static const char *
table_entry_type_to_str (table_entry_type type)
{
switch (type)
{
case table_code_entry: return "code-entry";
case table_colon_entry: return "colon-entry";
}
return "*invalid*";
}
void
dump_table_entry(lf *file,
char *prefix,
const table_entry *entry,
char *suffix)
{
lf_printf (file, "%s(table_entry*) 0x%lx", prefix, (long) entry);
if (entry != NULL)
{
int field;
lf_indent (file, +1);
dump_line_ref (file, "\n(line ", entry->line, ")");
lf_printf (file, "\n(type %s)", table_entry_type_to_str (entry->type));
lf_printf (file, "\n(nr_fields %d)", entry->nr_fields);
lf_printf (file, "\n(fields");
lf_indent (file, +1);
for (field = 0; field < entry->nr_fields; field++)
lf_printf (file, "\n\"%s\"", entry->field[field]);
lf_indent (file, -1);
lf_printf (file, ")");
lf_indent (file, -1);
}
lf_printf (file, "%s", suffix);
}
#ifdef MAIN
int
main(int argc, char **argv)
{
table *t;
table_entry *entry;
lf *l;
int line_nr;
if (argc != 2)
{
printf("Usage: table <file>\n");
exit (1);
}
t = table_open (argv[1]);
l = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "tmp-table");
line_nr = 0;
do
{
char line[10];
entry = table_read (t);
line_nr ++;
sprintf (line, "(%d ", line_nr);
dump_table_entry (l, line, entry, ")\n");
}
while (entry != NULL);
return 0;
}
#endif