#endif
static int files_open = 0;
-/*@null@*/ /*@only@*/ static char *obj_filename = NULL;
+/*@null@*/ /*@only@*/ static char *obj_filename = NULL, *in_filename = NULL;
/*@null@*/ static FILE *in = NULL, *obj = NULL;
/* Forward declarations: cmd line parser handlers */
/* if no files were specified, fallback to reading stdin */
if (!in) {
in = stdin;
- switch_filename("<STDIN>");
+ in_filename = xstrdup("<STDIN>");
if (!obj)
obj = stdout;
}
+ /* Initialize line info */
+ line_set(in_filename, 1, 1);
+
/* Set x86 as the architecture */
cur_arch = &x86_arch;
if (OutputAllErrorWarning() > 0) {
sections_delete(sections);
symrec_delete_all();
- filename_delete_all();
+ line_shutdown();
+ floatnum_shutdown();
BitVector_Shutdown();
return EXIT_FAILURE;
}
sections_delete(sections);
symrec_delete_all();
- filename_delete_all();
+ line_shutdown();
floatnum_shutdown();
WarningNow("can open only one input file, only latest file will be processed");
if(fclose(in))
ErrorNow("could not close old input file");
+ if (in_filename)
+ xfree(in_filename);
}
in = fopen(param, "rt");
ErrorNow(_("could not open file `%s'"), param);
return 1;
}
- switch_filename(param);
+ in_filename = xstrdup(param);
files_open++;
return 0;
multiple copies), 0 if unknown */
/* where it came from */
- /*@dependent@*/ /*@null@*/ const char *filename;
- unsigned int lineno;
+ unsigned int line;
/* other assembler state info */
unsigned long offset; /* 0 if unknown */
bc->multiple = (expr *)NULL;
bc->len = 0;
- bc->filename = in_filename;
- bc->lineno = line_number;
+ bc->line = line_index;
bc->offset = 0;
const bytecode_data *data;
const bytecode_reserve *reserve;
const bytecode_incbin *incbin;
+ const char *filename;
+ unsigned long line;
switch (bc->type) {
case BC_EMPTY:
else
expr_print(f, bc->multiple);
fprintf(f, "\n%*sLength=%lu\n", indent_level, "", bc->len);
- fprintf(f, "%*sFilename=\"%s\" Line Number=%u\n", indent_level, "",
- bc->filename ? bc->filename : "<UNKNOWN>", bc->lineno);
+ line_lookup(bc->line, &filename, &line);
+ fprintf(f, "%*sFilename=\"%s\" Line Number=%lu\n", indent_level, "",
+ filename, line);
fprintf(f, "%*sOffset=%lx\n", indent_level, "", bc->offset);
}
enum { WE_ERROR, WE_WARNING } type;
- /*@dependent@*/ const char *filename;
unsigned long line;
/* FIXME: This should not be a fixed size. But we don't have vasprintf()
* right now. */
va_list ap;
errwarn *we;
- if ((previous_error_line == line_number) && !previous_error_parser)
+ if ((previous_error_line == line_index) && !previous_error_parser)
return;
if (!errwarns) {
we = xmalloc(sizeof(errwarn));
we->type = WE_ERROR;
- we->filename = in_filename;
- we->line = line_number;
+ we->line = line_index;
}
assert(we != NULL);
STAILQ_INSERT_TAIL(errwarns, we, link);
/*@=branchstate@*/
- previous_error_line = line_number;
+ previous_error_line = line_index;
previous_error_parser = 0;
error_count++;
va_list ap;
errwarn *we;
- if (previous_warning_line == line_number)
+ if (previous_warning_line == line_index)
return;
- previous_warning_line = line_number;
+ previous_warning_line = line_index;
we = xmalloc(sizeof(errwarn));
we->type = WE_WARNING;
- we->filename = in_filename;
- we->line = line_number;
+ we->line = line_index;
va_start(ap, fmt);
vsprintf(we->msg, fmt, ap);
va_end(ap);
}
void
-ErrorAt(const char *filename, unsigned long line, const char *fmt, ...)
+ErrorAt(unsigned long index, const char *fmt, ...)
{
/* XXX: Should insert into list instead of printing immediately */
va_list ap;
+ const char *filename;
+ unsigned long line;
+ line_lookup(index, &filename, &line);
fprintf(stderr, "%s:%lu: ", filename?filename:"(NULL)", line);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
}
void
-WarningAt(const char *filename, unsigned long line, const char *fmt, ...)
+WarningAt(unsigned long index, const char *fmt, ...)
{
/* XXX: Should insert into list instead of printing immediately */
va_list ap;
+ const char *filename;
+ unsigned long line;
+ line_lookup(index, &filename, &line);
fprintf(stderr, "%s:%lu: %s ", filename?filename:"NULL", line,
_("warning:"));
va_start(ap, fmt);
OutputAllErrorWarning(void)
{
errwarn *we, *we2;
+ const char *filename;
+ unsigned long line;
/* If errwarns hasn't been initialized, there are no messages. */
if (!errwarns)
/* Output error and warning messages. */
STAILQ_FOREACH(we, errwarns, link) {
+ line_lookup(we->line, &filename, &line);
if (we->type == WE_ERROR)
- fprintf(stderr, "%s:%lu: %s\n", we->filename, we->line, we->msg);
+ fprintf(stderr, "%s:%lu: %s\n", filename, line, we->msg);
else
- fprintf(stderr, "%s:%lu: %s %s\n", we->filename, we->line,
- _("warning:"), we->msg);
+ fprintf(stderr, "%s:%lu: %s %s\n", filename, line, _("warning:"),
+ we->msg);
}
/* Delete messages. */
* called in line order from a parser. The *At() functions are much slower,
* at least in the current implementation.
*/
-void ErrorAt(/*@null@*/ const char *filename, unsigned long line, const char *,
- ...) /*@printflike@*/;
-void WarningAt(/*@null@*/ const char *filename, unsigned long line,
- const char *, ...) /*@printflike@*/;
+void ErrorAt(unsigned long index, const char *, ...) /*@printflike@*/;
+void WarningAt(unsigned long index, const char *, ...) /*@printflike@*/;
/* These two functions immediately output the error or warning, with no file
* or line information. They should be used for errors and warnings outside
*/
struct expr {
ExprOp op;
- /*@dependent@*/ /*@null@*/ const char *filename;
unsigned long line;
int numterms;
ExprItem terms[2]; /* structure may be extended to include more */
}
}
- ptr->filename = in_filename;
- ptr->line = line_number;
+ ptr->line = line_index;
return ptr;
}
/* Build -1*ei subexpression */
sube->op = EXPR_MUL;
- sube->filename = e->filename;
sube->line = e->line;
sube->numterms = 2;
sube->terms[0].type = EXPR_INT;
*/
ne = xmalloc(sizeof(expr));
ne->op = EXPR_MUL;
- ne->filename = e->filename;
ne->line = e->line;
ne->numterms = 2;
ne->terms[0].type = EXPR_INT;
n = xmalloc(sizeof(expr)+sizeof(ExprItem)*(e->numterms<2?0:e->numterms-2));
n->op = e->op;
- n->filename = e->filename;
n->line = e->line;
n->numterms = e->numterms;
for (i=0; i<e->numterms; i++) {
/* Current (selected) object format) */
/*@null@*/ objfmt *cur_objfmt = NULL;
-/*@null@*/ /*@dependent@*/ const char *in_filename = (const char *)NULL;
-unsigned int line_number = 1;
-unsigned int line_number_inc = 1;
-unsigned int asm_options = 0;
+/* Source lines tracking */
+/* FIXME: Need better data structure for this than a linked list. */
+typedef /*@reldef@*/ STAILQ_HEAD(line_index_mapping_head, line_index_mapping)
+ line_index_mapping_head;
+typedef struct line_index_mapping {
+ /*@reldef@*/ STAILQ_ENTRY(line_index_mapping) link;
-int indent_level = 0;
+ /* monotonically increasing line index */
+ unsigned long index;
+ /* related info */
+ /* "original" source filename */
+ /*@null@*/ /*@dependent@*/ const char *filename;
+ /* "original" source base line number */
+ unsigned long line;
+ /* "original" source line number increment (for following lines) */
+ unsigned int line_inc;
+} line_index_mapping;
+/* Shared storage for filenames */
static /*@only@*/ /*@null@*/ HAMT *filename_table = NULL;
+/* Virtual line number. Uniquely specifies every line read by the parser. */
+unsigned long line_index = 1;
+static line_index_mapping_head *line_index_map = NULL;
+
+/* Global assembler options. */
+unsigned int asm_options = 0;
+
+/* Indentation level for assembler *_print() routines */
+int indent_level = 0;
+
static void
filename_delete_one(/*@only@*/ void *d)
{
}
void
-switch_filename(const char *filename)
+line_set(const char *filename, unsigned long line, unsigned long line_inc)
{
- char *copy = xstrdup(filename);
+ char *copy;
int replace = 0;
+ line_index_mapping *mapping;
+
+ /* Build a mapping */
+ mapping = xmalloc(sizeof(line_index_mapping));
+
+ /* Copy the filename (via shared storage) */
+ copy = xstrdup(filename);
if (!filename_table)
filename_table = HAMT_new();
/*@-aliasunique@*/
- in_filename = HAMT_insert(filename_table, copy, copy, &replace,
- filename_delete_one);
+ mapping->filename = HAMT_insert(filename_table, copy, copy, &replace,
+ filename_delete_one);
/*@=aliasunique@*/
+
+ mapping->index = line_index;
+ mapping->line = line;
+ mapping->line_inc = line_inc;
+
+ /* Add the mapping to the map */
+ if (!line_index_map) {
+ line_index_map = xmalloc(sizeof(line_index_mapping_head));
+ STAILQ_INIT(line_index_map);
+ }
+ STAILQ_INSERT_TAIL(line_index_map, mapping, link);
}
void
-filename_delete_all(void)
+line_shutdown(void)
{
- in_filename = NULL;
+ line_index_mapping *mapping, *mapping2;
+ mapping = STAILQ_FIRST(line_index_map);
+ while (mapping) {
+ mapping2 = STAILQ_NEXT(mapping, link);
+ xfree(mapping);
+ mapping = mapping2;
+ }
+ xfree(line_index_map);
+
if (filename_table) {
HAMT_delete(filename_table, filename_delete_one);
filename_table = NULL;
}
}
+
+void
+line_lookup(unsigned long index, const char **filename, unsigned long *line)
+{
+ line_index_mapping *mapping, *mapping2;
+
+ assert(index <= line_index);
+
+ /* Linearly search through map to find highest line_index <= index */
+ mapping = STAILQ_FIRST(line_index_map);
+ while (mapping) {
+ mapping2 = STAILQ_NEXT(mapping, link);
+ if (!mapping2 || mapping2->index > index)
+ break;
+ mapping = mapping2;
+ }
+
+ *filename = mapping->filename;
+ *line = mapping->line+mapping->line_inc*(index-mapping->index);
+}
/* Current (selected) object format */
extern /*@null@*/ objfmt *cur_objfmt;
-/*@null@*/ /*@dependent@*/ extern const char *in_filename;
-extern unsigned int line_number;
-
-/* Amount to increase line_number by after each line. Should be 0 or 1, set by
- * %line (in NASM syntax). Initialized to 1 at startup.
- * (0 is for 1-line macros that expand to multiple lines).
- */
-extern unsigned int line_number_inc;
+/* Virtual line number. Uniquely specifies every line read by the parser. */
+extern unsigned long line_index;
+/* Global assembler options. */
extern unsigned int asm_options;
+/* Indentation level for assembler *_print() routines */
extern int indent_level;
-void switch_filename(const char *filename);
-void filename_delete_all(void);
+void line_set(const char *filename, unsigned long line,
+ unsigned long line_inc);
+void line_shutdown(void);
+void line_lookup(unsigned long index, const char **filename,
+ unsigned long *line);
#endif
SymType type;
SymStatus status;
SymVisibility visibility;
- /*@dependent@*/ /*@null@*/ const char *filename; /* file and line */
unsigned long line; /* symbol was first declared or used on */
union {
expr *expn; /* equ value */
rec = xmalloc(sizeof(symrec));
rec->name = symname;
rec->type = SYM_UNKNOWN;
- rec->filename = in_filename;
- rec->line = line_number;
+ rec->line = line_index;
rec->visibility = SYM_LOCAL;
rec->of_data_vis_ce = NULL;
rec->of_data_vis_g = NULL;
Error(_("duplicate definition of `%s'; first defined on line %d"),
name, rec->line);
} else {
- rec->line = line_number; /* set line number of definition */
+ rec->line = line_index; /* set line number of definition */
rec->type = type;
rec->status |= SYM_DEFINED;
}
if (of_data)
cur_objfmt->declare_data_delete(vis, of_data);
} else {
- rec->line = line_number; /* set line number of declaration */
+ rec->line = line_index; /* set line number of declaration */
rec->visibility |= vis;
/* If declared as COMMON or EXTERN, set as DEFINED. */
}
static unsigned long firstundef_line;
-static /*@dependent@*/ /*@null@*/ const char *firstundef_filename;
static int
symrec_parser_finalize_checksym(symrec *sym, /*@unused@*/ /*@null@*/ void *d)
{
/* error if a symbol is used but never defined */
if ((sym->status & SYM_USED) && !(sym->status & SYM_DEFINED)) {
- ErrorAt(sym->filename, sym->line,
- _("undefined symbol `%s' (first use)"), sym->name);
- if (sym->line < firstundef_line) {
+ ErrorAt(sym->line, _("undefined symbol `%s' (first use)"), sym->name);
+ if (sym->line < firstundef_line)
firstundef_line = sym->line;
- firstundef_filename = sym->filename;
- }
}
return 1;
firstundef_line = ULONG_MAX;
symrec_traverse(NULL, symrec_parser_finalize_checksym);
if (firstundef_line < ULONG_MAX)
- ErrorAt(firstundef_filename, firstundef_line,
+ ErrorAt(firstundef_line,
_(" (Each undefined symbol is reported only once.)"));
}
void
symrec_print(FILE *f, const symrec *sym)
{
+ const char *filename;
+ unsigned long line;
+
switch (sym->type) {
case SYM_UNKNOWN:
fprintf(f, "%*s-Unknown (Common/Extern)-\n", indent_level, "");
indent_level--;
}
+ line_lookup(sym->line, &filename, &line);
fprintf(f, "%*sFilename=\"%s\" Line Number=%lu\n", indent_level, "",
- sym->filename?sym->filename:"(NULL)", sym->line);
+ filename, line);
}
*/
if (!intnum_check_size(intn, (size_t)wordsize, 0) &&
!intnum_check_size(intn, 1, 1)) {
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
}
case 2:
case 4:
if (wordsize != *displen) {
- ErrorAt(e->filename, e->line,
+ ErrorAt(e->line,
_("invalid effective address (displacement size)"));
return 0;
}
x86_expr_checkea_get_reg32)) {
case 0:
e = *ep;
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
case 1:
return 1;
*/
for (i=0; i<8; i++) {
if (reg32mult[i] < 0) {
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
}
if (i != indexreg && reg32mult[i] == 1)
*/
for (i=0; i<8; i++)
if (i != basereg && i != indexreg && reg32mult[i] != 0) {
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
}
if (indexreg != REG32_NONE && reg32mult[indexreg] != 1 &&
reg32mult[indexreg] != 2 && reg32mult[indexreg] != 4 &&
reg32mult[indexreg] != 8) {
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
}
* legal.
*/
if (reg32mult[REG32_ESP] > 1 || basereg == REG32_ESP) {
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
}
/* If mult==1 and basereg is not ESP, swap indexreg w/basereg. */
x86_expr_checkea_get_reg16)) {
case 0:
e = *ep;
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
case 1:
return 1;
/* reg multipliers not 0 or 1 are illegal. */
if (reg16mult.bx & ~1 || reg16mult.si & ~1 || reg16mult.di & ~1 ||
reg16mult.bp & ~1) {
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
}
/* Check the modrm value for invalid combinations. */
if (modrm16[havereg] & 0070) {
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
}
$2);
if (nasm_parser_temp_bc)
nasm_parser_prev_bc = nasm_parser_temp_bc;
- line_number += line_number_inc;
+ line_index++;
}
;
line: '\n' { $$ = (bytecode *)NULL; }
| lineexp '\n'
| LINE INTNUM '+' INTNUM FILENAME '\n' {
- line_number = (unsigned int)intnum_get_uint($2);
- line_number_inc = (unsigned int)intnum_get_uint($4);
- line_number -= line_number_inc; /* as we'll add it back in */
- switch_filename($5);
+ /* %line indicates the line number of the *next* line, so subtract out
+ * the increment when setting the line number.
+ */
+ line_set($5, intnum_get_uint($2)-intnum_get_uint($4),
+ intnum_get_uint($4));
intnum_delete($2);
intnum_delete($4);
xfree($5);
$2);
if (nasm_parser_temp_bc)
nasm_parser_prev_bc = nasm_parser_temp_bc;
- line_number += line_number_inc;
+ line_index++;
}
;
line: '\n' { $$ = (bytecode *)NULL; }
| lineexp '\n'
| LINE INTNUM '+' INTNUM FILENAME '\n' {
- line_number = (unsigned int)intnum_get_uint($2);
- line_number_inc = (unsigned int)intnum_get_uint($4);
- line_number -= line_number_inc; /* as we'll add it back in */
- switch_filename($5);
+ /* %line indicates the line number of the *next* line, so subtract out
+ * the increment when setting the line number.
+ */
+ line_set($5, intnum_get_uint($2)-intnum_get_uint($4),
+ intnum_get_uint($4));
intnum_delete($2);
intnum_delete($4);
xfree($5);
*/
if (!intnum_check_size(intn, (size_t)wordsize, 0) &&
!intnum_check_size(intn, 1, 1)) {
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
}
case 2:
case 4:
if (wordsize != *displen) {
- ErrorAt(e->filename, e->line,
+ ErrorAt(e->line,
_("invalid effective address (displacement size)"));
return 0;
}
x86_expr_checkea_get_reg32)) {
case 0:
e = *ep;
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
case 1:
return 1;
*/
for (i=0; i<8; i++) {
if (reg32mult[i] < 0) {
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
}
if (i != indexreg && reg32mult[i] == 1)
*/
for (i=0; i<8; i++)
if (i != basereg && i != indexreg && reg32mult[i] != 0) {
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
}
if (indexreg != REG32_NONE && reg32mult[indexreg] != 1 &&
reg32mult[indexreg] != 2 && reg32mult[indexreg] != 4 &&
reg32mult[indexreg] != 8) {
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
}
* legal.
*/
if (reg32mult[REG32_ESP] > 1 || basereg == REG32_ESP) {
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
}
/* If mult==1 and basereg is not ESP, swap indexreg w/basereg. */
x86_expr_checkea_get_reg16)) {
case 0:
e = *ep;
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
case 1:
return 1;
/* reg multipliers not 0 or 1 are illegal. */
if (reg16mult.bx & ~1 || reg16mult.si & ~1 || reg16mult.di & ~1 ||
reg16mult.bp & ~1) {
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
}
/* Check the modrm value for invalid combinations. */
if (modrm16[havereg] & 0070) {
- ErrorAt(e->filename, e->line, _("invalid effective address"));
+ ErrorAt(e->line, _("invalid effective address"));
return 0;
}
multiple copies), 0 if unknown */
/* where it came from */
- /*@dependent@*/ /*@null@*/ const char *filename;
- unsigned int lineno;
+ unsigned int line;
/* other assembler state info */
unsigned long offset; /* 0 if unknown */
bc->multiple = (expr *)NULL;
bc->len = 0;
- bc->filename = in_filename;
- bc->lineno = line_number;
+ bc->line = line_index;
bc->offset = 0;
const bytecode_data *data;
const bytecode_reserve *reserve;
const bytecode_incbin *incbin;
+ const char *filename;
+ unsigned long line;
switch (bc->type) {
case BC_EMPTY:
else
expr_print(f, bc->multiple);
fprintf(f, "\n%*sLength=%lu\n", indent_level, "", bc->len);
- fprintf(f, "%*sFilename=\"%s\" Line Number=%u\n", indent_level, "",
- bc->filename ? bc->filename : "<UNKNOWN>", bc->lineno);
+ line_lookup(bc->line, &filename, &line);
+ fprintf(f, "%*sFilename=\"%s\" Line Number=%lu\n", indent_level, "",
+ filename, line);
fprintf(f, "%*sOffset=%lx\n", indent_level, "", bc->offset);
}
enum { WE_ERROR, WE_WARNING } type;
- /*@dependent@*/ const char *filename;
unsigned long line;
/* FIXME: This should not be a fixed size. But we don't have vasprintf()
* right now. */
va_list ap;
errwarn *we;
- if ((previous_error_line == line_number) && !previous_error_parser)
+ if ((previous_error_line == line_index) && !previous_error_parser)
return;
if (!errwarns) {
we = xmalloc(sizeof(errwarn));
we->type = WE_ERROR;
- we->filename = in_filename;
- we->line = line_number;
+ we->line = line_index;
}
assert(we != NULL);
STAILQ_INSERT_TAIL(errwarns, we, link);
/*@=branchstate@*/
- previous_error_line = line_number;
+ previous_error_line = line_index;
previous_error_parser = 0;
error_count++;
va_list ap;
errwarn *we;
- if (previous_warning_line == line_number)
+ if (previous_warning_line == line_index)
return;
- previous_warning_line = line_number;
+ previous_warning_line = line_index;
we = xmalloc(sizeof(errwarn));
we->type = WE_WARNING;
- we->filename = in_filename;
- we->line = line_number;
+ we->line = line_index;
va_start(ap, fmt);
vsprintf(we->msg, fmt, ap);
va_end(ap);
}
void
-ErrorAt(const char *filename, unsigned long line, const char *fmt, ...)
+ErrorAt(unsigned long index, const char *fmt, ...)
{
/* XXX: Should insert into list instead of printing immediately */
va_list ap;
+ const char *filename;
+ unsigned long line;
+ line_lookup(index, &filename, &line);
fprintf(stderr, "%s:%lu: ", filename?filename:"(NULL)", line);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
}
void
-WarningAt(const char *filename, unsigned long line, const char *fmt, ...)
+WarningAt(unsigned long index, const char *fmt, ...)
{
/* XXX: Should insert into list instead of printing immediately */
va_list ap;
+ const char *filename;
+ unsigned long line;
+ line_lookup(index, &filename, &line);
fprintf(stderr, "%s:%lu: %s ", filename?filename:"NULL", line,
_("warning:"));
va_start(ap, fmt);
OutputAllErrorWarning(void)
{
errwarn *we, *we2;
+ const char *filename;
+ unsigned long line;
/* If errwarns hasn't been initialized, there are no messages. */
if (!errwarns)
/* Output error and warning messages. */
STAILQ_FOREACH(we, errwarns, link) {
+ line_lookup(we->line, &filename, &line);
if (we->type == WE_ERROR)
- fprintf(stderr, "%s:%lu: %s\n", we->filename, we->line, we->msg);
+ fprintf(stderr, "%s:%lu: %s\n", filename, line, we->msg);
else
- fprintf(stderr, "%s:%lu: %s %s\n", we->filename, we->line,
- _("warning:"), we->msg);
+ fprintf(stderr, "%s:%lu: %s %s\n", filename, line, _("warning:"),
+ we->msg);
}
/* Delete messages. */
* called in line order from a parser. The *At() functions are much slower,
* at least in the current implementation.
*/
-void ErrorAt(/*@null@*/ const char *filename, unsigned long line, const char *,
- ...) /*@printflike@*/;
-void WarningAt(/*@null@*/ const char *filename, unsigned long line,
- const char *, ...) /*@printflike@*/;
+void ErrorAt(unsigned long index, const char *, ...) /*@printflike@*/;
+void WarningAt(unsigned long index, const char *, ...) /*@printflike@*/;
/* These two functions immediately output the error or warning, with no file
* or line information. They should be used for errors and warnings outside
*/
struct expr {
ExprOp op;
- /*@dependent@*/ /*@null@*/ const char *filename;
unsigned long line;
int numterms;
ExprItem terms[2]; /* structure may be extended to include more */
}
}
- ptr->filename = in_filename;
- ptr->line = line_number;
+ ptr->line = line_index;
return ptr;
}
/* Build -1*ei subexpression */
sube->op = EXPR_MUL;
- sube->filename = e->filename;
sube->line = e->line;
sube->numterms = 2;
sube->terms[0].type = EXPR_INT;
*/
ne = xmalloc(sizeof(expr));
ne->op = EXPR_MUL;
- ne->filename = e->filename;
ne->line = e->line;
ne->numterms = 2;
ne->terms[0].type = EXPR_INT;
n = xmalloc(sizeof(expr)+sizeof(ExprItem)*(e->numterms<2?0:e->numterms-2));
n->op = e->op;
- n->filename = e->filename;
n->line = e->line;
n->numterms = e->numterms;
for (i=0; i<e->numterms; i++) {
/* Current (selected) object format) */
/*@null@*/ objfmt *cur_objfmt = NULL;
-/*@null@*/ /*@dependent@*/ const char *in_filename = (const char *)NULL;
-unsigned int line_number = 1;
-unsigned int line_number_inc = 1;
-unsigned int asm_options = 0;
+/* Source lines tracking */
+/* FIXME: Need better data structure for this than a linked list. */
+typedef /*@reldef@*/ STAILQ_HEAD(line_index_mapping_head, line_index_mapping)
+ line_index_mapping_head;
+typedef struct line_index_mapping {
+ /*@reldef@*/ STAILQ_ENTRY(line_index_mapping) link;
-int indent_level = 0;
+ /* monotonically increasing line index */
+ unsigned long index;
+ /* related info */
+ /* "original" source filename */
+ /*@null@*/ /*@dependent@*/ const char *filename;
+ /* "original" source base line number */
+ unsigned long line;
+ /* "original" source line number increment (for following lines) */
+ unsigned int line_inc;
+} line_index_mapping;
+/* Shared storage for filenames */
static /*@only@*/ /*@null@*/ HAMT *filename_table = NULL;
+/* Virtual line number. Uniquely specifies every line read by the parser. */
+unsigned long line_index = 1;
+static line_index_mapping_head *line_index_map = NULL;
+
+/* Global assembler options. */
+unsigned int asm_options = 0;
+
+/* Indentation level for assembler *_print() routines */
+int indent_level = 0;
+
static void
filename_delete_one(/*@only@*/ void *d)
{
}
void
-switch_filename(const char *filename)
+line_set(const char *filename, unsigned long line, unsigned long line_inc)
{
- char *copy = xstrdup(filename);
+ char *copy;
int replace = 0;
+ line_index_mapping *mapping;
+
+ /* Build a mapping */
+ mapping = xmalloc(sizeof(line_index_mapping));
+
+ /* Copy the filename (via shared storage) */
+ copy = xstrdup(filename);
if (!filename_table)
filename_table = HAMT_new();
/*@-aliasunique@*/
- in_filename = HAMT_insert(filename_table, copy, copy, &replace,
- filename_delete_one);
+ mapping->filename = HAMT_insert(filename_table, copy, copy, &replace,
+ filename_delete_one);
/*@=aliasunique@*/
+
+ mapping->index = line_index;
+ mapping->line = line;
+ mapping->line_inc = line_inc;
+
+ /* Add the mapping to the map */
+ if (!line_index_map) {
+ line_index_map = xmalloc(sizeof(line_index_mapping_head));
+ STAILQ_INIT(line_index_map);
+ }
+ STAILQ_INSERT_TAIL(line_index_map, mapping, link);
}
void
-filename_delete_all(void)
+line_shutdown(void)
{
- in_filename = NULL;
+ line_index_mapping *mapping, *mapping2;
+ mapping = STAILQ_FIRST(line_index_map);
+ while (mapping) {
+ mapping2 = STAILQ_NEXT(mapping, link);
+ xfree(mapping);
+ mapping = mapping2;
+ }
+ xfree(line_index_map);
+
if (filename_table) {
HAMT_delete(filename_table, filename_delete_one);
filename_table = NULL;
}
}
+
+void
+line_lookup(unsigned long index, const char **filename, unsigned long *line)
+{
+ line_index_mapping *mapping, *mapping2;
+
+ assert(index <= line_index);
+
+ /* Linearly search through map to find highest line_index <= index */
+ mapping = STAILQ_FIRST(line_index_map);
+ while (mapping) {
+ mapping2 = STAILQ_NEXT(mapping, link);
+ if (!mapping2 || mapping2->index > index)
+ break;
+ mapping = mapping2;
+ }
+
+ *filename = mapping->filename;
+ *line = mapping->line+mapping->line_inc*(index-mapping->index);
+}
/* Current (selected) object format */
extern /*@null@*/ objfmt *cur_objfmt;
-/*@null@*/ /*@dependent@*/ extern const char *in_filename;
-extern unsigned int line_number;
-
-/* Amount to increase line_number by after each line. Should be 0 or 1, set by
- * %line (in NASM syntax). Initialized to 1 at startup.
- * (0 is for 1-line macros that expand to multiple lines).
- */
-extern unsigned int line_number_inc;
+/* Virtual line number. Uniquely specifies every line read by the parser. */
+extern unsigned long line_index;
+/* Global assembler options. */
extern unsigned int asm_options;
+/* Indentation level for assembler *_print() routines */
extern int indent_level;
-void switch_filename(const char *filename);
-void filename_delete_all(void);
+void line_set(const char *filename, unsigned long line,
+ unsigned long line_inc);
+void line_shutdown(void);
+void line_lookup(unsigned long index, const char **filename,
+ unsigned long *line);
#endif
/* Current (selected) object format) */
/*@null@*/ objfmt *cur_objfmt = NULL;
-/*@null@*/ /*@dependent@*/ const char *in_filename = (const char *)NULL;
-unsigned int line_number = 1;
-unsigned int line_number_inc = 1;
-unsigned int asm_options = 0;
+/* Source lines tracking */
+/* FIXME: Need better data structure for this than a linked list. */
+typedef /*@reldef@*/ STAILQ_HEAD(line_index_mapping_head, line_index_mapping)
+ line_index_mapping_head;
+typedef struct line_index_mapping {
+ /*@reldef@*/ STAILQ_ENTRY(line_index_mapping) link;
-int indent_level = 0;
+ /* monotonically increasing line index */
+ unsigned long index;
+ /* related info */
+ /* "original" source filename */
+ /*@null@*/ /*@dependent@*/ const char *filename;
+ /* "original" source base line number */
+ unsigned long line;
+ /* "original" source line number increment (for following lines) */
+ unsigned int line_inc;
+} line_index_mapping;
+/* Shared storage for filenames */
static /*@only@*/ /*@null@*/ HAMT *filename_table = NULL;
+/* Virtual line number. Uniquely specifies every line read by the parser. */
+unsigned long line_index = 1;
+static line_index_mapping_head *line_index_map = NULL;
+
+/* Global assembler options. */
+unsigned int asm_options = 0;
+
+/* Indentation level for assembler *_print() routines */
+int indent_level = 0;
+
static void
filename_delete_one(/*@only@*/ void *d)
{
}
void
-switch_filename(const char *filename)
+line_set(const char *filename, unsigned long line, unsigned long line_inc)
{
- char *copy = xstrdup(filename);
+ char *copy;
int replace = 0;
+ line_index_mapping *mapping;
+
+ /* Build a mapping */
+ mapping = xmalloc(sizeof(line_index_mapping));
+
+ /* Copy the filename (via shared storage) */
+ copy = xstrdup(filename);
if (!filename_table)
filename_table = HAMT_new();
/*@-aliasunique@*/
- in_filename = HAMT_insert(filename_table, copy, copy, &replace,
- filename_delete_one);
+ mapping->filename = HAMT_insert(filename_table, copy, copy, &replace,
+ filename_delete_one);
/*@=aliasunique@*/
+
+ mapping->index = line_index;
+ mapping->line = line;
+ mapping->line_inc = line_inc;
+
+ /* Add the mapping to the map */
+ if (!line_index_map) {
+ line_index_map = xmalloc(sizeof(line_index_mapping_head));
+ STAILQ_INIT(line_index_map);
+ }
+ STAILQ_INSERT_TAIL(line_index_map, mapping, link);
}
void
-filename_delete_all(void)
+line_shutdown(void)
{
- in_filename = NULL;
+ line_index_mapping *mapping, *mapping2;
+ mapping = STAILQ_FIRST(line_index_map);
+ while (mapping) {
+ mapping2 = STAILQ_NEXT(mapping, link);
+ xfree(mapping);
+ mapping = mapping2;
+ }
+ xfree(line_index_map);
+
if (filename_table) {
HAMT_delete(filename_table, filename_delete_one);
filename_table = NULL;
}
}
+
+void
+line_lookup(unsigned long index, const char **filename, unsigned long *line)
+{
+ line_index_mapping *mapping, *mapping2;
+
+ assert(index <= line_index);
+
+ /* Linearly search through map to find highest line_index <= index */
+ mapping = STAILQ_FIRST(line_index_map);
+ while (mapping) {
+ mapping2 = STAILQ_NEXT(mapping, link);
+ if (!mapping2 || mapping2->index > index)
+ break;
+ mapping = mapping2;
+ }
+
+ *filename = mapping->filename;
+ *line = mapping->line+mapping->line_inc*(index-mapping->index);
+}
/* Current (selected) object format */
extern /*@null@*/ objfmt *cur_objfmt;
-/*@null@*/ /*@dependent@*/ extern const char *in_filename;
-extern unsigned int line_number;
-
-/* Amount to increase line_number by after each line. Should be 0 or 1, set by
- * %line (in NASM syntax). Initialized to 1 at startup.
- * (0 is for 1-line macros that expand to multiple lines).
- */
-extern unsigned int line_number_inc;
+/* Virtual line number. Uniquely specifies every line read by the parser. */
+extern unsigned long line_index;
+/* Global assembler options. */
extern unsigned int asm_options;
+/* Indentation level for assembler *_print() routines */
extern int indent_level;
-void switch_filename(const char *filename);
-void filename_delete_all(void);
+void line_set(const char *filename, unsigned long line,
+ unsigned long line_inc);
+void line_shutdown(void);
+void line_lookup(unsigned long index, const char **filename,
+ unsigned long *line);
#endif
#endif
static int files_open = 0;
-/*@null@*/ /*@only@*/ static char *obj_filename = NULL;
+/*@null@*/ /*@only@*/ static char *obj_filename = NULL, *in_filename = NULL;
/*@null@*/ static FILE *in = NULL, *obj = NULL;
/* Forward declarations: cmd line parser handlers */
/* if no files were specified, fallback to reading stdin */
if (!in) {
in = stdin;
- switch_filename("<STDIN>");
+ in_filename = xstrdup("<STDIN>");
if (!obj)
obj = stdout;
}
+ /* Initialize line info */
+ line_set(in_filename, 1, 1);
+
/* Set x86 as the architecture */
cur_arch = &x86_arch;
if (OutputAllErrorWarning() > 0) {
sections_delete(sections);
symrec_delete_all();
- filename_delete_all();
+ line_shutdown();
+ floatnum_shutdown();
BitVector_Shutdown();
return EXIT_FAILURE;
}
sections_delete(sections);
symrec_delete_all();
- filename_delete_all();
+ line_shutdown();
floatnum_shutdown();
WarningNow("can open only one input file, only latest file will be processed");
if(fclose(in))
ErrorNow("could not close old input file");
+ if (in_filename)
+ xfree(in_filename);
}
in = fopen(param, "rt");
ErrorNow(_("could not open file `%s'"), param);
return 1;
}
- switch_filename(param);
+ in_filename = xstrdup(param);
files_open++;
return 0;
$2);
if (nasm_parser_temp_bc)
nasm_parser_prev_bc = nasm_parser_temp_bc;
- line_number += line_number_inc;
+ line_index++;
}
;
line: '\n' { $$ = (bytecode *)NULL; }
| lineexp '\n'
| LINE INTNUM '+' INTNUM FILENAME '\n' {
- line_number = (unsigned int)intnum_get_uint($2);
- line_number_inc = (unsigned int)intnum_get_uint($4);
- line_number -= line_number_inc; /* as we'll add it back in */
- switch_filename($5);
+ /* %line indicates the line number of the *next* line, so subtract out
+ * the increment when setting the line number.
+ */
+ line_set($5, intnum_get_uint($2)-intnum_get_uint($4),
+ intnum_get_uint($4));
intnum_delete($2);
intnum_delete($4);
xfree($5);
$2);
if (nasm_parser_temp_bc)
nasm_parser_prev_bc = nasm_parser_temp_bc;
- line_number += line_number_inc;
+ line_index++;
}
;
line: '\n' { $$ = (bytecode *)NULL; }
| lineexp '\n'
| LINE INTNUM '+' INTNUM FILENAME '\n' {
- line_number = (unsigned int)intnum_get_uint($2);
- line_number_inc = (unsigned int)intnum_get_uint($4);
- line_number -= line_number_inc; /* as we'll add it back in */
- switch_filename($5);
+ /* %line indicates the line number of the *next* line, so subtract out
+ * the increment when setting the line number.
+ */
+ line_set($5, intnum_get_uint($2)-intnum_get_uint($4),
+ intnum_get_uint($4));
intnum_delete($2);
intnum_delete($4);
xfree($5);
SymType type;
SymStatus status;
SymVisibility visibility;
- /*@dependent@*/ /*@null@*/ const char *filename; /* file and line */
unsigned long line; /* symbol was first declared or used on */
union {
expr *expn; /* equ value */
rec = xmalloc(sizeof(symrec));
rec->name = symname;
rec->type = SYM_UNKNOWN;
- rec->filename = in_filename;
- rec->line = line_number;
+ rec->line = line_index;
rec->visibility = SYM_LOCAL;
rec->of_data_vis_ce = NULL;
rec->of_data_vis_g = NULL;
Error(_("duplicate definition of `%s'; first defined on line %d"),
name, rec->line);
} else {
- rec->line = line_number; /* set line number of definition */
+ rec->line = line_index; /* set line number of definition */
rec->type = type;
rec->status |= SYM_DEFINED;
}
if (of_data)
cur_objfmt->declare_data_delete(vis, of_data);
} else {
- rec->line = line_number; /* set line number of declaration */
+ rec->line = line_index; /* set line number of declaration */
rec->visibility |= vis;
/* If declared as COMMON or EXTERN, set as DEFINED. */
}
static unsigned long firstundef_line;
-static /*@dependent@*/ /*@null@*/ const char *firstundef_filename;
static int
symrec_parser_finalize_checksym(symrec *sym, /*@unused@*/ /*@null@*/ void *d)
{
/* error if a symbol is used but never defined */
if ((sym->status & SYM_USED) && !(sym->status & SYM_DEFINED)) {
- ErrorAt(sym->filename, sym->line,
- _("undefined symbol `%s' (first use)"), sym->name);
- if (sym->line < firstundef_line) {
+ ErrorAt(sym->line, _("undefined symbol `%s' (first use)"), sym->name);
+ if (sym->line < firstundef_line)
firstundef_line = sym->line;
- firstundef_filename = sym->filename;
- }
}
return 1;
firstundef_line = ULONG_MAX;
symrec_traverse(NULL, symrec_parser_finalize_checksym);
if (firstundef_line < ULONG_MAX)
- ErrorAt(firstundef_filename, firstundef_line,
+ ErrorAt(firstundef_line,
_(" (Each undefined symbol is reported only once.)"));
}
void
symrec_print(FILE *f, const symrec *sym)
{
+ const char *filename;
+ unsigned long line;
+
switch (sym->type) {
case SYM_UNKNOWN:
fprintf(f, "%*s-Unknown (Common/Extern)-\n", indent_level, "");
indent_level--;
}
+ line_lookup(sym->line, &filename, &line);
fprintf(f, "%*sFilename=\"%s\" Line Number=%lu\n", indent_level, "",
- sym->filename?sym->filename:"(NULL)", sym->line);
+ filename, line);
}