-/* $Id: bytecode.c,v 1.13 2001/07/11 23:16:50 peter Exp $
+/* $Id: bytecode.c,v 1.14 2001/07/25 00:33:10 peter Exp $
* Bytecode utility functions
*
* Copyright (C) 2001 Peter Johnson
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
+#include <stdlib.h>
#include "globals.h"
#include "bytecode.h"
#include "errwarn.h"
BuildBC_Common(bc);
}
-/* TODO: implement. Shouldn't be difficult. */
-unsigned char *
-ConvertBCInsnToBytes (unsigned char *ptr, bytecode *bc, int *len)
+void
+BuildBC_Data (bytecode *bc,
+ dataval *data,
+ unsigned long size)
{
- if(bc->type != BC_INSN)
- return (unsigned char *)NULL;
- return (unsigned char *)NULL;
+ dataval *cur = data;
+
+ /* First check to see if all the data elements are valid for the size
+ * being set.
+ * Validity table:
+ * db (1) -> expr, string
+ * dw (2) -> expr, string
+ * dd (4) -> expr, float, string
+ * dq (8) -> expr, float, string
+ * dt (10) -> float, string
+ *
+ * Once we calculate expr we'll have to validate it against the size
+ * and warn/error appropriately (symbol constants versus labels:
+ * constants (equ's) should always be legal, but labels should raise
+ * warnings when used in db or dq context at the minimum).
+ */
+ while(cur) {
+ switch(cur->type) {
+ case DV_EMPTY:
+ case DV_STRING:
+ /* string is valid in every size */
+ break;
+ case DV_FLOAT:
+ if(size == 1)
+ Error(ERR_DECLDATA_FLOAT, (char *)NULL, "DB");
+ else if(size == 2)
+ Error(ERR_DECLDATA_FLOAT, (char *)NULL, "DW");
+ break;
+ case DV_EXPR:
+ if(size == 10)
+ Error(ERR_DECLDATA_EXPR, (char *)NULL, "DT");
+ break;
+ }
+ cur = cur->next;
+ }
+
+ bc->next = (bytecode *)NULL;
+ bc->type = BC_DATA;
+
+ bc->data.data.data = data;
+ bc->data.data.size = size;
+
+ BuildBC_Common(bc);
}
void
-DebugPrintBC (bytecode *bc)
+BuildBC_Reserve (bytecode *bc,
+ expr *numitems,
+ unsigned long itemsize)
{
- unsigned long i;
+ bc->next = (bytecode *)NULL;
+ bc->type = BC_RESERVE;
+ bc->data.reserve.numitems = numitems;
+ bc->data.reserve.itemsize = itemsize;
+
+ BuildBC_Common(bc);
+}
+
+void
+DebugPrintBC (bytecode *bc)
+{
switch(bc->type) {
+ case BC_EMPTY:
+ printf("_Empty_\n");
+ break;
case BC_INSN:
printf("_Instruction_\n");
printf("Effective Address:\n");
break;
case BC_DATA:
printf("_Data_\n");
- for(i=0; i<bc->len; i++) {
- printf("%2x ", (unsigned int)bc->data.data.data[i]);
- if((i & ~0xFFFF) == i)
- printf("\n");
- }
+ printf("Final Element Size=%u\n",
+ (unsigned int)bc->data.data.size);
+ printf("Elements:\n");
+ dataval_print(bc->data.data.data);
break;
case BC_RESERVE:
printf("_Reserve_\n");
+ printf("Num Items=");
+ expr_print(bc->data.reserve.numitems);
+ printf("\nItem Size=%u\n",
+ (unsigned int)bc->data.reserve.itemsize);
break;
default:
printf("_Unknown_\n");
bc->filename ? bc->filename : "<UNKNOWN>", bc->lineno);
printf("Offset=%lx BITS=%u\n", bc->offset, bc->mode_bits);
}
+
+dataval *
+dataval_new_expr (expr *exp)
+{
+ dataval *retval = malloc(sizeof(dataval));
+
+ if(!retval)
+ Fatal(FATAL_NOMEM);
+
+ retval->next = (dataval *)NULL;
+ retval->last = retval;
+ retval->type = DV_EXPR;
+ retval->data.exp = exp;
+
+ return retval;
+}
+
+dataval *
+dataval_new_float (double float_val)
+{
+ dataval *retval = malloc(sizeof(dataval));
+
+ if(!retval)
+ Fatal(FATAL_NOMEM);
+
+ retval->next = (dataval *)NULL;
+ retval->last = retval;
+ retval->type = DV_FLOAT;
+ retval->data.float_val = float_val;
+
+ return retval;
+}
+
+dataval *
+dataval_new_string (char *str_val)
+{
+ dataval *retval = malloc(sizeof(dataval));
+
+ if(!retval)
+ Fatal(FATAL_NOMEM);
+
+ retval->next = (dataval *)NULL;
+ retval->last = retval;
+ retval->type = DV_STRING;
+ retval->data.str_val = str_val;
+
+ return retval;
+}
+
+dataval *
+dataval_append (dataval *list, dataval *item)
+{
+ if(item)
+ item->next = (dataval *)NULL;
+
+ if(!list) {
+ item->last = item;
+ return item;
+ } else {
+ if(item) {
+ list->last->next = item;
+ list->last = item;
+ item->last = (dataval *)NULL;
+ }
+ return list;
+ }
+}
+
+void
+dataval_print (dataval *start)
+{
+ dataval *cur = start;
+
+ while(cur) {
+ switch(cur->type) {
+ case DV_EMPTY:
+ printf(" Empty\n");
+ break;
+ case DV_EXPR:
+ printf(" Expr=");
+ expr_print(cur->data.exp);
+ printf("\n");
+ break;
+ case DV_FLOAT:
+ printf(" Float=%e\n", cur->data.float_val);
+ break;
+ case DV_STRING:
+ printf(" String=%s\n", cur->data.str_val);
+ break;
+ }
+
+ cur = cur->next;
+ }
+}
+
-/* $Id: bytecode.h,v 1.14 2001/07/11 23:16:50 peter Exp $
+/* $Id: bytecode.h,v 1.15 2001/07/25 00:33:10 peter Exp $
* Bytecode utility functions header file
*
* Copyright (C) 2001 Peter Johnson
unsigned char f_sign; /* 1 if final imm should be signed */
} immval;
+typedef struct dataval_s {
+ struct dataval_s *next, *last;
+
+ enum { DV_EMPTY, DV_EXPR, DV_FLOAT, DV_STRING } type;
+
+ union {
+ struct expr_s *exp;
+ double float_val;
+ char *str_val;
+ } data;
+} dataval;
+
typedef enum jmprel_opcode_sel_e {
JR_NONE,
JR_SHORT,
typedef struct bytecode_s {
struct bytecode_s *next;
- enum { BC_INSN, BC_JMPREL, BC_DATA, BC_RESERVE } type;
+ enum { BC_EMPTY, BC_INSN, BC_JMPREL, BC_DATA, BC_RESERVE } type;
union {
struct {
unsigned char lockrep_pre; /* 0 indicates no prefix */
} jmprel;
struct {
- unsigned char *data;
+ dataval *data; /* non-converted data (linked list) */
+
+ /* final (converted) size of each element (in bytes) */
+ unsigned char size;
} data;
+ struct {
+ struct expr_s *numitems; /* number of items to reserve */
+ unsigned char itemsize; /* size of each item (in bytes) */
+ } reserve;
} data;
unsigned long len; /* total length of entire bytecode */
unsigned char near_op2,
unsigned char addrsize);
-unsigned char *ConvertBCInsnToBytes(unsigned char *ptr, bytecode *bc, int *len);
+void BuildBC_Data(bytecode *bc,
+ dataval *data,
+ unsigned long size);
+
+void BuildBC_Reserve(bytecode *bc,
+ struct expr_s *numitems,
+ unsigned long itemsize);
void DebugPrintBC(bytecode *bc);
+dataval *dataval_new_expr(struct expr_s *exp);
+dataval *dataval_new_float(double float_val);
+dataval *dataval_new_string(char *str_val);
+
+dataval *dataval_append(dataval *list, dataval *item);
+
+void dataval_print(dataval *start);
+
#endif
-/* $Id: errwarn.c,v 1.16 2001/07/11 23:16:50 peter Exp $
+/* $Id: errwarn.c,v 1.17 2001/07/25 00:33:10 peter Exp $
* Error and warning reporting and related functions.
*
* Copyright (C) 2001 Peter Johnson
"expression syntax error",
"duplicate definition of `%1'; previously defined line %2",
"mismatch in operand sizes",
- "no %s form of that jump instruction exists"
+ "no %s form of that jump instruction exists",
+ "unterminated string",
+ "unexpected end of file in string",
+ "expression syntax error",
+ "floating-point constant encountered in `%s'",
+ "non-floating-point value encountered in `%s'"
};
/* Warning messages. Match up with warn_num enum in errwarn.h. */
"multiple segment overrides, using leftmost",
"multiple LOCK or REP prefixes, using leftmost",
"no non-local label before '%s'",
- "multiple SHORT or NEAR specifiers, using leftmost"
+ "multiple SHORT or NEAR specifiers, using leftmost",
+ "character constant too large, ignoring trailing characters"
};
/* I hate to define these strings as static buffers; a better solution would be
-/* $Id: errwarn.h,v 1.10 2001/07/11 23:16:50 peter Exp $
+/* $Id: errwarn.h,v 1.11 2001/07/25 00:33:10 peter Exp $
* Error and warning reporting and related functions header file.
*
* Copyright (C) 2001 Peter Johnson
ERR_EXP_SYNTAX,
ERR_DUPLICATE_DEF,
ERR_OP_SIZE_MISMATCH,
- ERR_NO_JMPREL_FORM
+ ERR_NO_JMPREL_FORM,
+ ERR_STRING_UNTERM,
+ ERR_STRING_EOF,
+ ERR_EXPR_SYNTAX,
+ ERR_DECLDATA_FLOAT,
+ ERR_DECLDATA_EXPR
} err_num;
/* Warning constants. Match up with warn_msgs in errwarn.c. */
WARN_MULT_SEG_OVERRIDE,
WARN_MULT_LOCKREP_PREFIX,
WARN_NO_BASE_LABEL,
- WARN_MULT_SHORTNEAR
+ WARN_MULT_SHORTNEAR,
+ WARN_CHAR_CONST_TOO_BIG
} warn_num;
char *conv_unprint(char ch);
-/* $Id: bison.y.in,v 1.21 2001/07/11 21:04:58 peter Exp $
+/* $Id: bison.y.in,v 1.22 2001/07/25 00:33:10 peter Exp $
* Main bison parser
*
* Copyright (C) 2001 Peter Johnson, Michael Urman
void init_table(void);
extern int yylex(void);
extern void yyerror(char *);
+static unsigned long ConvertCharConstToInt(char *);
%}
expr *exp;
immval im_val;
targetval tgt_val;
+ dataval *data;
bytecode bc;
-}
+}
%token <int_val> INTNUM
%token <double_val> FLTNUM
-%token <str_val> DIRECTIVE_NAME DIRECTIVE_VAL
+%token <str_val> DIRECTIVE_NAME DIRECTIVE_VAL STRING
%token <int_val> BYTE WORD DWORD QWORD TWORD DQWORD
%token <int_val> DECLARE_DATA
%token <int_val> RESERVE_SPACE
%type <ea_val> rm8x rm16x rm32x /*rm64x rm128x*/
%type <ea_val> rm8 rm16 rm32 rm64 rm128
%type <im_val> imm imm8x imm16x imm32x imm8 imm16 imm32
-%type <exp> expr
+%type <exp> expr expr_no_string
%type <syminfo> explabel
%type <sym> label_id
%type <tgt_val> target
+%type <data> dataval datavals
%left '|'
%left '^'
| input line { OutputError(); OutputWarning(); line_number++; }
;
-line: '\n' { $$.len = 0; }
+line: '\n' { $$.type = BC_EMPTY; }
| exp '\n' { DebugPrintBC(&$1); $$ = $1; }
| label exp '\n' { DebugPrintBC(&$2); $$ = $2; }
| label '\n'
- | directive '\n' { }
- | error '\n' { Error(ERR_INVALID_LINE, (char *)NULL); yyerrok; }
+ | directive '\n' { $$.type = BC_EMPTY; }
+ | error '\n' {
+ Error(ERR_INVALID_LINE, (char *)NULL);
+ $$.type = BC_EMPTY;
+ yyerrok;
+ }
;
exp: instr
+ | DECLARE_DATA datavals { BuildBC_Data(&$$, $2, $1); }
+ | RESERVE_SPACE expr { BuildBC_Reserve(&$$, $2, $1); }
+;
+
+datavals: dataval
+ | datavals ',' dataval { $$ = dataval_append($1, $3); }
+;
+
+dataval: expr_no_string { $$ = dataval_new_expr($1); }
+ | FLTNUM { $$ = dataval_new_float($1); }
+ | STRING { $$ = dataval_new_string($1); }
+ | error {
+ Error(ERR_EXPR_SYNTAX, (char *)NULL);
+ $$ = (dataval *)NULL;
+ }
;
label: label_id { $1->value = 0; } /* TODO: calculate offset */
;
/* expression trees */
-expr:
- INTNUM { $$ = expr_new_ident (EXPR_NUM, ExprNum($1)); }
+expr_no_string: INTNUM { $$ = expr_new_ident (EXPR_NUM, ExprNum($1)); }
| explabel { $$ = expr_new_ident (EXPR_SYM, ExprSym(sym_use_get ($1.name, SYM_LABEL))); }
/*| expr '||' expr { $$ = expr_new_tree ($1, EXPR_LOR, $3); }*/
| expr '|' expr { $$ = expr_new_tree ($1, EXPR_OR, $3); }
| '(' expr ')' { $$ = $2; }
;
+expr: expr_no_string
+ | STRING { $$ = expr_new_ident (EXPR_NUM, ExprNum(ConvertCharConstToInt($1))); }
+;
+
explabel: ID | SPECIAL_ID | LOCAL_ID ;
instr: instrbase
/* instruction grammars (dynamically generated) */
/* @INSTRUCTIONS@ */
+%%
+
+static unsigned long
+ConvertCharConstToInt(char *cc)
+{
+ unsigned long retval = 0;
+ size_t len = strlen(cc);
+
+ if(len > 4)
+ Warning(WARN_CHAR_CONST_TOO_BIG, (char *)NULL);
+
+ switch(len) {
+ case 4:
+ retval |= (unsigned long)cc[3];
+ retval <<= 8;
+ case 3:
+ retval |= (unsigned long)cc[2];
+ retval <<= 8;
+ case 2:
+ retval |= (unsigned long)cc[1];
+ retval <<= 8;
+ case 1:
+ retval |= (unsigned long)cc[0];
+ }
+
+ return retval;
+}
+
-/* $Id: nasm-bison.y,v 1.21 2001/07/11 21:04:58 peter Exp $
+/* $Id: nasm-bison.y,v 1.22 2001/07/25 00:33:10 peter Exp $
* Main bison parser
*
* Copyright (C) 2001 Peter Johnson, Michael Urman
void init_table(void);
extern int yylex(void);
extern void yyerror(char *);
+static unsigned long ConvertCharConstToInt(char *);
%}
expr *exp;
immval im_val;
targetval tgt_val;
+ dataval *data;
bytecode bc;
-}
+}
%token <int_val> INTNUM
%token <double_val> FLTNUM
-%token <str_val> DIRECTIVE_NAME DIRECTIVE_VAL
+%token <str_val> DIRECTIVE_NAME DIRECTIVE_VAL STRING
%token <int_val> BYTE WORD DWORD QWORD TWORD DQWORD
%token <int_val> DECLARE_DATA
%token <int_val> RESERVE_SPACE
%type <ea_val> rm8x rm16x rm32x /*rm64x rm128x*/
%type <ea_val> rm8 rm16 rm32 rm64 rm128
%type <im_val> imm imm8x imm16x imm32x imm8 imm16 imm32
-%type <exp> expr
+%type <exp> expr expr_no_string
%type <syminfo> explabel
%type <sym> label_id
%type <tgt_val> target
+%type <data> dataval datavals
%left '|'
%left '^'
| input line { OutputError(); OutputWarning(); line_number++; }
;
-line: '\n' { $$.len = 0; }
+line: '\n' { $$.type = BC_EMPTY; }
| exp '\n' { DebugPrintBC(&$1); $$ = $1; }
| label exp '\n' { DebugPrintBC(&$2); $$ = $2; }
| label '\n'
- | directive '\n' { }
- | error '\n' { Error(ERR_INVALID_LINE, (char *)NULL); yyerrok; }
+ | directive '\n' { $$.type = BC_EMPTY; }
+ | error '\n' {
+ Error(ERR_INVALID_LINE, (char *)NULL);
+ $$.type = BC_EMPTY;
+ yyerrok;
+ }
;
exp: instr
+ | DECLARE_DATA datavals { BuildBC_Data(&$$, $2, $1); }
+ | RESERVE_SPACE expr { BuildBC_Reserve(&$$, $2, $1); }
+;
+
+datavals: dataval
+ | datavals ',' dataval { $$ = dataval_append($1, $3); }
+;
+
+dataval: expr_no_string { $$ = dataval_new_expr($1); }
+ | FLTNUM { $$ = dataval_new_float($1); }
+ | STRING { $$ = dataval_new_string($1); }
+ | error {
+ Error(ERR_EXPR_SYNTAX, (char *)NULL);
+ $$ = (dataval *)NULL;
+ }
;
label: label_id { $1->value = 0; } /* TODO: calculate offset */
;
/* expression trees */
-expr:
- INTNUM { $$ = expr_new_ident (EXPR_NUM, ExprNum($1)); }
+expr_no_string: INTNUM { $$ = expr_new_ident (EXPR_NUM, ExprNum($1)); }
| explabel { $$ = expr_new_ident (EXPR_SYM, ExprSym(sym_use_get ($1.name, SYM_LABEL))); }
/*| expr '||' expr { $$ = expr_new_tree ($1, EXPR_LOR, $3); }*/
| expr '|' expr { $$ = expr_new_tree ($1, EXPR_OR, $3); }
| '(' expr ')' { $$ = $2; }
;
+expr: expr_no_string
+ | STRING { $$ = expr_new_ident (EXPR_NUM, ExprNum(ConvertCharConstToInt($1))); }
+;
+
explabel: ID | SPECIAL_ID | LOCAL_ID ;
instr: instrbase
/* instruction grammars (dynamically generated) */
/* @INSTRUCTIONS@ */
+%%
+
+static unsigned long
+ConvertCharConstToInt(char *cc)
+{
+ unsigned long retval = 0;
+ size_t len = strlen(cc);
+
+ if(len > 4)
+ Warning(WARN_CHAR_CONST_TOO_BIG, (char *)NULL);
+
+ switch(len) {
+ case 4:
+ retval |= (unsigned long)cc[3];
+ retval <<= 8;
+ case 3:
+ retval |= (unsigned long)cc[2];
+ retval <<= 8;
+ case 2:
+ retval |= (unsigned long)cc[1];
+ retval <<= 8;
+ case 1:
+ retval |= (unsigned long)cc[0];
+ }
+
+ return retval;
+}
+
-/* $Id: token.l.in,v 1.11 2001/07/11 21:01:54 peter Exp $
+/* $Id: token.l.in,v 1.12 2001/07/25 00:33:10 peter Exp $
* Main lexer
*
* Copyright (C) 2001 Peter Johnson
#include "expr.h"
#include "bison.h"
+/* starting size of string buffer */
+#define STRBUF_ALLOC_SIZE 128
+
+/* string buffer used when parsing strings/character constants */
+static char *strbuf = (char *)NULL;
+
+/* length of strbuf (including terminating NULL character) */
+static size_t strbuf_size = 0;
+
%}
%option noyywrap
%option nounput
yylval.double_val = strtod(yytext, (char **)NULL);
return FLTNUM;
}
+
+ /* string/character constant values */
+["'] {
+ int inch, count;
+ char endch = yytext[0];
+
+ strbuf = malloc(STRBUF_ALLOC_SIZE);
+ if(!strbuf)
+ Fatal(FATAL_NOMEM);
+
+ strbuf_size = STRBUF_ALLOC_SIZE;
+ inch = input();
+ count = 0;
+ while(inch != EOF && inch != endch && inch != '\n') {
+ strbuf[count++] = inch;
+ if(count >= strbuf_size) {
+ strbuf = realloc(strbuf, strbuf_size + STRBUF_ALLOC_SIZE);
+ if(!strbuf)
+ Fatal(FATAL_NOMEM);
+ strbuf_size += STRBUF_ALLOC_SIZE;
+ }
+ inch = input();
+ }
+
+ if(inch == '\n')
+ Error(ERR_STRING_UNTERM, (char *)NULL);
+ else if(inch == EOF)
+ Error(ERR_STRING_EOF, (char *)NULL);
+
+ strbuf[count] = '\0';
+
+ yylval.str_val = strbuf;
+ return STRING;
+}
+
/* directive: [name value] */
^"[" { BEGIN DIRECTIVE; return '['; }
<DIRECTIVE>"]" { BEGIN INITIAL; return ']'; }
-/* $Id: bison.y.in,v 1.21 2001/07/11 21:04:58 peter Exp $
+/* $Id: bison.y.in,v 1.22 2001/07/25 00:33:10 peter Exp $
* Main bison parser
*
* Copyright (C) 2001 Peter Johnson, Michael Urman
void init_table(void);
extern int yylex(void);
extern void yyerror(char *);
+static unsigned long ConvertCharConstToInt(char *);
%}
expr *exp;
immval im_val;
targetval tgt_val;
+ dataval *data;
bytecode bc;
-}
+}
%token <int_val> INTNUM
%token <double_val> FLTNUM
-%token <str_val> DIRECTIVE_NAME DIRECTIVE_VAL
+%token <str_val> DIRECTIVE_NAME DIRECTIVE_VAL STRING
%token <int_val> BYTE WORD DWORD QWORD TWORD DQWORD
%token <int_val> DECLARE_DATA
%token <int_val> RESERVE_SPACE
%type <ea_val> rm8x rm16x rm32x /*rm64x rm128x*/
%type <ea_val> rm8 rm16 rm32 rm64 rm128
%type <im_val> imm imm8x imm16x imm32x imm8 imm16 imm32
-%type <exp> expr
+%type <exp> expr expr_no_string
%type <syminfo> explabel
%type <sym> label_id
%type <tgt_val> target
+%type <data> dataval datavals
%left '|'
%left '^'
| input line { OutputError(); OutputWarning(); line_number++; }
;
-line: '\n' { $$.len = 0; }
+line: '\n' { $$.type = BC_EMPTY; }
| exp '\n' { DebugPrintBC(&$1); $$ = $1; }
| label exp '\n' { DebugPrintBC(&$2); $$ = $2; }
| label '\n'
- | directive '\n' { }
- | error '\n' { Error(ERR_INVALID_LINE, (char *)NULL); yyerrok; }
+ | directive '\n' { $$.type = BC_EMPTY; }
+ | error '\n' {
+ Error(ERR_INVALID_LINE, (char *)NULL);
+ $$.type = BC_EMPTY;
+ yyerrok;
+ }
;
exp: instr
+ | DECLARE_DATA datavals { BuildBC_Data(&$$, $2, $1); }
+ | RESERVE_SPACE expr { BuildBC_Reserve(&$$, $2, $1); }
+;
+
+datavals: dataval
+ | datavals ',' dataval { $$ = dataval_append($1, $3); }
+;
+
+dataval: expr_no_string { $$ = dataval_new_expr($1); }
+ | FLTNUM { $$ = dataval_new_float($1); }
+ | STRING { $$ = dataval_new_string($1); }
+ | error {
+ Error(ERR_EXPR_SYNTAX, (char *)NULL);
+ $$ = (dataval *)NULL;
+ }
;
label: label_id { $1->value = 0; } /* TODO: calculate offset */
;
/* expression trees */
-expr:
- INTNUM { $$ = expr_new_ident (EXPR_NUM, ExprNum($1)); }
+expr_no_string: INTNUM { $$ = expr_new_ident (EXPR_NUM, ExprNum($1)); }
| explabel { $$ = expr_new_ident (EXPR_SYM, ExprSym(sym_use_get ($1.name, SYM_LABEL))); }
/*| expr '||' expr { $$ = expr_new_tree ($1, EXPR_LOR, $3); }*/
| expr '|' expr { $$ = expr_new_tree ($1, EXPR_OR, $3); }
| '(' expr ')' { $$ = $2; }
;
+expr: expr_no_string
+ | STRING { $$ = expr_new_ident (EXPR_NUM, ExprNum(ConvertCharConstToInt($1))); }
+;
+
explabel: ID | SPECIAL_ID | LOCAL_ID ;
instr: instrbase
/* instruction grammars (dynamically generated) */
/* @INSTRUCTIONS@ */
+%%
+
+static unsigned long
+ConvertCharConstToInt(char *cc)
+{
+ unsigned long retval = 0;
+ size_t len = strlen(cc);
+
+ if(len > 4)
+ Warning(WARN_CHAR_CONST_TOO_BIG, (char *)NULL);
+
+ switch(len) {
+ case 4:
+ retval |= (unsigned long)cc[3];
+ retval <<= 8;
+ case 3:
+ retval |= (unsigned long)cc[2];
+ retval <<= 8;
+ case 2:
+ retval |= (unsigned long)cc[1];
+ retval <<= 8;
+ case 1:
+ retval |= (unsigned long)cc[0];
+ }
+
+ return retval;
+}
+
-/* $Id: bytecode.c,v 1.13 2001/07/11 23:16:50 peter Exp $
+/* $Id: bytecode.c,v 1.14 2001/07/25 00:33:10 peter Exp $
* Bytecode utility functions
*
* Copyright (C) 2001 Peter Johnson
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
+#include <stdlib.h>
#include "globals.h"
#include "bytecode.h"
#include "errwarn.h"
BuildBC_Common(bc);
}
-/* TODO: implement. Shouldn't be difficult. */
-unsigned char *
-ConvertBCInsnToBytes (unsigned char *ptr, bytecode *bc, int *len)
+void
+BuildBC_Data (bytecode *bc,
+ dataval *data,
+ unsigned long size)
{
- if(bc->type != BC_INSN)
- return (unsigned char *)NULL;
- return (unsigned char *)NULL;
+ dataval *cur = data;
+
+ /* First check to see if all the data elements are valid for the size
+ * being set.
+ * Validity table:
+ * db (1) -> expr, string
+ * dw (2) -> expr, string
+ * dd (4) -> expr, float, string
+ * dq (8) -> expr, float, string
+ * dt (10) -> float, string
+ *
+ * Once we calculate expr we'll have to validate it against the size
+ * and warn/error appropriately (symbol constants versus labels:
+ * constants (equ's) should always be legal, but labels should raise
+ * warnings when used in db or dq context at the minimum).
+ */
+ while(cur) {
+ switch(cur->type) {
+ case DV_EMPTY:
+ case DV_STRING:
+ /* string is valid in every size */
+ break;
+ case DV_FLOAT:
+ if(size == 1)
+ Error(ERR_DECLDATA_FLOAT, (char *)NULL, "DB");
+ else if(size == 2)
+ Error(ERR_DECLDATA_FLOAT, (char *)NULL, "DW");
+ break;
+ case DV_EXPR:
+ if(size == 10)
+ Error(ERR_DECLDATA_EXPR, (char *)NULL, "DT");
+ break;
+ }
+ cur = cur->next;
+ }
+
+ bc->next = (bytecode *)NULL;
+ bc->type = BC_DATA;
+
+ bc->data.data.data = data;
+ bc->data.data.size = size;
+
+ BuildBC_Common(bc);
}
void
-DebugPrintBC (bytecode *bc)
+BuildBC_Reserve (bytecode *bc,
+ expr *numitems,
+ unsigned long itemsize)
{
- unsigned long i;
+ bc->next = (bytecode *)NULL;
+ bc->type = BC_RESERVE;
+ bc->data.reserve.numitems = numitems;
+ bc->data.reserve.itemsize = itemsize;
+
+ BuildBC_Common(bc);
+}
+
+void
+DebugPrintBC (bytecode *bc)
+{
switch(bc->type) {
+ case BC_EMPTY:
+ printf("_Empty_\n");
+ break;
case BC_INSN:
printf("_Instruction_\n");
printf("Effective Address:\n");
break;
case BC_DATA:
printf("_Data_\n");
- for(i=0; i<bc->len; i++) {
- printf("%2x ", (unsigned int)bc->data.data.data[i]);
- if((i & ~0xFFFF) == i)
- printf("\n");
- }
+ printf("Final Element Size=%u\n",
+ (unsigned int)bc->data.data.size);
+ printf("Elements:\n");
+ dataval_print(bc->data.data.data);
break;
case BC_RESERVE:
printf("_Reserve_\n");
+ printf("Num Items=");
+ expr_print(bc->data.reserve.numitems);
+ printf("\nItem Size=%u\n",
+ (unsigned int)bc->data.reserve.itemsize);
break;
default:
printf("_Unknown_\n");
bc->filename ? bc->filename : "<UNKNOWN>", bc->lineno);
printf("Offset=%lx BITS=%u\n", bc->offset, bc->mode_bits);
}
+
+dataval *
+dataval_new_expr (expr *exp)
+{
+ dataval *retval = malloc(sizeof(dataval));
+
+ if(!retval)
+ Fatal(FATAL_NOMEM);
+
+ retval->next = (dataval *)NULL;
+ retval->last = retval;
+ retval->type = DV_EXPR;
+ retval->data.exp = exp;
+
+ return retval;
+}
+
+dataval *
+dataval_new_float (double float_val)
+{
+ dataval *retval = malloc(sizeof(dataval));
+
+ if(!retval)
+ Fatal(FATAL_NOMEM);
+
+ retval->next = (dataval *)NULL;
+ retval->last = retval;
+ retval->type = DV_FLOAT;
+ retval->data.float_val = float_val;
+
+ return retval;
+}
+
+dataval *
+dataval_new_string (char *str_val)
+{
+ dataval *retval = malloc(sizeof(dataval));
+
+ if(!retval)
+ Fatal(FATAL_NOMEM);
+
+ retval->next = (dataval *)NULL;
+ retval->last = retval;
+ retval->type = DV_STRING;
+ retval->data.str_val = str_val;
+
+ return retval;
+}
+
+dataval *
+dataval_append (dataval *list, dataval *item)
+{
+ if(item)
+ item->next = (dataval *)NULL;
+
+ if(!list) {
+ item->last = item;
+ return item;
+ } else {
+ if(item) {
+ list->last->next = item;
+ list->last = item;
+ item->last = (dataval *)NULL;
+ }
+ return list;
+ }
+}
+
+void
+dataval_print (dataval *start)
+{
+ dataval *cur = start;
+
+ while(cur) {
+ switch(cur->type) {
+ case DV_EMPTY:
+ printf(" Empty\n");
+ break;
+ case DV_EXPR:
+ printf(" Expr=");
+ expr_print(cur->data.exp);
+ printf("\n");
+ break;
+ case DV_FLOAT:
+ printf(" Float=%e\n", cur->data.float_val);
+ break;
+ case DV_STRING:
+ printf(" String=%s\n", cur->data.str_val);
+ break;
+ }
+
+ cur = cur->next;
+ }
+}
+
-/* $Id: bytecode.h,v 1.14 2001/07/11 23:16:50 peter Exp $
+/* $Id: bytecode.h,v 1.15 2001/07/25 00:33:10 peter Exp $
* Bytecode utility functions header file
*
* Copyright (C) 2001 Peter Johnson
unsigned char f_sign; /* 1 if final imm should be signed */
} immval;
+typedef struct dataval_s {
+ struct dataval_s *next, *last;
+
+ enum { DV_EMPTY, DV_EXPR, DV_FLOAT, DV_STRING } type;
+
+ union {
+ struct expr_s *exp;
+ double float_val;
+ char *str_val;
+ } data;
+} dataval;
+
typedef enum jmprel_opcode_sel_e {
JR_NONE,
JR_SHORT,
typedef struct bytecode_s {
struct bytecode_s *next;
- enum { BC_INSN, BC_JMPREL, BC_DATA, BC_RESERVE } type;
+ enum { BC_EMPTY, BC_INSN, BC_JMPREL, BC_DATA, BC_RESERVE } type;
union {
struct {
unsigned char lockrep_pre; /* 0 indicates no prefix */
} jmprel;
struct {
- unsigned char *data;
+ dataval *data; /* non-converted data (linked list) */
+
+ /* final (converted) size of each element (in bytes) */
+ unsigned char size;
} data;
+ struct {
+ struct expr_s *numitems; /* number of items to reserve */
+ unsigned char itemsize; /* size of each item (in bytes) */
+ } reserve;
} data;
unsigned long len; /* total length of entire bytecode */
unsigned char near_op2,
unsigned char addrsize);
-unsigned char *ConvertBCInsnToBytes(unsigned char *ptr, bytecode *bc, int *len);
+void BuildBC_Data(bytecode *bc,
+ dataval *data,
+ unsigned long size);
+
+void BuildBC_Reserve(bytecode *bc,
+ struct expr_s *numitems,
+ unsigned long itemsize);
void DebugPrintBC(bytecode *bc);
+dataval *dataval_new_expr(struct expr_s *exp);
+dataval *dataval_new_float(double float_val);
+dataval *dataval_new_string(char *str_val);
+
+dataval *dataval_append(dataval *list, dataval *item);
+
+void dataval_print(dataval *start);
+
#endif
-/* $Id: errwarn.c,v 1.16 2001/07/11 23:16:50 peter Exp $
+/* $Id: errwarn.c,v 1.17 2001/07/25 00:33:10 peter Exp $
* Error and warning reporting and related functions.
*
* Copyright (C) 2001 Peter Johnson
"expression syntax error",
"duplicate definition of `%1'; previously defined line %2",
"mismatch in operand sizes",
- "no %s form of that jump instruction exists"
+ "no %s form of that jump instruction exists",
+ "unterminated string",
+ "unexpected end of file in string",
+ "expression syntax error",
+ "floating-point constant encountered in `%s'",
+ "non-floating-point value encountered in `%s'"
};
/* Warning messages. Match up with warn_num enum in errwarn.h. */
"multiple segment overrides, using leftmost",
"multiple LOCK or REP prefixes, using leftmost",
"no non-local label before '%s'",
- "multiple SHORT or NEAR specifiers, using leftmost"
+ "multiple SHORT or NEAR specifiers, using leftmost",
+ "character constant too large, ignoring trailing characters"
};
/* I hate to define these strings as static buffers; a better solution would be
-/* $Id: errwarn.h,v 1.10 2001/07/11 23:16:50 peter Exp $
+/* $Id: errwarn.h,v 1.11 2001/07/25 00:33:10 peter Exp $
* Error and warning reporting and related functions header file.
*
* Copyright (C) 2001 Peter Johnson
ERR_EXP_SYNTAX,
ERR_DUPLICATE_DEF,
ERR_OP_SIZE_MISMATCH,
- ERR_NO_JMPREL_FORM
+ ERR_NO_JMPREL_FORM,
+ ERR_STRING_UNTERM,
+ ERR_STRING_EOF,
+ ERR_EXPR_SYNTAX,
+ ERR_DECLDATA_FLOAT,
+ ERR_DECLDATA_EXPR
} err_num;
/* Warning constants. Match up with warn_msgs in errwarn.c. */
WARN_MULT_SEG_OVERRIDE,
WARN_MULT_LOCKREP_PREFIX,
WARN_NO_BASE_LABEL,
- WARN_MULT_SHORTNEAR
+ WARN_MULT_SHORTNEAR,
+ WARN_CHAR_CONST_TOO_BIG
} warn_num;
char *conv_unprint(char ch);
-/* $Id: bison.y.in,v 1.21 2001/07/11 21:04:58 peter Exp $
+/* $Id: bison.y.in,v 1.22 2001/07/25 00:33:10 peter Exp $
* Main bison parser
*
* Copyright (C) 2001 Peter Johnson, Michael Urman
void init_table(void);
extern int yylex(void);
extern void yyerror(char *);
+static unsigned long ConvertCharConstToInt(char *);
%}
expr *exp;
immval im_val;
targetval tgt_val;
+ dataval *data;
bytecode bc;
-}
+}
%token <int_val> INTNUM
%token <double_val> FLTNUM
-%token <str_val> DIRECTIVE_NAME DIRECTIVE_VAL
+%token <str_val> DIRECTIVE_NAME DIRECTIVE_VAL STRING
%token <int_val> BYTE WORD DWORD QWORD TWORD DQWORD
%token <int_val> DECLARE_DATA
%token <int_val> RESERVE_SPACE
%type <ea_val> rm8x rm16x rm32x /*rm64x rm128x*/
%type <ea_val> rm8 rm16 rm32 rm64 rm128
%type <im_val> imm imm8x imm16x imm32x imm8 imm16 imm32
-%type <exp> expr
+%type <exp> expr expr_no_string
%type <syminfo> explabel
%type <sym> label_id
%type <tgt_val> target
+%type <data> dataval datavals
%left '|'
%left '^'
| input line { OutputError(); OutputWarning(); line_number++; }
;
-line: '\n' { $$.len = 0; }
+line: '\n' { $$.type = BC_EMPTY; }
| exp '\n' { DebugPrintBC(&$1); $$ = $1; }
| label exp '\n' { DebugPrintBC(&$2); $$ = $2; }
| label '\n'
- | directive '\n' { }
- | error '\n' { Error(ERR_INVALID_LINE, (char *)NULL); yyerrok; }
+ | directive '\n' { $$.type = BC_EMPTY; }
+ | error '\n' {
+ Error(ERR_INVALID_LINE, (char *)NULL);
+ $$.type = BC_EMPTY;
+ yyerrok;
+ }
;
exp: instr
+ | DECLARE_DATA datavals { BuildBC_Data(&$$, $2, $1); }
+ | RESERVE_SPACE expr { BuildBC_Reserve(&$$, $2, $1); }
+;
+
+datavals: dataval
+ | datavals ',' dataval { $$ = dataval_append($1, $3); }
+;
+
+dataval: expr_no_string { $$ = dataval_new_expr($1); }
+ | FLTNUM { $$ = dataval_new_float($1); }
+ | STRING { $$ = dataval_new_string($1); }
+ | error {
+ Error(ERR_EXPR_SYNTAX, (char *)NULL);
+ $$ = (dataval *)NULL;
+ }
;
label: label_id { $1->value = 0; } /* TODO: calculate offset */
;
/* expression trees */
-expr:
- INTNUM { $$ = expr_new_ident (EXPR_NUM, ExprNum($1)); }
+expr_no_string: INTNUM { $$ = expr_new_ident (EXPR_NUM, ExprNum($1)); }
| explabel { $$ = expr_new_ident (EXPR_SYM, ExprSym(sym_use_get ($1.name, SYM_LABEL))); }
/*| expr '||' expr { $$ = expr_new_tree ($1, EXPR_LOR, $3); }*/
| expr '|' expr { $$ = expr_new_tree ($1, EXPR_OR, $3); }
| '(' expr ')' { $$ = $2; }
;
+expr: expr_no_string
+ | STRING { $$ = expr_new_ident (EXPR_NUM, ExprNum(ConvertCharConstToInt($1))); }
+;
+
explabel: ID | SPECIAL_ID | LOCAL_ID ;
instr: instrbase
/* instruction grammars (dynamically generated) */
/* @INSTRUCTIONS@ */
+%%
+
+static unsigned long
+ConvertCharConstToInt(char *cc)
+{
+ unsigned long retval = 0;
+ size_t len = strlen(cc);
+
+ if(len > 4)
+ Warning(WARN_CHAR_CONST_TOO_BIG, (char *)NULL);
+
+ switch(len) {
+ case 4:
+ retval |= (unsigned long)cc[3];
+ retval <<= 8;
+ case 3:
+ retval |= (unsigned long)cc[2];
+ retval <<= 8;
+ case 2:
+ retval |= (unsigned long)cc[1];
+ retval <<= 8;
+ case 1:
+ retval |= (unsigned long)cc[0];
+ }
+
+ return retval;
+}
+
-/* $Id: nasm-bison.y,v 1.21 2001/07/11 21:04:58 peter Exp $
+/* $Id: nasm-bison.y,v 1.22 2001/07/25 00:33:10 peter Exp $
* Main bison parser
*
* Copyright (C) 2001 Peter Johnson, Michael Urman
void init_table(void);
extern int yylex(void);
extern void yyerror(char *);
+static unsigned long ConvertCharConstToInt(char *);
%}
expr *exp;
immval im_val;
targetval tgt_val;
+ dataval *data;
bytecode bc;
-}
+}
%token <int_val> INTNUM
%token <double_val> FLTNUM
-%token <str_val> DIRECTIVE_NAME DIRECTIVE_VAL
+%token <str_val> DIRECTIVE_NAME DIRECTIVE_VAL STRING
%token <int_val> BYTE WORD DWORD QWORD TWORD DQWORD
%token <int_val> DECLARE_DATA
%token <int_val> RESERVE_SPACE
%type <ea_val> rm8x rm16x rm32x /*rm64x rm128x*/
%type <ea_val> rm8 rm16 rm32 rm64 rm128
%type <im_val> imm imm8x imm16x imm32x imm8 imm16 imm32
-%type <exp> expr
+%type <exp> expr expr_no_string
%type <syminfo> explabel
%type <sym> label_id
%type <tgt_val> target
+%type <data> dataval datavals
%left '|'
%left '^'
| input line { OutputError(); OutputWarning(); line_number++; }
;
-line: '\n' { $$.len = 0; }
+line: '\n' { $$.type = BC_EMPTY; }
| exp '\n' { DebugPrintBC(&$1); $$ = $1; }
| label exp '\n' { DebugPrintBC(&$2); $$ = $2; }
| label '\n'
- | directive '\n' { }
- | error '\n' { Error(ERR_INVALID_LINE, (char *)NULL); yyerrok; }
+ | directive '\n' { $$.type = BC_EMPTY; }
+ | error '\n' {
+ Error(ERR_INVALID_LINE, (char *)NULL);
+ $$.type = BC_EMPTY;
+ yyerrok;
+ }
;
exp: instr
+ | DECLARE_DATA datavals { BuildBC_Data(&$$, $2, $1); }
+ | RESERVE_SPACE expr { BuildBC_Reserve(&$$, $2, $1); }
+;
+
+datavals: dataval
+ | datavals ',' dataval { $$ = dataval_append($1, $3); }
+;
+
+dataval: expr_no_string { $$ = dataval_new_expr($1); }
+ | FLTNUM { $$ = dataval_new_float($1); }
+ | STRING { $$ = dataval_new_string($1); }
+ | error {
+ Error(ERR_EXPR_SYNTAX, (char *)NULL);
+ $$ = (dataval *)NULL;
+ }
;
label: label_id { $1->value = 0; } /* TODO: calculate offset */
;
/* expression trees */
-expr:
- INTNUM { $$ = expr_new_ident (EXPR_NUM, ExprNum($1)); }
+expr_no_string: INTNUM { $$ = expr_new_ident (EXPR_NUM, ExprNum($1)); }
| explabel { $$ = expr_new_ident (EXPR_SYM, ExprSym(sym_use_get ($1.name, SYM_LABEL))); }
/*| expr '||' expr { $$ = expr_new_tree ($1, EXPR_LOR, $3); }*/
| expr '|' expr { $$ = expr_new_tree ($1, EXPR_OR, $3); }
| '(' expr ')' { $$ = $2; }
;
+expr: expr_no_string
+ | STRING { $$ = expr_new_ident (EXPR_NUM, ExprNum(ConvertCharConstToInt($1))); }
+;
+
explabel: ID | SPECIAL_ID | LOCAL_ID ;
instr: instrbase
/* instruction grammars (dynamically generated) */
/* @INSTRUCTIONS@ */
+%%
+
+static unsigned long
+ConvertCharConstToInt(char *cc)
+{
+ unsigned long retval = 0;
+ size_t len = strlen(cc);
+
+ if(len > 4)
+ Warning(WARN_CHAR_CONST_TOO_BIG, (char *)NULL);
+
+ switch(len) {
+ case 4:
+ retval |= (unsigned long)cc[3];
+ retval <<= 8;
+ case 3:
+ retval |= (unsigned long)cc[2];
+ retval <<= 8;
+ case 2:
+ retval |= (unsigned long)cc[1];
+ retval <<= 8;
+ case 1:
+ retval |= (unsigned long)cc[0];
+ }
+
+ return retval;
+}
+
-/* $Id: token.l.in,v 1.11 2001/07/11 21:01:54 peter Exp $
+/* $Id: token.l.in,v 1.12 2001/07/25 00:33:10 peter Exp $
* Main lexer
*
* Copyright (C) 2001 Peter Johnson
#include "expr.h"
#include "bison.h"
+/* starting size of string buffer */
+#define STRBUF_ALLOC_SIZE 128
+
+/* string buffer used when parsing strings/character constants */
+static char *strbuf = (char *)NULL;
+
+/* length of strbuf (including terminating NULL character) */
+static size_t strbuf_size = 0;
+
%}
%option noyywrap
%option nounput
yylval.double_val = strtod(yytext, (char **)NULL);
return FLTNUM;
}
+
+ /* string/character constant values */
+["'] {
+ int inch, count;
+ char endch = yytext[0];
+
+ strbuf = malloc(STRBUF_ALLOC_SIZE);
+ if(!strbuf)
+ Fatal(FATAL_NOMEM);
+
+ strbuf_size = STRBUF_ALLOC_SIZE;
+ inch = input();
+ count = 0;
+ while(inch != EOF && inch != endch && inch != '\n') {
+ strbuf[count++] = inch;
+ if(count >= strbuf_size) {
+ strbuf = realloc(strbuf, strbuf_size + STRBUF_ALLOC_SIZE);
+ if(!strbuf)
+ Fatal(FATAL_NOMEM);
+ strbuf_size += STRBUF_ALLOC_SIZE;
+ }
+ inch = input();
+ }
+
+ if(inch == '\n')
+ Error(ERR_STRING_UNTERM, (char *)NULL);
+ else if(inch == EOF)
+ Error(ERR_STRING_EOF, (char *)NULL);
+
+ strbuf[count] = '\0';
+
+ yylval.str_val = strbuf;
+ return STRING;
+}
+
/* directive: [name value] */
^"[" { BEGIN DIRECTIVE; return '['; }
<DIRECTIVE>"]" { BEGIN INITIAL; return ']'; }
-/* $Id: token.l.in,v 1.11 2001/07/11 21:01:54 peter Exp $
+/* $Id: token.l.in,v 1.12 2001/07/25 00:33:10 peter Exp $
* Main lexer
*
* Copyright (C) 2001 Peter Johnson
#include "expr.h"
#include "bison.h"
+/* starting size of string buffer */
+#define STRBUF_ALLOC_SIZE 128
+
+/* string buffer used when parsing strings/character constants */
+static char *strbuf = (char *)NULL;
+
+/* length of strbuf (including terminating NULL character) */
+static size_t strbuf_size = 0;
+
%}
%option noyywrap
%option nounput
yylval.double_val = strtod(yytext, (char **)NULL);
return FLTNUM;
}
+
+ /* string/character constant values */
+["'] {
+ int inch, count;
+ char endch = yytext[0];
+
+ strbuf = malloc(STRBUF_ALLOC_SIZE);
+ if(!strbuf)
+ Fatal(FATAL_NOMEM);
+
+ strbuf_size = STRBUF_ALLOC_SIZE;
+ inch = input();
+ count = 0;
+ while(inch != EOF && inch != endch && inch != '\n') {
+ strbuf[count++] = inch;
+ if(count >= strbuf_size) {
+ strbuf = realloc(strbuf, strbuf_size + STRBUF_ALLOC_SIZE);
+ if(!strbuf)
+ Fatal(FATAL_NOMEM);
+ strbuf_size += STRBUF_ALLOC_SIZE;
+ }
+ inch = input();
+ }
+
+ if(inch == '\n')
+ Error(ERR_STRING_UNTERM, (char *)NULL);
+ else if(inch == EOF)
+ Error(ERR_STRING_EOF, (char *)NULL);
+
+ strbuf[count] = '\0';
+
+ yylval.str_val = strbuf;
+ return STRING;
+}
+
/* directive: [name value] */
^"[" { BEGIN DIRECTIVE; return '['; }
<DIRECTIVE>"]" { BEGIN INITIAL; return ']'; }