633 lines
13 KiB
C
633 lines
13 KiB
C
/* This file is part of the program psim.
|
|
|
|
Copyright (C) 1994-1995,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.
|
|
|
|
*/
|
|
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <ctype.h>
|
|
|
|
#include "config.h"
|
|
#include "misc.h"
|
|
#include "lf.h"
|
|
#include "table.h"
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_STDLIB_H
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
typedef struct _open_table open_table;
|
|
struct _open_table {
|
|
size_t size;
|
|
char *buffer;
|
|
char *pos;
|
|
line_ref pseudo_line;
|
|
line_ref real_line;
|
|
open_table *parent;
|
|
table *root;
|
|
};
|
|
struct _table {
|
|
open_table *current;
|
|
};
|
|
|
|
|
|
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)
|
|
{
|
|
FILE *ff;
|
|
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 (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;
|
|
/* open the file */
|
|
|
|
ff = fopen (dup_name, "rb");
|
|
if (ff)
|
|
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 */
|
|
fseek (ff, 0, SEEK_END);
|
|
file->size = ftell (ff);
|
|
fseek (ff, 0, SEEK_SET);
|
|
|
|
/* allocate this much memory */
|
|
file->buffer = (char*) zalloc (file->size + 1);
|
|
if (file->buffer == NULL)
|
|
{
|
|
perror (file_name);
|
|
exit (1);
|
|
}
|
|
file->pos = file->buffer;
|
|
|
|
/* read it all in */
|
|
if (fread (file->buffer, 1, file->size, ff) < file->size) {
|
|
perror (file_name);
|
|
exit (1);
|
|
}
|
|
file->buffer[file->size] = '\0';
|
|
|
|
/* set the initial line numbering */
|
|
file->real_line.line_nr = 1; /* specifies current line */
|
|
file->pseudo_line.line_nr = 1; /* specifies current line */
|
|
|
|
/* done */
|
|
fclose (ff);
|
|
}
|
|
|
|
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_read (table *root)
|
|
{
|
|
open_table *file = root->current;
|
|
table_entry *entry = NULL;
|
|
while(1)
|
|
{
|
|
|
|
/* end-of-file? */
|
|
while (*file->pos == '\0')
|
|
{
|
|
if (file->parent != NULL)
|
|
{
|
|
file = file->parent;
|
|
root->current = file;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
/* code_block? */
|
|
if (*file->pos == '{')
|
|
{
|
|
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;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
}
|
|
|
|
ASSERT (entry == NULL || entry->field[entry->nr_fields] == NULL);
|
|
return entry;
|
|
}
|
|
|
|
extern void
|
|
table_print_code (lf *file,
|
|
table_entry *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');
|
|
}
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
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
|