Add include-file support to igen.
authorAndrew Cagney <cagney@redhat.com>
Mon, 27 Oct 1997 06:30:35 +0000 (06:30 +0000)
committerAndrew Cagney <cagney@redhat.com>
Mon, 27 Oct 1997 06:30:35 +0000 (06:30 +0000)
sim/igen/ChangeLog
sim/igen/igen.c
sim/igen/ld-insn.c
sim/igen/ld-insn.h [new file with mode: 0644]
sim/igen/table.c

index aba94cb..b535133 100644 (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
index 0fbe8e5..afd2904 100644 (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)
index eaa7eca..c5c3679 100644 (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;
diff --git a/sim/igen/ld-insn.h b/sim/igen/ld-insn.h
new file mode 100644 (file)
index 0000000..be6f4be
--- /dev/null
@@ -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);
index 461a632..71be438 100644 (file)
 #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;
-
-  /* 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);
+  file = ZALLOC (open_table);
+  if (file == NULL)
+    {
+      perror (file_name);
+      exit (1);
+    }
+  file->root = root;
+  file->parent = root->current;
+  root->current = file;
+
+  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);
 }
 
-
-extern table_entry *
-table_entry_read(table *file)
+table *
+table_open (const char *file_name)
 {
-  int field;
-  table_entry *entry;
+  table *root;
 
-  /* 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);
+  /* create a file descriptor */
+  root = ZALLOC (table);
+  if (root == NULL)
+    {
+      perror (file_name);
+      exit (1);
     }
-    /* 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');
+
+  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++;
     }
-    /* end of line? */
-    if (*file->pos == '\n') {
-      file->pos++;
-      file->line_nr++;
+}
+
+
+char *
+back_spaces (char *start, char *chp)
+{
+  while (1)
+    {
+      if (chp <= start
+         || !isspace (chp[-1]))
+       return chp;
+      chp--;
     }
-    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++;
+}
+
+char *
+skip_digits (char *chp)
+{
+  while (1)
+    {
+      if (*chp == '\0'
+         || *chp == '\n'
+         || !isdigit (*chp))
+       return chp;
+      chp++;
     }
-  }
+}
 
-  /* 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 == ':')
+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_read (table *root)
+{
+  open_table *file = root->current;
+  table_entry *entry = NULL;
+  while(1)
+    {
+
+      /* 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++;
-    }
-  }
 
-  /* 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;
-
-    /* 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++;
-      }
-    }
+      /* 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;
+       }
 
-    /* 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++;
-    }
+      /* cpp directive? */
+      if (file->pos[0] == '#')
+       {
+         char *chp = skip_spaces (file->pos + 1);
+
+         /* 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;
+       }
 
-    file->line_nr++;
-    model->line_nr = file->current_file_line_offset + file->line_nr;
-  }
+      /* 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;
+       }
 
-  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++;
+      /* comment - leading // or # - skip */
+      if ((file->pos[0] == '/' && file->pos[1] == '/')
+         || (file->pos[0] == '#'))
+       {
+         next_line (file);
+         continue;
        }
-       if (*save_pos == '\t') {
-         file->pos = save_pos;
-         file->line_nr += extra_lines;
+
+      /* 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;
       }
-    } while (*file->pos != '\0' && *file->pos == '\t');
-    if (file->pos[-1] == '\n')
-      file->pos[-1] = '\0';
-  }
-  else
-    entry->annex = NULL;
 
-  /* return it */
-  return entry;
+    }
 
+  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);
+  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');
+    }
+}
 
-  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 = ':';
-    }
-    printf(")\n");
 
-    dumpf(indent, "(line_nr %d)\n", entry->line_nr);
+void
+dump_line_ref (lf *file,
+                char *prefix,
+                const line_ref *line,
+                char *suffix)
+{
+  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);
+}
 
-    dumpf(indent, "(file_name %s)\n", entry->file_name);
 
-    dumpf(indent, "(annex\n%s\n", entry->annex);
-    dumpf(indent, " )\n");
+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);
 }
 
 
-extern void
-table_entry_print_cpp_line_nr(lf *file,
-                             table_entry *entry)
+#ifdef MAIN
+int
+main(int argc, char **argv)
 {
-  lf_print__external_reference(file, entry->line_nr, entry->file_name);
-}
+  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