]> granicus.if.org Git - yasm/commitdiff
NASM parser: change from Bison parser to hand-written recursive descent
authorPeter Johnson <peter@tortall.net>
Sat, 23 Dec 2006 10:20:51 +0000 (10:20 -0000)
committerPeter Johnson <peter@tortall.net>
Sat, 23 Dec 2006 10:20:51 +0000 (10:20 -0000)
parser with one token of lookahead.  This allows for better error handling
and proper handling of things like "xxxx"/5.  There may be a minor speedup
but it's probably a wash.

Still TODO:
 - Unify the expression parser with the NASM preproc one.
 - Change the GAS parser to recursive descent.

Only had to change one test result; this is due to re-ordering of symrec
creation versus symrec use in data expressions such as x db y.  With the
Bison parser, the symrec use (y) would come first, now the symrec creation
(x) comes first.

svn path=/trunk/yasm/; revision=1716

modules/objfmts/win64/tests/win64-dataref.hex
modules/parsers/nasm/Makefile.inc
modules/parsers/nasm/nasm-bison.y [deleted file]
modules/parsers/nasm/nasm-defs.h [deleted file]
modules/parsers/nasm/nasm-parse.c [new file with mode: 0644]
modules/parsers/nasm/nasm-parser.c
modules/parsers/nasm/nasm-parser.h
modules/parsers/nasm/nasm-token.re

index fa604a6fce465438dd7b220a3114ce124ce78fe6..3af07864f79fe0b9b9908e81c343f5c5e6ea889d 100644 (file)
@@ -1364,7 +1364,7 @@ f8
 00 
 00 
 00 
-16 
+17 
 00 
 00 
 00 
@@ -1374,7 +1374,7 @@ f8
 00 
 00 
 00 
-16 
+17 
 00 
 00 
 00 
@@ -1999,36 +1999,36 @@ a0
 03 
 00 
 78 
+70 
+74 
+72 
 00 
 00 
 00 
 00 
+40 
 00 
 00 
 00 
-00 
+02 
 00 
 00 
 00 
 03 
 00 
+78 
+00 
 00 
 00 
-03 
 00 
-78 
-70 
-74 
-72 
 00 
 00 
 00 
 00 
-40 
 00 
 00 
 00 
-02 
+03 
 00 
 00 
 00 
index 4a57f65cf4a6c1d4570e15d8c4a89ea70ab9e164..f4fb977fc5eb249fc8cc171ce397a738743ce7a1 100644 (file)
@@ -2,9 +2,7 @@
 
 libyasm_a_SOURCES += modules/parsers/nasm/nasm-parser.c
 libyasm_a_SOURCES += modules/parsers/nasm/nasm-parser.h
-libyasm_a_SOURCES += modules/parsers/nasm/nasm-defs.h
-libyasm_a_SOURCES += modules/parsers/nasm/nasm-bison.y
-libyasm_a_SOURCES += nasm-bison.h
+libyasm_a_SOURCES += modules/parsers/nasm/nasm-parse.c
 libyasm_a_SOURCES += nasm-token.c
 
 YASM_MODULES += parser_nasm
@@ -12,12 +10,8 @@ YASM_MODULES += parser_nasm
 nasm-token.c: $(srcdir)/modules/parsers/nasm/nasm-token.re re2c$(EXEEXT)
        $(top_builddir)/re2c$(EXEEXT) -b -o $@ $(srcdir)/modules/parsers/nasm/nasm-token.re
 
-BUILT_SOURCES += nasm-bison.c
-BUILT_SOURCES += nasm-bison.h
 BUILT_SOURCES += nasm-token.c
 
-CLEANFILES += nasm-bison.c
-CLEANFILES += nasm-bison.h
 CLEANFILES += nasm-token.c
 
 EXTRA_DIST += modules/parsers/nasm/tests/Makefile.inc
diff --git a/modules/parsers/nasm/nasm-bison.y b/modules/parsers/nasm/nasm-bison.y
deleted file mode 100644 (file)
index 9fc0dcd..0000000
+++ /dev/null
@@ -1,694 +0,0 @@
-/*
- * NASM-compatible bison parser
- *
- *  Copyright (C) 2001  Peter Johnson, Michael Urman
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-%{
-#include <util.h>
-RCSID("$Id$");
-
-#define YASM_LIB_INTERNAL
-#define YASM_EXPR_INTERNAL
-#include <libyasm.h>
-
-#ifdef STDC_HEADERS
-# include <math.h>
-#endif
-
-#include "modules/parsers/nasm/nasm-parser.h"
-#include "modules/parsers/nasm/nasm-defs.h"
-
-static void nasm_parser_directive
-    (yasm_parser_nasm *parser_nasm, const char *name,
-     yasm_valparamhead *valparams,
-     /*@null@*/ yasm_valparamhead *objext_valparams);
-static int fix_directive_symrec(/*@null@*/ yasm_expr__item *ei,
-                               /*@null@*/ void *d);
-static void define_label(yasm_parser_nasm *parser_nasm, /*@only@*/ char *name,
-                        int local);
-
-#define nasm_parser_error(s)   yasm_error_set(YASM_ERROR_PARSE, "%s", s)
-#define YYPARSE_PARAM  parser_nasm_arg
-#define YYLEX_PARAM    parser_nasm_arg
-#define parser_nasm    ((yasm_parser_nasm *)parser_nasm_arg)
-#define nasm_parser_debug   (parser_nasm->debug)
-
-/*@-usedef -nullassign -memtrans -usereleased -compdef -mustfree@*/
-%}
-
-%pure_parser
-
-%union {
-    unsigned int int_info;
-    char *str_val;
-    yasm_intnum *intn;
-    yasm_floatnum *flt;
-    yasm_symrec *sym;
-    unsigned long arch_data[4];
-    yasm_effaddr *ea;
-    yasm_expr *exp;
-    yasm_datavalhead datahead;
-    yasm_dataval *data;
-    yasm_bytecode *bc;
-    yasm_valparamhead dir_valparams;
-    yasm_valparam *dir_valparam;
-    struct {
-       yasm_insn_operands operands;
-       int num_operands;
-    } insn_operands;
-    yasm_insn_operand *insn_operand;
-    struct {
-       char *name;
-       int local;
-    } label;
-    struct {
-       char *contents;
-       size_t len;
-    } str;
-}
-
-%token <intn> INTNUM
-%token <flt> FLTNUM
-%token <str_val> DIRECTIVE_NAME FILENAME
-%token <str> STRING ONECHARSTR
-%token <int_info> SIZE_OVERRIDE
-%token <int_info> DECLARE_DATA
-%token <int_info> RESERVE_SPACE
-%token INCBIN EQU TIMES
-%token SEG WRT NOSPLIT STRICT
-%token <arch_data> INSN PREFIX REG SEGREG TARGETMOD
-%token LEFT_OP RIGHT_OP SIGNDIV SIGNMOD START_SECTION_ID
-%token <str_val> ID LOCAL_ID SPECIAL_ID
-%token LINE
-
-%type <bc> line lineexp exp instr
-
-%type <ea> memaddr
-%type <exp> dvexpr expr direxpr
-%type <sym> explabel
-%type <label> label_id label
-%type <data> dataval
-%type <datahead> datavals
-%type <dir_valparams> directive_valparams
-%type <dir_valparam> directive_valparam
-%type <insn_operands> operands
-%type <insn_operand> operand
-%type <str> string
-
-%left ':'
-%left WRT
-%left '|'
-%left '^'
-%left '&'
-%left LEFT_OP RIGHT_OP
-%left '-' '+'
-%left '*' '/' SIGNDIV '%' SIGNMOD
-%nonassoc UNARYOP
-%nonassoc SEG
-
-%%
-input: /* empty */
-    | input line    {
-       yasm_errwarn_propagate(parser_nasm->errwarns, cur_line);
-       parser_nasm->temp_bc =
-           yasm_section_bcs_append(parser_nasm->cur_section, $2);
-       if (parser_nasm->temp_bc)
-           parser_nasm->prev_bc = parser_nasm->temp_bc;
-       if (parser_nasm->save_input)
-           yasm_linemap_add_source(parser_nasm->linemap,
-               parser_nasm->temp_bc,
-               (char *)parser_nasm->save_line[parser_nasm->save_last ^ 1]);
-       yasm_linemap_goto_next(parser_nasm->linemap);
-    }
-;
-
-line: '\n'             { $$ = (yasm_bytecode *)NULL; }
-    | lineexp '\n'
-    | LINE INTNUM '+' INTNUM FILENAME '\n' {
-       /* %line indicates the line number of the *next* line, so subtract out
-        * the increment when setting the line number.
-        */
-       yasm_linemap_set(parser_nasm->linemap, $5,
-           yasm_intnum_get_uint($2) - yasm_intnum_get_uint($4),
-           yasm_intnum_get_uint($4));
-       yasm_intnum_destroy($2);
-       yasm_intnum_destroy($4);
-       yasm_xfree($5);
-       $$ = (yasm_bytecode *)NULL;
-    }
-    | '[' { parser_nasm->state = DIRECTIVE; } directive ']' '\n' {
-       $$ = (yasm_bytecode *)NULL;
-    }
-    | error '\n'       {
-       yasm_error_set(YASM_ERROR_SYNTAX,
-                      N_("label or instruction expected at start of line"));
-       $$ = (yasm_bytecode *)NULL;
-       yyerrok;
-    }
-;
-
-lineexp: exp
-    | TIMES expr exp           { $$ = $3; yasm_bc_set_multiple($$, $2); }
-    | label_id                 {
-       yasm_warn_set(YASM_WARN_ORPHAN_LABEL,
-           N_("label alone on a line without a colon might be in error"));
-       $$ = (yasm_bytecode *)NULL;
-       define_label(parser_nasm, $1.name, $1.local);
-    }
-    | label_id ':'             {
-       $$ = (yasm_bytecode *)NULL;
-       define_label(parser_nasm, $1.name, $1.local);
-    }
-    | label exp                        {
-       $$ = $2;
-       define_label(parser_nasm, $1.name, $1.local);
-    }
-    | label TIMES expr exp     {
-       $$ = $4;
-       yasm_bc_set_multiple($$, $3);
-       define_label(parser_nasm, $1.name, $1.local);
-    }
-    | label EQU expr           {
-       $$ = (yasm_bytecode *)NULL;
-       yasm_symtab_define_equ(p_symtab, $1.name, $3, cur_line);
-       yasm_xfree($1.name);
-    }
-;
-
-exp: instr
-    | DECLARE_DATA datavals            {
-       $$ = yasm_bc_create_data(&$2, $1/8, 0, parser_nasm->arch, cur_line);
-    }
-    | RESERVE_SPACE expr               {
-       $$ = yasm_bc_create_reserve($2, $1/8, cur_line);
-    }
-    | INCBIN string                    {
-       $$ = yasm_bc_create_incbin($2.contents, NULL, NULL,
-                                  parser_nasm->linemap, cur_line);
-    }
-    | INCBIN string ','                        {
-       $$ = yasm_bc_create_incbin($2.contents, NULL, NULL,
-                                  parser_nasm->linemap, cur_line);
-    }
-    | INCBIN string ',' expr           {
-       $$ = yasm_bc_create_incbin($2.contents, $4, NULL,
-                                  parser_nasm->linemap, cur_line);
-    }
-    | INCBIN string ',' expr ','       {
-       $$ = yasm_bc_create_incbin($2.contents, $4, NULL,
-                                  parser_nasm->linemap, cur_line);
-    }
-    | INCBIN string ',' expr ',' expr  {
-       $$ = yasm_bc_create_incbin($2.contents, $4, $6, parser_nasm->linemap,
-                                  cur_line);
-    }
-;
-
-instr: INSN            {
-       $$ = yasm_bc_create_insn(parser_nasm->arch, $1, 0, NULL, cur_line);
-    }
-    | INSN operands    {
-       $$ = yasm_bc_create_insn(parser_nasm->arch, $1, $2.num_operands,
-                                &$2.operands, cur_line);
-    }
-    | INSN error       {
-       yasm_error_set(YASM_ERROR_SYNTAX, N_("expression syntax error"));
-       $$ = NULL;
-    }
-    | PREFIX instr     {
-       $$ = $2;
-       yasm_bc_insn_add_prefix($$, $1);
-    }
-    | SEGREG instr     {
-       $$ = $2;
-       yasm_bc_insn_add_seg_prefix($$, $1[0]);
-    }
-;
-
-datavals: dataval          {
-       yasm_dvs_initialize(&$$);
-       yasm_dvs_append(&$$, $1);
-    }
-    | datavals ',' dataval  { yasm_dvs_append(&$1, $3); $$ = $1; }
-    | datavals ','         { $$ = $1; }
-;
-
-dataval: dvexpr                { $$ = yasm_dv_create_expr($1); }
-    | STRING           {
-       $$ = yasm_dv_create_string($1.contents, $1.len);
-    }
-    | error            {
-       yasm_error_set(YASM_ERROR_SYNTAX, N_("expression syntax error"));
-       $$ = (yasm_dataval *)NULL;
-    }
-;
-
-label: label_id
-    | label_id ':'     { $$ = $1; }
-;
-
-label_id: ID           { $$.name = $1; $$.local = 0; }
-    | SPECIAL_ID       { $$.name = $1; $$.local = 1; }
-    | LOCAL_ID         { $$.name = $1; $$.local = 1; }
-;
-
-/* directives */
-directive: DIRECTIVE_NAME directive_val        {
-       yasm_xfree($1);
-    }
-    | DIRECTIVE_NAME error             {
-       yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid arguments to [%s]"), $1);
-       yasm_xfree($1);
-    }
-;
-
-    /* $<str_val>0 is the DIRECTIVE_NAME */
-    /* After : is (optional) object-format specific extension */
-directive_val: directive_valparams {
-       nasm_parser_directive(parser_nasm, $<str_val>0, &$1, NULL);
-    }
-    | directive_valparams ':' directive_valparams {
-       nasm_parser_directive(parser_nasm, $<str_val>0, &$1, &$3);
-    }
-;
-
-directive_valparams: directive_valparam                {
-       yasm_vps_initialize(&$$);
-       yasm_vps_append(&$$, $1);
-    }
-    | directive_valparams directive_valparam   {
-       yasm_vps_append(&$1, $2);
-       $$ = $1;
-    }
-    | directive_valparams ',' directive_valparam    {
-       yasm_vps_append(&$1, $3);
-       $$ = $1;
-    }
-;
-
-directive_valparam: direxpr    {
-       /* If direxpr is just an ID, put it in val and delete the expr.
-        * Otherwise, we need to go through the expr and replace the current
-        * (local) symrecs with the use of global ones.
-        */
-       const /*@null@*/ yasm_symrec *vp_symrec;
-       if ((vp_symrec = yasm_expr_get_symrec(&$1, 0))) {
-           $$ = yasm_vp_create(yasm__xstrdup(yasm_symrec_get_name(vp_symrec)),
-                               NULL);
-           yasm_expr_destroy($1);
-       } else {
-           yasm_expr__traverse_leaves_in($1, parser_nasm,
-                                         fix_directive_symrec);
-           $$ = yasm_vp_create(NULL, $1);
-       }
-    }
-    | string                   { $$ = yasm_vp_create($1.contents, NULL); }
-    | ID '=' direxpr           {
-       yasm_expr__traverse_leaves_in($3, parser_nasm, fix_directive_symrec);
-       $$ = yasm_vp_create($1, $3);
-    }
-;
-
-/* memory addresses */
-memaddr: expr              {
-       $$ = yasm_arch_ea_create(parser_nasm->arch, $1);
-    }
-    | SEGREG ':' memaddr    {
-       $$ = $3;
-       yasm_ea_set_segreg($$, $1[0]);
-    }
-    | SIZE_OVERRIDE memaddr { $$ = $2; yasm_ea_set_len($$, $1); }
-    | NOSPLIT memaddr      { $$ = $2; yasm_ea_set_nosplit($$, 1); }
-;
-
-/* instruction operands */
-operands: operand          {
-       yasm_ops_initialize(&$$.operands);
-       yasm_ops_append(&$$.operands, $1);
-       $$.num_operands = 1;
-    }
-    | operands ',' operand  {
-       yasm_ops_append(&$1.operands, $3);
-       $$.operands = $1.operands;
-       $$.num_operands = $1.num_operands+1;
-    }
-;
-
-operand: '[' memaddr ']'    { $$ = yasm_operand_create_mem($2); }
-    | expr                 { $$ = yasm_operand_create_imm($1); }
-    | SEGREG               { $$ = yasm_operand_create_segreg($1[0]); }
-    | STRICT operand       { $$ = $2; $$->strict = 1; }
-    | SIZE_OVERRIDE operand {
-       $$ = $2;
-       if ($$->type == YASM_INSN__OPERAND_REG &&
-           yasm_arch_get_reg_size(parser_nasm->arch, $$->data.reg) != $1)
-           yasm_error_set(YASM_ERROR_TYPE,
-                          N_("cannot override register size"));
-       else
-           $$->size = $1;
-    }
-    | TARGETMOD operand            { $$ = $2; $$->targetmod = $1[0]; }
-;
-
-/* expression trees */
-
-/* expr w/o FLTNUM and unary + and -, for use in directives */
-direxpr: INTNUM                        { $$ = p_expr_new_ident(yasm_expr_int($1)); }
-    | ID                       {
-       $$ = p_expr_new_ident(yasm_expr_sym(
-           yasm_symtab_define_label(p_symtab, $1,
-               yasm_section_bcs_first(parser_nasm->cur_section), 0,
-               cur_line)));
-       yasm_xfree($1);
-    }
-    | direxpr '|' direxpr      { $$ = p_expr_new_tree($1, YASM_EXPR_OR, $3); }
-    | direxpr '^' direxpr      { $$ = p_expr_new_tree($1, YASM_EXPR_XOR, $3); }
-    | direxpr '&' direxpr      { $$ = p_expr_new_tree($1, YASM_EXPR_AND, $3); }
-    | direxpr LEFT_OP direxpr  { $$ = p_expr_new_tree($1, YASM_EXPR_SHL, $3); }
-    | direxpr RIGHT_OP direxpr { $$ = p_expr_new_tree($1, YASM_EXPR_SHR, $3); }
-    | direxpr '+' direxpr      { $$ = p_expr_new_tree($1, YASM_EXPR_ADD, $3); }
-    | direxpr '-' direxpr      { $$ = p_expr_new_tree($1, YASM_EXPR_SUB, $3); }
-    | direxpr '*' direxpr      { $$ = p_expr_new_tree($1, YASM_EXPR_MUL, $3); }
-    | direxpr '/' direxpr      { $$ = p_expr_new_tree($1, YASM_EXPR_DIV, $3); }
-    | direxpr SIGNDIV direxpr  { $$ = p_expr_new_tree($1, YASM_EXPR_SIGNDIV, $3); }
-    | direxpr '%' direxpr      { $$ = p_expr_new_tree($1, YASM_EXPR_MOD, $3); }
-    | direxpr SIGNMOD direxpr  { $$ = p_expr_new_tree($1, YASM_EXPR_SIGNMOD, $3); }
-    /*| '!' expr           { $$ = p_expr_new_branch(YASM_EXPR_LNOT, $2); }*/
-    | '~' direxpr %prec UNARYOP        { $$ = p_expr_new_branch(YASM_EXPR_NOT, $2); }
-    | '(' direxpr ')'          { $$ = $2; }
-;
-
-dvexpr: INTNUM             { $$ = p_expr_new_ident(yasm_expr_int($1)); }
-    | FLTNUM               { $$ = p_expr_new_ident(yasm_expr_float($1)); }
-    | ONECHARSTR           {
-       $$ = p_expr_new_ident(yasm_expr_int(
-           yasm_intnum_create_charconst_nasm($1.contents)));
-       yasm_xfree($1.contents);
-    }
-    | explabel             { $$ = p_expr_new_ident(yasm_expr_sym($1)); }
-    /*| dvexpr '||' dvexpr  { $$ = p_expr_new_tree($1, YASM_EXPR_LOR, $3); }*/
-    | dvexpr '|' dvexpr            { $$ = p_expr_new_tree($1, YASM_EXPR_OR, $3); }
-    | dvexpr '^' dvexpr            { $$ = p_expr_new_tree($1, YASM_EXPR_XOR, $3); }
-    /*| dvexpr '&&' dvexpr  { $$ = p_expr_new_tree($1, YASM_EXPR_LAND, $3); }*/
-    | dvexpr '&' dvexpr            { $$ = p_expr_new_tree($1, YASM_EXPR_AND, $3); }
-    /*| dvexpr '==' dvexpr  { $$ = p_expr_new_tree($1, YASM_EXPR_EQUALS, $3); }*/
-    /*| dvexpr '>' dvexpr   { $$ = p_expr_new_tree($1, YASM_EXPR_GT, $3); }*/
-    /*| dvexpr '<' dvexpr   { $$ = p_expr_new_tree($1, YASM_EXPR_GT, $3); }*/
-    /*| dvexpr '>=' dvexpr  { $$ = p_expr_new_tree($1, YASM_EXPR_GE, $3); }*/
-    /*| dvexpr '<=' dvexpr  { $$ = p_expr_new_tree($1, YASM_EXPR_GE, $3); }*/
-    /*| dvexpr '!=' dvexpr  { $$ = p_expr_new_tree($1, YASM_EXPR_NE, $3); }*/
-    | dvexpr LEFT_OP dvexpr { $$ = p_expr_new_tree($1, YASM_EXPR_SHL, $3); }
-    | dvexpr RIGHT_OP dvexpr { $$ = p_expr_new_tree($1, YASM_EXPR_SHR, $3); }
-    | dvexpr '+' dvexpr            { $$ = p_expr_new_tree($1, YASM_EXPR_ADD, $3); }
-    | dvexpr '-' dvexpr            { $$ = p_expr_new_tree($1, YASM_EXPR_SUB, $3); }
-    | dvexpr '*' dvexpr            { $$ = p_expr_new_tree($1, YASM_EXPR_MUL, $3); }
-    | dvexpr '/' dvexpr            { $$ = p_expr_new_tree($1, YASM_EXPR_DIV, $3); }
-    | dvexpr SIGNDIV dvexpr { $$ = p_expr_new_tree($1, YASM_EXPR_SIGNDIV, $3); }
-    | dvexpr '%' dvexpr            { $$ = p_expr_new_tree($1, YASM_EXPR_MOD, $3); }
-    | dvexpr SIGNMOD dvexpr { $$ = p_expr_new_tree($1, YASM_EXPR_SIGNMOD, $3); }
-    | '+' dvexpr %prec UNARYOP  { $$ = $2; }
-    | '-' dvexpr %prec UNARYOP  { $$ = p_expr_new_branch(YASM_EXPR_NEG, $2); }
-    /*| '!' dvexpr         { $$ = p_expr_new_branch(YASM_EXPR_LNOT, $2); }*/
-    | '~' dvexpr %prec UNARYOP  { $$ = p_expr_new_branch(YASM_EXPR_NOT, $2); }
-    | SEG dvexpr               { $$ = p_expr_new_branch(YASM_EXPR_SEG, $2); }
-    | dvexpr WRT dvexpr            { $$ = p_expr_new_tree($1, YASM_EXPR_WRT, $3); }
-    | '(' dvexpr ')'           { $$ = $2; }
-;
-
-/* Expressions for operands and memory expressions.
- * We don't attempt to check memory expressions for validity here.
- * Essentially the same as dvexpr above but adds REG and string.
- */
-expr: INTNUM           { $$ = p_expr_new_ident(yasm_expr_int($1)); }
-    | FLTNUM           { $$ = p_expr_new_ident(yasm_expr_float($1)); }
-    | REG              { $$ = p_expr_new_ident(yasm_expr_reg($1[0])); }
-    | string           {
-       $$ = p_expr_new_ident(yasm_expr_int(
-           yasm_intnum_create_charconst_nasm($1.contents)));
-       yasm_xfree($1.contents);
-    }
-    | explabel         { $$ = p_expr_new_ident(yasm_expr_sym($1)); }
-    /*| expr '||' expr { $$ = p_expr_new_tree($1, YASM_EXPR_LOR, $3); }*/
-    | expr '|' expr    { $$ = p_expr_new_tree($1, YASM_EXPR_OR, $3); }
-    | expr '^' expr    { $$ = p_expr_new_tree($1, YASM_EXPR_XOR, $3); }
-    /*| expr '&&' expr { $$ = p_expr_new_tree($1, YASM_EXPR_LAND, $3); }*/
-    | expr '&' expr    { $$ = p_expr_new_tree($1, YASM_EXPR_AND, $3); }
-    /*| expr '==' expr { $$ = p_expr_new_tree($1, YASM_EXPR_EQUALS, $3); }*/
-    /*| expr '>' expr  { $$ = p_expr_new_tree($1, YASM_EXPR_GT, $3); }*/
-    /*| expr '<' expr  { $$ = p_expr_new_tree($1, YASM_EXPR_GT, $3); }*/
-    /*| expr '>=' expr { $$ = p_expr_new_tree($1, YASM_EXPR_GE, $3); }*/
-    /*| expr '<=' expr { $$ = p_expr_new_tree($1, YASM_EXPR_GE, $3); }*/
-    /*| expr '!=' expr { $$ = p_expr_new_tree($1, YASM_EXPR_NE, $3); }*/
-    | expr LEFT_OP expr        { $$ = p_expr_new_tree($1, YASM_EXPR_SHL, $3); }
-    | expr RIGHT_OP expr { $$ = p_expr_new_tree($1, YASM_EXPR_SHR, $3); }
-    | expr '+' expr    { $$ = p_expr_new_tree($1, YASM_EXPR_ADD, $3); }
-    | expr '-' expr    { $$ = p_expr_new_tree($1, YASM_EXPR_SUB, $3); }
-    | expr '*' expr    { $$ = p_expr_new_tree($1, YASM_EXPR_MUL, $3); }
-    | expr '/' expr    { $$ = p_expr_new_tree($1, YASM_EXPR_DIV, $3); }
-    | expr SIGNDIV expr        { $$ = p_expr_new_tree($1, YASM_EXPR_SIGNDIV, $3); }
-    | expr '%' expr    { $$ = p_expr_new_tree($1, YASM_EXPR_MOD, $3); }
-    | expr SIGNMOD expr        { $$ = p_expr_new_tree($1, YASM_EXPR_SIGNMOD, $3); }
-    | '+' expr %prec UNARYOP   { $$ = $2; }
-    | '-' expr %prec UNARYOP   { $$ = p_expr_new_branch(YASM_EXPR_NEG, $2); }
-    /*| '!' expr       { $$ = p_expr_new_branch(YASM_EXPR_LNOT, $2); }*/
-    | '~' expr %prec UNARYOP   { $$ = p_expr_new_branch(YASM_EXPR_NOT, $2); }
-    | SEG expr         { $$ = p_expr_new_branch(YASM_EXPR_SEG, $2); }
-    | expr WRT expr    { $$ = p_expr_new_tree($1, YASM_EXPR_WRT, $3); }
-    | expr ':' expr    { $$ = p_expr_new_tree($1, YASM_EXPR_SEGOFF, $3); }
-    | '(' expr ')'     { $$ = $2; }
-;
-
-explabel: ID           {
-       $$ = yasm_symtab_use(p_symtab, $1, cur_line);
-       yasm_xfree($1);
-    }
-    | SPECIAL_ID       {
-       $$ = yasm_symtab_use(p_symtab, $1, cur_line);
-       yasm_xfree($1);
-    }
-    | LOCAL_ID         {
-       $$ = yasm_symtab_use(p_symtab, $1, cur_line);
-       yasm_xfree($1);
-    }
-    | '$'              {
-       /* "$" references the current assembly position */
-       $$ = yasm_symtab_define_curpos(p_symtab, "$", parser_nasm->prev_bc,
-                                      cur_line);
-    }
-    | START_SECTION_ID {
-       /* "$$" references the start of the current section */
-       $$ = yasm_symtab_define_label(p_symtab, "$$",
-           yasm_section_bcs_first(parser_nasm->cur_section), 0, cur_line);
-    }
-;
-
-string: STRING | ONECHARSTR;
-
-%%
-/*@=usedef =nullassign =memtrans =usereleased =compdef =mustfree@*/
-
-#undef parser_nasm
-
-static void
-define_label(yasm_parser_nasm *parser_nasm, char *name, int local)
-{
-    if (!local) {
-       if (parser_nasm->locallabel_base)
-           yasm_xfree(parser_nasm->locallabel_base);
-       parser_nasm->locallabel_base_len = strlen(name);
-       parser_nasm->locallabel_base =
-           yasm_xmalloc(parser_nasm->locallabel_base_len+1);
-       strcpy(parser_nasm->locallabel_base, name);
-    }
-
-    yasm_symtab_define_label(p_symtab, name, parser_nasm->prev_bc, 1,
-                            cur_line);
-    yasm_xfree(name);
-}
-
-static int
-fix_directive_symrec(yasm_expr__item *ei, void *d)
-{
-    yasm_parser_nasm *parser_nasm = (yasm_parser_nasm *)d;
-    if (!ei || ei->type != YASM_EXPR_SYM)
-       return 0;
-
-    /* FIXME: Delete current symrec */
-    ei->data.sym =
-       yasm_symtab_use(p_symtab, yasm_symrec_get_name(ei->data.sym),
-                       cur_line);
-
-    return 0;
-}
-
-static void
-nasm_parser_directive(yasm_parser_nasm *parser_nasm, const char *name,
-                     yasm_valparamhead *valparams,
-                     yasm_valparamhead *objext_valparams)
-{
-    yasm_valparam *vp, *vp2;
-    unsigned long line = cur_line;
-
-    /* Handle (mostly) output-format independent directives here */
-    if (yasm__strcasecmp(name, "extern") == 0) {
-       vp = yasm_vps_first(valparams);
-       if (vp->val) {
-           yasm_objfmt_extern_declare(parser_nasm->objfmt, vp->val,
-                                      objext_valparams, line);
-       } else
-           yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid argument to [%s]"),
-                          "EXTERN");
-    } else if (yasm__strcasecmp(name, "global") == 0) {
-       vp = yasm_vps_first(valparams);
-       if (vp->val) {
-           yasm_objfmt_global_declare(parser_nasm->objfmt, vp->val,
-                                      objext_valparams, line);
-       } else
-           yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid argument to [%s]"),
-                          "GLOBAL");
-    } else if (yasm__strcasecmp(name, "common") == 0) {
-       vp = yasm_vps_first(valparams);
-       if (vp->val) {
-           vp2 = yasm_vps_next(vp);
-           if (!vp2 || (!vp2->val && !vp2->param))
-               yasm_error_set(YASM_ERROR_SYNTAX,
-                              N_("no size specified in %s declaration"),
-                              "COMMON");
-           else {
-               if (vp2->val) {
-                   yasm_objfmt_common_declare(parser_nasm->objfmt, vp->val,
-                       p_expr_new_ident(yasm_expr_sym(
-                           yasm_symtab_use(p_symtab, vp2->val, line))),
-                       objext_valparams, line);
-               } else if (vp2->param) {
-                   yasm_objfmt_common_declare(parser_nasm->objfmt, vp->val,
-                                              vp2->param, objext_valparams,
-                                              line);
-                   vp2->param = NULL;
-               }
-           }
-       } else
-           yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid argument to [%s]"),
-                          "COMMON");
-    } else if (yasm__strcasecmp(name, "section") == 0 ||
-              yasm__strcasecmp(name, "segment") == 0) {
-       yasm_section *new_section =
-           yasm_objfmt_section_switch(parser_nasm->objfmt, valparams,
-                                      objext_valparams, line);
-       if (new_section) {
-           parser_nasm->cur_section = new_section;
-           parser_nasm->prev_bc = yasm_section_bcs_last(new_section);
-       } else
-           yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid argument to [%s]"),
-                          "SECTION");
-    } else if (yasm__strcasecmp(name, "absolute") == 0) {
-       /* it can be just an ID or a complete expression, so handle both. */
-       vp = yasm_vps_first(valparams);
-       if (vp->val)
-           parser_nasm->cur_section =
-               yasm_object_create_absolute(parser_nasm->object,
-                   p_expr_new_ident(yasm_expr_sym(
-                       yasm_symtab_use(p_symtab, vp->val, line))), line);
-       else if (vp->param) {
-           parser_nasm->cur_section =
-               yasm_object_create_absolute(parser_nasm->object, vp->param,
-                                           line);
-           vp->param = NULL;
-       }
-       parser_nasm->prev_bc = yasm_section_bcs_last(parser_nasm->cur_section);
-    } else if (yasm__strcasecmp(name, "align") == 0) {
-       /*@only@*/ yasm_expr *boundval;
-       /*@depedent@*/ yasm_intnum *boundintn;
-
-       /* it can be just an ID or a complete expression, so handle both. */
-       vp = yasm_vps_first(valparams);
-       if (vp->val)
-           boundval = p_expr_new_ident(yasm_expr_sym(
-               yasm_symtab_use(p_symtab, vp->val, line)));
-       else if (vp->param) {
-           boundval = vp->param;
-           vp->param = NULL;
-       }
-
-       /* Largest .align in the section specifies section alignment.
-        * Note: this doesn't match NASM behavior, but is a lot more
-        * intelligent!
-        */
-       boundintn = yasm_expr_get_intnum(&boundval, 0);
-       if (boundintn) {
-           unsigned long boundint = yasm_intnum_get_uint(boundintn);
-
-           /* Alignments must be a power of two. */
-           if (is_exp2(boundint)) {
-               if (boundint > yasm_section_get_align(parser_nasm->cur_section))
-                   yasm_section_set_align(parser_nasm->cur_section, boundint,
-                                          cur_line);
-           }
-       }
-
-       /* As this directive is called only when nop is used as fill, always
-        * use arch (nop) fill.
-        */
-       parser_nasm->prev_bc =
-           yasm_section_bcs_append(parser_nasm->cur_section,
-               yasm_bc_create_align(boundval, NULL, NULL,
-                   /*yasm_section_is_code(parser_nasm->cur_section) ?*/
-                       yasm_arch_get_fill(parser_nasm->arch)/* : NULL*/,
-                   cur_line));
-    } else if (yasm__strcasecmp(name, "cpu") == 0) {
-       yasm_vps_foreach(vp, valparams) {
-           if (vp->val)
-               yasm_arch_parse_cpu(parser_nasm->arch, vp->val,
-                                   strlen(vp->val));
-           else if (vp->param) {
-               const yasm_intnum *intcpu;
-               intcpu = yasm_expr_get_intnum(&vp->param, 0);
-               if (!intcpu)
-                   yasm_error_set(YASM_ERROR_SYNTAX,
-                                  N_("invalid argument to [%s]"), "CPU");
-               else {
-                   char strcpu[16];
-                   sprintf(strcpu, "%lu", yasm_intnum_get_uint(intcpu));
-                   yasm_arch_parse_cpu(parser_nasm->arch, strcpu,
-                                       strlen(strcpu));
-               }
-           }
-       }
-    } else if (!yasm_arch_parse_directive(parser_nasm->arch, name, valparams,
-                   objext_valparams, parser_nasm->object, line)) {
-       ;
-    } else if (!yasm_dbgfmt_directive(parser_nasm->dbgfmt, name,
-                                     parser_nasm->cur_section, valparams,
-                                     line)) {
-       ;
-    } else if (yasm_objfmt_directive(parser_nasm->objfmt, name, valparams,
-                                    objext_valparams, line)) {
-       yasm_error_set(YASM_ERROR_SYNTAX, N_("unrecognized directive [%s]"),
-                      name);
-    }
-
-    yasm_vps_delete(valparams);
-    if (objext_valparams)
-       yasm_vps_delete(objext_valparams);
-}
diff --git a/modules/parsers/nasm/nasm-defs.h b/modules/parsers/nasm/nasm-defs.h
deleted file mode 100644 (file)
index a4b6447..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/* $Id$
- * Variable name redefinitions for NASM-compatible parser
- *
- *  Copyright (C) 2001  Peter Johnson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-#define yy_create_buffer       nasm_parser__create_buffer
-#define yy_delete_buffer       nasm_parser__delete_buffer
-#define yy_init_buffer         nasm_parser__init_buffer
-#define yy_load_buffer_state   nasm_parser__load_buffer_state
-#define yy_switch_to_buffer    nasm_parser__switch_to_buffer
-#define yyact                  nasm_parser_act
-#define yyback                 nasm_parser_back
-#define yybgin                 nasm_parser_bgin
-#define yychar                 nasm_parser_char
-#define yychk                  nasm_parser_chk
-#define yycrank                        nasm_parser_crank
-#define yydebug                        nasm_parser_debug
-#define yydef                  nasm_parser_def
-#define yyerrflag              nasm_parser_errflag
-#define yyerror                        nasm_parser_error
-#define yyestate               nasm_parser_estate
-#define yyexca                 nasm_parser_exca
-#define yyextra                        nasm_parser_extra
-#define yyfnd                  nasm_parser_fnd
-#define yyin                   nasm_parser_in
-#define yyinput                        nasm_parser_input
-#define yyleng                 nasm_parser_leng
-#define yylex                  nasm_parser_lex
-#define yylineno               nasm_parser_lineno
-#define yylook                 nasm_parser_look
-#define yylsp                  nasm_parser_lsp
-#define yylstate               nasm_parser_lstate
-#define yylval                 nasm_parser_lval
-#define yymatch                        nasm_parser_match
-#define yymorfg                        nasm_parser_morfg
-#define yynerrs                        nasm_parser_nerrs
-#define yyolsp                 nasm_parser_olsp
-#define yyout                  nasm_parser_out
-#define yyoutput               nasm_parser_output
-#define yypact                 nasm_parser_pact
-#define yyparse                        nasm_parser_parse
-#define yypgo                  nasm_parser_pgo
-#define yyprevious             nasm_parser_previous
-#define yyps                   nasm_parser_ps
-#define yypv                   nasm_parser_pv
-#define yyr1                   nasm_parser_r1
-#define yyr2                   nasm_parser_r2
-#define yyreds                 nasm_parser_reds
-#define yyrestart              nasm_parser_restart
-#define yys                    nasm_parser_s
-#define yysbuf                 nasm_parser_sbuf
-#define yysptr                 nasm_parser_sptr
-#define yystate                        nasm_parser_state
-#define yysvec                 nasm_parser_svec
-#define yytchar                        nasm_parser_tchar
-#define yytext                 nasm_parser_text
-#define yytmp                  nasm_parser_tmp
-#define yytoks                 nasm_parser_toks
-#define yytop                  nasm_parser_top
-#define yyunput                        nasm_parser_unput
-#define yyv                    nasm_parser_v
-#define yyval                  nasm_parser_val
-#define yyvstop                        nasm_parser_vstop
-/*#define yywrap                       nasm_parser_wrap*/
diff --git a/modules/parsers/nasm/nasm-parse.c b/modules/parsers/nasm/nasm-parse.c
new file mode 100644 (file)
index 0000000..99e9feb
--- /dev/null
@@ -0,0 +1,1197 @@
+/*
+ * NASM-compatible parser
+ *
+ *  Copyright (C) 2001  Peter Johnson, Michael Urman
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <util.h>
+RCSID("$Id$");
+
+#define YASM_LIB_INTERNAL
+#define YASM_EXPR_INTERNAL
+#include <libyasm.h>
+
+#ifdef STDC_HEADERS
+# include <math.h>
+#endif
+
+#include "modules/parsers/nasm/nasm-parser.h"
+
+typedef enum {
+    NORM_EXPR,
+    DIR_EXPR,
+    DV_EXPR
+} expr_type;
+
+static yasm_bytecode *parse_line(yasm_parser_nasm *parser_nasm);
+static int parse_directive_valparams(yasm_parser_nasm *parser_nasm,
+                                    /*@out@*/ yasm_valparamhead *vps);
+static yasm_bytecode *parse_times(yasm_parser_nasm *parser_nasm);
+static yasm_bytecode *parse_exp(yasm_parser_nasm *parser_nasm);
+static yasm_bytecode *parse_instr(yasm_parser_nasm *parser_nasm);
+static yasm_insn_operand *parse_operand(yasm_parser_nasm *parser_nasm);
+static yasm_effaddr *parse_memaddr(yasm_parser_nasm *parser_nasm);
+static yasm_expr *parse_expr(yasm_parser_nasm *parser_nasm, expr_type type);
+static yasm_expr *parse_bexpr(yasm_parser_nasm *parser_nasm, expr_type type);
+static yasm_expr *parse_expr0(yasm_parser_nasm *parser_nasm, expr_type type);
+static yasm_expr *parse_expr1(yasm_parser_nasm *parser_nasm, expr_type type);
+static yasm_expr *parse_expr2(yasm_parser_nasm *parser_nasm, expr_type type);
+static yasm_expr *parse_expr3(yasm_parser_nasm *parser_nasm, expr_type type);
+static yasm_expr *parse_expr4(yasm_parser_nasm *parser_nasm, expr_type type);
+static yasm_expr *parse_expr5(yasm_parser_nasm *parser_nasm, expr_type type);
+static yasm_expr *parse_expr6(yasm_parser_nasm *parser_nasm, expr_type type);
+
+static void nasm_parser_directive
+    (yasm_parser_nasm *parser_nasm, const char *name,
+     yasm_valparamhead *valparams,
+     /*@null@*/ yasm_valparamhead *objext_valparams);
+static int fix_directive_symrec(/*@null@*/ yasm_expr__item *ei,
+                               /*@null@*/ void *d);
+static void define_label(yasm_parser_nasm *parser_nasm, /*@only@*/ char *name,
+                        int local);
+
+#define is_eol_tok(tok)        ((tok) == '\n' || (tok) == 0)
+#define is_eol()       is_eol_tok(curtok)
+
+#define get_next_token()    (curtok = nasm_parser_lex(&curval, parser_nasm))
+
+static void
+get_peek_token(yasm_parser_nasm *parser_nasm)
+{
+    char savech = parser_nasm->tokch;
+    if (parser_nasm->peek_token != NONE)
+       yasm_internal_error(N_("only can have one token of lookahead"));
+    parser_nasm->peek_token =
+       nasm_parser_lex(&parser_nasm->peek_tokval, parser_nasm);
+    parser_nasm->peek_tokch = parser_nasm->tokch;
+    parser_nasm->tokch = savech;
+}
+
+static void
+destroy_curtok_(yasm_parser_nasm *parser_nasm)
+{
+    if (curtok < 256)
+       ;
+    else switch ((enum tokentype)curtok) {
+       case INTNUM:
+           yasm_intnum_destroy(curval.intn);
+           break;
+       case FLTNUM:
+           yasm_floatnum_destroy(curval.flt);
+           break;
+       case DIRECTIVE_NAME:
+       case FILENAME:
+       case ID:
+       case LOCAL_ID:
+       case SPECIAL_ID:
+           yasm_xfree(curval.str_val);
+           break;
+       case STRING:
+           yasm_xfree(curval.str.contents);
+           break;
+       default:
+           break;
+    }
+    curtok = 0;            /* sanity */
+}
+#define destroy_curtok()    destroy_curtok_(parser_nasm)
+
+/* Eat all remaining tokens to EOL, discarding all of them.  If there's any
+ * intervening tokens, generates an error (junk at end of line).
+ */
+static void
+demand_eol_(yasm_parser_nasm *parser_nasm)
+{
+    size_t zero = 0;
+    char ch;
+
+    if (is_eol())
+       return;
+
+    yasm_error_set(YASM_ERROR_SYNTAX,
+       N_("junk at end of line, first unrecognized character is `%c'"),
+       parser_nasm->tokch);
+
+    do {
+       get_next_token();
+       destroy_curtok();
+    } while (!is_eol());
+}
+#define demand_eol() demand_eol_(parser_nasm)
+
+static int
+expect_(yasm_parser_nasm *parser_nasm, int token)
+{
+    static char strch[] = "expected ` '";
+    const char *str;
+
+    if (curtok == token)
+       return 1;
+
+    switch (token) {
+       case INTNUM:            str = "expected integer"; break;
+       case FLTNUM:            str = "expected floating point value"; break;
+       case DIRECTIVE_NAME:    str = "expected directive name"; break;
+       case FILENAME:          str = "expected filename"; break;
+       case STRING:            str = "expected string"; break;
+       case SIZE_OVERRIDE:     str = "expected size override"; break;
+       case DECLARE_DATA:      str = "expected DB/DW/etc."; break;
+       case RESERVE_SPACE:     str = "expected RESB/RESW/etc."; break;
+       case INCBIN:            str = "expected INCBIN"; break;
+       case EQU:               str = "expected EQU"; break;
+       case TIMES:             str = "expected TIMES"; break;
+       case SEG:               str = "expected SEG"; break;
+       case WRT:               str = "expected WRT"; break;
+       case NOSPLIT:           str = "expected NOSPLIT"; break;
+       case STRICT:            str = "expected STRICT"; break;
+       case INSN:              str = "expected instruction"; break;
+       case PREFIX:            str = "expected instruction prefix"; break;
+       case REG:               str = "expected register"; break;
+       case SEGREG:            str = "expected segment register"; break;
+       case TARGETMOD:         str = "expected target modifier"; break;
+       case LEFT_OP:           str = "expected <<"; break;
+       case RIGHT_OP:          str = "expected >>"; break;
+       case SIGNDIV:           str = "expected //"; break;
+       case SIGNMOD:           str = "expected %%"; break;
+       case START_SECTION_ID:  str = "expected $$"; break;
+       case ID:                str = "expected identifier"; break;
+       case LOCAL_ID:          str = "expected .identifier"; break;
+       case SPECIAL_ID:        str = "expected ..identifier"; break;
+       case LINE:              str = "expected %line"; break;
+       default:
+           strch[10] = token;
+           str = strch;
+           break;
+    }
+    yasm_error_set(YASM_ERROR_PARSE, str);
+    destroy_curtok();
+    return 0;
+}
+#define expect(token) expect_(parser_nasm, token)
+
+void
+nasm_parser_parse(yasm_parser_nasm *parser_nasm)
+{
+    while (get_next_token() != 0) {
+       yasm_bytecode *bc = NULL, *temp_bc;
+       
+       if (!is_eol()) {
+           bc = parse_line(parser_nasm);
+           demand_eol();
+       }
+
+       yasm_errwarn_propagate(parser_nasm->errwarns, cur_line);
+
+       temp_bc = yasm_section_bcs_append(parser_nasm->cur_section, bc);
+       if (temp_bc)
+           parser_nasm->prev_bc = temp_bc;
+       if (parser_nasm->save_input)
+           yasm_linemap_add_source(parser_nasm->linemap,
+               temp_bc,
+               (char *)parser_nasm->save_line[parser_nasm->save_last ^ 1]);
+       yasm_linemap_goto_next(parser_nasm->linemap);
+    }
+}
+
+/* All parse_* functions expect to be called with curtok being their first
+ * token.  They should return with curtok being the token *after* their
+ * information.
+ */
+
+static yasm_bytecode *
+parse_line(yasm_parser_nasm *parser_nasm)
+{
+    yasm_bytecode *bc;
+
+    switch (curtok) {
+       case LINE: /* LINE INTNUM '+' INTNUM FILENAME */
+       {
+           yasm_intnum *line, *incr;
+           char *filename;
+
+           get_next_token();
+
+           if (!expect(INTNUM)) return NULL;
+           line = INTNUM_val;
+           get_next_token();
+
+           if (!expect('+')) return NULL;
+           get_next_token();
+
+           if (!expect(INTNUM)) return NULL;
+           incr = INTNUM_val;
+           get_next_token();
+
+           if (!expect(FILENAME)) return NULL;
+           filename = FILENAME_val;
+           get_next_token();
+
+           /* %line indicates the line number of the *next* line, so subtract
+            * out the increment when setting the line number.
+            */
+           yasm_linemap_set(parser_nasm->linemap, filename,
+               yasm_intnum_get_uint(line) - yasm_intnum_get_uint(incr),
+               yasm_intnum_get_uint(incr));
+           yasm_intnum_destroy(line);
+           yasm_intnum_destroy(incr);
+           yasm_xfree(filename);
+           return NULL;
+       }
+       case '[': /* [ directive ] */
+       {
+           char *dirname;
+           yasm_valparamhead dir_vps;
+
+           parser_nasm->state = DIRECTIVE;
+           get_next_token();
+
+           if (!expect(DIRECTIVE_NAME))
+               return NULL;
+           dirname = DIRECTIVE_NAME_val;
+           get_next_token();
+
+           if (!parse_directive_valparams(parser_nasm, &dir_vps)) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("invalid arguments to [%s]"), dirname);
+               yasm_xfree(dirname);
+               return NULL;
+           }
+           if (curtok == ':') {
+               yasm_valparamhead ext_vps;
+               get_next_token();
+               if (!parse_directive_valparams(parser_nasm, &ext_vps)) {
+                   yasm_error_set(YASM_ERROR_SYNTAX,
+                                  N_("invalid arguments to [%s]"), dirname);
+                   yasm_xfree(dirname);
+                   return NULL;
+               }
+               nasm_parser_directive(parser_nasm, dirname, &dir_vps,
+                                     &ext_vps);
+           } else
+               nasm_parser_directive(parser_nasm, dirname, &dir_vps, NULL);
+           yasm_xfree(dirname);
+           expect(']');
+           get_next_token();
+           return NULL;
+       }
+       case TIMES: /* TIMES expr exp */
+           get_next_token();
+           return parse_times(parser_nasm);
+       case ID:
+       case SPECIAL_ID:
+       case LOCAL_ID:
+       {
+           char *name = ID_val;
+           int local = (curtok != ID);
+
+           get_next_token();
+           if (is_eol()) {
+               /* label alone on the line */
+               yasm_warn_set(YASM_WARN_ORPHAN_LABEL,
+                   N_("label alone on a line without a colon might be in error"));
+               define_label(parser_nasm, name, local);
+               return NULL;
+           }
+           if (curtok == ':')
+               get_next_token();
+
+           if (curtok == EQU) {
+               /* label EQU expr */
+               yasm_expr *e;
+               get_next_token();
+               e = parse_expr(parser_nasm, NORM_EXPR);
+               if (!e) {
+                   yasm_error_set(YASM_ERROR_SYNTAX,
+                                  N_("expression expected after %s"), "EQU");
+                   yasm_xfree(name);
+                   return NULL;
+               }
+               yasm_symtab_define_equ(p_symtab, name, e, cur_line);
+               yasm_xfree(name);
+               return NULL;
+           }
+
+           define_label(parser_nasm, name, local);
+           if (is_eol())
+               return NULL;
+           if (curtok == TIMES) {
+               get_next_token();
+               return parse_times(parser_nasm);
+           }
+           bc = parse_exp(parser_nasm);
+           if (!bc)
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("instruction expected after label"));
+           return bc;
+       }
+       default:
+           bc = parse_exp(parser_nasm);
+           if (!bc)
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                   N_("label or instruction expected at start of line"));
+           return bc;
+    }
+}
+
+static int
+parse_directive_valparams(yasm_parser_nasm *parser_nasm,
+                         /*@out@*/ yasm_valparamhead *vps)
+{
+    yasm_vps_initialize(vps);
+    for (;;) {
+       yasm_valparam *vp;
+       yasm_expr *e;
+
+       switch (curtok) {
+           case STRING:
+               vp = yasm_vp_create(STRING_val.contents, NULL);
+               get_next_token();
+               break;
+           case ID:
+           {
+               char *id = ID_val;
+               get_peek_token(parser_nasm);
+               if (parser_nasm->peek_token == '=') {
+                   get_next_token(); /* id */
+                   get_next_token(); /* = */
+                   e = parse_expr(parser_nasm, DIR_EXPR);
+                   if (!e) {
+                       yasm_vps_delete(vps);
+                       return 0;
+                   }
+                   yasm_expr__traverse_leaves_in(e, parser_nasm,
+                                                 fix_directive_symrec);
+                   vp = yasm_vp_create(id, e);
+                   break;
+               }
+               if (parser_nasm->peek_token == ','
+                   || parser_nasm->peek_token == ']'
+                   || parser_nasm->peek_token == ':') {
+                   /* Try to catch just IDs here first */
+                   get_next_token(); /* id */
+                   vp = yasm_vp_create(id, NULL);
+                   break;
+               }
+               /*@fallthrough@*/
+           }
+           default:
+           {
+               /* If direxpr is just an ID, put it in val and delete the expr.
+                * Otherwise, we need to go through the expr and replace the
+                * current (local) symrecs with the use of global ones.
+                */
+               const /*@null@*/ yasm_symrec *vp_symrec;
+               e = parse_expr(parser_nasm, DIR_EXPR);
+               if (!e) {
+                   yasm_vps_delete(vps);
+                   return 0;
+               }
+               if ((vp_symrec = yasm_expr_get_symrec(&e, 0))) {
+                   vp = yasm_vp_create(
+                       yasm__xstrdup(yasm_symrec_get_name(vp_symrec)), NULL);
+                   yasm_expr_destroy(e);
+               } else {
+                   yasm_expr__traverse_leaves_in(e, parser_nasm,
+                                                 fix_directive_symrec);
+                   vp = yasm_vp_create(NULL, e);
+               }
+           }
+       }
+
+       yasm_vps_append(vps, vp);
+       if (curtok == ',')
+           get_next_token();
+       if (curtok == ']' || curtok == ':' || is_eol())
+           return 1;
+    }
+}
+
+static yasm_bytecode *
+parse_times(yasm_parser_nasm *parser_nasm)
+{
+    yasm_expr *multiple;
+    yasm_bytecode *bc;
+
+    multiple = parse_expr(parser_nasm, DV_EXPR);
+    if (!multiple) {
+       yasm_error_set(YASM_ERROR_SYNTAX, N_("expression expected after %s"),
+                      "TIMES");
+       return NULL;
+    }
+    bc = parse_exp(parser_nasm);
+    if (!bc) {
+       yasm_error_set(YASM_ERROR_SYNTAX,
+                      N_("instruction expected after TIMES expression"));
+       yasm_expr_destroy(multiple);
+       return NULL;
+    }
+    yasm_bc_set_multiple(bc, multiple);
+    return bc;
+}
+
+static yasm_bytecode *
+parse_exp(yasm_parser_nasm *parser_nasm)
+{
+    switch (curtok) {
+       case DECLARE_DATA:
+       {
+           unsigned int size = DECLARE_DATA_val/8;
+           yasm_datavalhead dvs;
+           yasm_dataval *dv;
+           yasm_expr *e;
+
+           get_next_token();
+
+           yasm_dvs_initialize(&dvs);
+           for (;;) {
+               if (curtok == STRING) {
+                   /* Peek ahead to see if we're in an expr.  If we're not,
+                    * then generate a real string dataval.
+                    */
+                   get_peek_token(parser_nasm);
+                   if (parser_nasm->peek_token == ','
+                       || is_eol_tok(parser_nasm->peek_token)) {
+                       dv = yasm_dv_create_string(STRING_val.contents,
+                                                  STRING_val.len);
+                       get_next_token();
+                       goto dv_done;
+                   }
+               }
+               if ((e = parse_expr(parser_nasm, DV_EXPR)))
+                   dv = yasm_dv_create_expr(e);
+               else {
+                   yasm_error_set(YASM_ERROR_SYNTAX,
+                                  N_("expression or string expected"));
+                   yasm_dvs_delete(&dvs);
+                   return NULL;
+               }
+dv_done:
+               yasm_dvs_append(&dvs, dv);
+               if (is_eol())
+                   break;
+               if (!expect(',')) {
+                   yasm_dvs_delete(&dvs);
+                   return NULL;
+               }
+               get_next_token();
+               if (is_eol())   /* allow trailing , on list */
+                   break;
+           }
+           return yasm_bc_create_data(&dvs, size, 0, parser_nasm->arch,
+                                      cur_line);
+       }
+       case RESERVE_SPACE:
+       {
+           unsigned int size = RESERVE_SPACE_val/8;
+           yasm_expr *e;
+           get_next_token();
+           e = parse_expr(parser_nasm, DV_EXPR);
+           if (!e) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("expression expected after %s"), "RESx");
+               return NULL;
+           }
+           return yasm_bc_create_reserve(e, size, cur_line);
+       }
+       case INCBIN:
+       {
+           char *filename;
+           yasm_expr *start = NULL, *maxlen = NULL;
+
+           get_next_token();
+
+           if (!expect(STRING)) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("filename string expected after INCBIN"));
+               return NULL;
+           }
+           filename = STRING_val.contents;
+           get_next_token();
+
+           /* optional start expression */
+           if (curtok == ',')
+               get_next_token();
+           if (is_eol())
+               goto incbin_done;
+           start = parse_expr(parser_nasm, DV_EXPR);
+           if (!start) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("expression expected for INCBIN start"));
+               return NULL;
+           }
+
+           /* optional maxlen expression */
+           if (curtok == ',')
+               get_next_token();
+           if (is_eol())
+               goto incbin_done;
+           maxlen = parse_expr(parser_nasm, DV_EXPR);
+           if (!start) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                   N_("expression expected for INCBIN maximum length"));
+               return NULL;
+           }
+
+incbin_done:
+           return yasm_bc_create_incbin(filename, start, maxlen,
+                                        parser_nasm->linemap, cur_line);
+       }
+       default:
+           return parse_instr(parser_nasm);
+    }
+}
+
+static yasm_bytecode *
+parse_instr(yasm_parser_nasm *parser_nasm)
+{
+    switch (curtok) {
+       case INSN:
+       {
+           yystype insn = curval;      /* structure copy */
+           yasm_insn_operands operands;
+           int num_operands = 0;
+
+           get_next_token();
+           if (is_eol()) {
+               /* no operands */
+               return yasm_bc_create_insn(parser_nasm->arch, insn.arch_data,
+                                          0, NULL, cur_line);
+           }
+
+           /* parse operands */
+           yasm_ops_initialize(&operands);
+           for (;;) {
+               yasm_insn_operand *op = parse_operand(parser_nasm);
+               if (!op) {
+                   yasm_error_set(YASM_ERROR_SYNTAX,
+                                  N_("expression syntax error"));
+                   yasm_ops_delete(&operands, 1);
+                   return NULL;
+               }
+               yasm_ops_append(&operands, op);
+               num_operands++;
+
+               if (is_eol())
+                   break;
+               if (!expect(',')) {
+                   yasm_ops_delete(&operands, 1);
+                   return NULL;
+               }
+               get_next_token();
+           }
+           return yasm_bc_create_insn(parser_nasm->arch, insn.arch_data,
+                                      num_operands, &operands, cur_line);
+       }
+       case PREFIX: {
+           yystype prefix = curval;    /* structure copy */
+           yasm_bytecode *bc;
+           get_next_token();
+           bc = parse_instr(parser_nasm);
+           if (bc)
+               yasm_bc_insn_add_prefix(bc, prefix.arch_data);
+           return bc;
+       }
+       case SEGREG: {
+           unsigned long segreg = SEGREG_val[0];
+           yasm_bytecode *bc;
+           get_next_token();
+           bc = parse_instr(parser_nasm);
+           if (bc)
+               yasm_bc_insn_add_seg_prefix(bc, segreg);
+           return bc;
+       }
+       default:
+           return NULL;
+    }
+}
+
+static yasm_insn_operand *
+parse_operand(yasm_parser_nasm *parser_nasm)
+{
+    yasm_insn_operand *op;
+    switch (curtok) {
+       case '[':
+       {
+           yasm_effaddr *ea;
+           get_next_token();
+           ea = parse_memaddr(parser_nasm);
+
+           expect(']');
+           get_next_token();
+
+           if (!ea) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("memory address expected"));
+               return NULL;
+           }
+           return yasm_operand_create_mem(ea);
+       }
+       case SEGREG:
+           op = yasm_operand_create_segreg(SEGREG_val[0]);
+           get_next_token();
+           return op;
+       case REG:
+           op = yasm_operand_create_reg(REG_val[0]);
+           get_next_token();
+           return op;
+       case STRICT:
+           get_next_token();
+           op = parse_operand(parser_nasm);
+           if (op)
+               op->strict = 1;
+           return op;
+       case SIZE_OVERRIDE:
+       {
+           unsigned int size = SIZE_OVERRIDE_val;
+           get_next_token();
+           op = parse_operand(parser_nasm);
+           if (!op)
+               return NULL;
+           if (op->type == YASM_INSN__OPERAND_REG &&
+               yasm_arch_get_reg_size(parser_nasm->arch, op->data.reg) != size)
+               yasm_error_set(YASM_ERROR_TYPE,
+                              N_("cannot override register size"));
+           else
+               op->size = size;
+           return op;
+       }
+       case TARGETMOD:
+       {
+           unsigned long tmod = TARGETMOD_val[0];
+           get_next_token();
+           op = parse_operand(parser_nasm);
+           if (op)
+               op->targetmod = tmod;
+           return op;
+       }
+       default:
+       {
+           yasm_expr *e = parse_expr(parser_nasm, NORM_EXPR);
+           if (!e)
+               return NULL;
+           return yasm_operand_create_imm(e);
+       }
+    }
+}
+
+/* memory addresses */
+static yasm_effaddr *
+parse_memaddr(yasm_parser_nasm *parser_nasm)
+{
+    yasm_effaddr *ea;
+    switch (curtok) {
+       case SEGREG:
+       {
+           unsigned long segreg = SEGREG_val[0];
+           get_next_token();
+           if (!expect(':')) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("`:' required after segment register"));
+               return NULL;
+           }
+           get_next_token();
+           ea = parse_memaddr(parser_nasm);
+           if (ea)
+               yasm_ea_set_segreg(ea, segreg);
+           return ea;
+       }
+       case SIZE_OVERRIDE:
+       {
+           unsigned int size = SIZE_OVERRIDE_val;
+           get_next_token();
+           ea = parse_memaddr(parser_nasm);
+           if (ea)
+               yasm_ea_set_len(ea, size);
+           return ea;
+       }
+       case NOSPLIT:
+           get_next_token();
+           ea = parse_memaddr(parser_nasm);
+           if (ea)
+               yasm_ea_set_nosplit(ea, 1);
+           return ea;
+       default:
+       {
+           yasm_expr *e = parse_expr(parser_nasm, NORM_EXPR);
+           if (!e)
+               return NULL;
+           return yasm_arch_ea_create(parser_nasm->arch, e);
+       }
+    }
+}
+
+/* Expression grammar parsed is:
+ *
+ * expr  : bexpr [ : bexpr ]
+ * bexpr : expr0 [ WRT expr6 ]
+ * expr0 : expr1 [ {|} expr1...]
+ * expr1 : expr2 [ {^} expr2...]
+ * expr2 : expr3 [ {&} expr3...]
+ * expr3 : expr4 [ {<<,>>} expr4...]
+ * expr4 : expr5 [ {+,-} expr5...]
+ * expr5 : expr6 [ {*,/,%,//,%%} expr6...]
+ * expr6 : { ~,+,-,SEG } expr6
+ *       | (expr)
+ *       | symbol
+ *       | $
+ *       | number
+ */
+
+#define parse_expr_common(leftfunc, tok, rightfunc, op) \
+    do {                                               \
+       yasm_expr *e, *f;                               \
+       e = leftfunc(parser_nasm, type);                \
+       if (!e)                                         \
+           return NULL;                                \
+                                                       \
+       while (curtok == tok) {                         \
+           get_next_token();                           \
+           f = rightfunc(parser_nasm, type);           \
+           if (!f) {                                   \
+               yasm_expr_destroy(e);                   \
+               return NULL;                            \
+           }                                           \
+           e = p_expr_new_tree(e, op, f);              \
+       }                                               \
+       return e;                                       \
+    } while(0)
+
+static yasm_expr *
+parse_expr(yasm_parser_nasm *parser_nasm, expr_type type)
+{
+    switch (type) {
+       case NORM_EXPR:
+           parse_expr_common(parse_bexpr, ':', parse_bexpr, YASM_EXPR_SEGOFF);
+       case DV_EXPR:
+           /* dataval expressions can't handle seg:off */
+           return parse_bexpr(parser_nasm, type);
+       case DIR_EXPR:
+           /* directive expressions can't handle seg:off or WRT */
+           return parse_expr0(parser_nasm, type);
+    }
+    /*@notreached@*/
+    return NULL;
+}
+
+static yasm_expr *
+parse_bexpr(yasm_parser_nasm *parser_nasm, expr_type type)
+{
+    parse_expr_common(parse_expr0, WRT, parse_expr6, YASM_EXPR_WRT);
+}
+
+static yasm_expr *
+parse_expr0(yasm_parser_nasm *parser_nasm, expr_type type)
+{
+    parse_expr_common(parse_expr1, '|', parse_expr1, YASM_EXPR_OR);
+}
+
+static yasm_expr *
+parse_expr1(yasm_parser_nasm *parser_nasm, expr_type type)
+{
+    parse_expr_common(parse_expr2, '^', parse_expr2, YASM_EXPR_XOR);
+}
+
+static yasm_expr *
+parse_expr2(yasm_parser_nasm *parser_nasm, expr_type type)
+{
+    parse_expr_common(parse_expr3, '&', parse_expr3, YASM_EXPR_AND);
+}
+
+static yasm_expr *
+parse_expr3(yasm_parser_nasm *parser_nasm, expr_type type)
+{
+    yasm_expr *e, *f;
+    e = parse_expr4(parser_nasm, type);
+    if (!e)
+       return NULL;
+
+    while (curtok == LEFT_OP || curtok == RIGHT_OP) {
+       int op = curtok;
+       get_next_token();
+       f = parse_expr4(parser_nasm, type);
+       if (!f) {
+           yasm_expr_destroy(e);
+           return NULL;
+       }
+
+       switch (op) {
+           case LEFT_OP: e = p_expr_new_tree(e, YASM_EXPR_SHL, f); break;
+           case RIGHT_OP: e = p_expr_new_tree(e, YASM_EXPR_SHR, f); break;
+       }
+    }
+    return e;
+}
+
+static yasm_expr *
+parse_expr4(yasm_parser_nasm *parser_nasm, expr_type type)
+{
+    yasm_expr *e, *f;
+    e = parse_expr5(parser_nasm, type);
+    if (!e)
+       return NULL;
+
+    while (curtok == '+' || curtok == '-') {
+       int op = curtok;
+       get_next_token();
+       f = parse_expr5(parser_nasm, type);
+       if (!f) {
+           yasm_expr_destroy(e);
+           return NULL;
+       }
+
+       switch (op) {
+           case '+': e = p_expr_new_tree(e, YASM_EXPR_ADD, f); break;
+           case '-': e = p_expr_new_tree(e, YASM_EXPR_SUB, f); break;
+       }
+    }
+    return e;
+}
+
+static yasm_expr *
+parse_expr5(yasm_parser_nasm *parser_nasm, expr_type type)
+{
+    yasm_expr *e, *f;
+    e = parse_expr6(parser_nasm, type);
+    if (!e)
+       return NULL;
+
+    while (curtok == '*' || curtok == '/' || curtok == '%'
+          || curtok == SIGNDIV || curtok == SIGNMOD) {
+       int op = curtok;
+       get_next_token();
+       f = parse_expr6(parser_nasm, type);
+       if (!f) {
+           yasm_expr_destroy(e);
+           return NULL;
+       }
+
+       switch (op) {
+           case '*': e = p_expr_new_tree(e, YASM_EXPR_MUL, f); break;
+           case '/': e = p_expr_new_tree(e, YASM_EXPR_DIV, f); break;
+           case '%': e = p_expr_new_tree(e, YASM_EXPR_MOD, f); break;
+           case SIGNDIV: e = p_expr_new_tree(e, YASM_EXPR_SIGNDIV, f); break;
+           case SIGNMOD: e = p_expr_new_tree(e, YASM_EXPR_SIGNMOD, f); break;
+       }
+    }
+    return e;
+}
+
+static yasm_expr *
+parse_expr6(yasm_parser_nasm *parser_nasm, expr_type type)
+{
+    yasm_expr *e;
+    yasm_symrec *sym;
+
+    /* directives allow very little and handle IDs specially */
+    if (type == DIR_EXPR) {
+       switch (curtok) {
+       case '~':
+           get_next_token();
+           e = parse_expr6(parser_nasm, type);
+           if (!e)
+               return NULL;
+           return p_expr_new_branch(YASM_EXPR_NOT, e);
+       case '(':
+           get_next_token();
+           e = parse_expr(parser_nasm, type);
+           if (!e)
+               return NULL;
+           if (!expect(')')) {
+               yasm_error_set(YASM_ERROR_SYNTAX, N_("missing parenthesis"));
+               return NULL;
+           }
+           get_next_token();
+           return e;
+       case INTNUM:
+           e = p_expr_new_ident(yasm_expr_int(INTNUM_val));
+           break;
+       case ID:
+           e = p_expr_new_ident(yasm_expr_sym(
+               yasm_symtab_define_label(p_symtab, ID_val,
+                   yasm_section_bcs_first(parser_nasm->cur_section), 0,
+                   cur_line)));
+           yasm_xfree(ID_val);
+           break;
+       default:
+           return NULL;
+       }
+    } else switch (curtok) {
+       case '+':
+           get_next_token();
+           return parse_expr6(parser_nasm, type);
+       case '-':
+           get_next_token();
+           e = parse_expr6(parser_nasm, type);
+           if (!e)
+               return NULL;
+           return p_expr_new_branch(YASM_EXPR_NEG, e);
+       case '~':
+           get_next_token();
+           e = parse_expr6(parser_nasm, type);
+           if (!e)
+               return NULL;
+           return p_expr_new_branch(YASM_EXPR_NOT, e);
+       case SEG:
+           get_next_token();
+           e = parse_expr6(parser_nasm, type);
+           if (!e)
+               return NULL;
+           return p_expr_new_branch(YASM_EXPR_SEG, e);
+       case '(':
+           get_next_token();
+           e = parse_expr(parser_nasm, type);
+           if (!e)
+               return NULL;
+           if (!expect(')')) {
+               yasm_error_set(YASM_ERROR_SYNTAX, N_("missing parenthesis"));
+               return NULL;
+           }
+           get_next_token();
+           return e;
+       case INTNUM:
+           e = p_expr_new_ident(yasm_expr_int(INTNUM_val));
+           break;
+       case FLTNUM:
+           e = p_expr_new_ident(yasm_expr_float(FLTNUM_val));
+           break;
+       case REG:
+           if (type == DV_EXPR) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("data values can't have registers"));
+               return NULL;
+           }
+           e = p_expr_new_ident(yasm_expr_reg(REG_val[0]));
+           break;
+       case STRING:
+           e = p_expr_new_ident(yasm_expr_int(
+               yasm_intnum_create_charconst_nasm(STRING_val.contents)));
+           yasm_xfree(STRING_val.contents);
+           break;
+       case ID:
+       case SPECIAL_ID:
+       case LOCAL_ID:
+           sym = yasm_symtab_use(p_symtab, ID_val, cur_line);
+           e = p_expr_new_ident(yasm_expr_sym(sym));
+           yasm_xfree(ID_val);
+           break;
+       case '$':
+           /* "$" references the current assembly position */
+           sym = yasm_symtab_define_curpos(p_symtab, "$",
+                                           parser_nasm->prev_bc, cur_line);
+           e = p_expr_new_ident(yasm_expr_sym(sym));
+           break;
+       case START_SECTION_ID:
+           /* "$$" references the start of the current section */
+           sym = yasm_symtab_define_label(p_symtab, "$$",
+               yasm_section_bcs_first(parser_nasm->cur_section), 0, cur_line);
+           e = p_expr_new_ident(yasm_expr_sym(sym));
+           break;
+       default:
+           return NULL;
+    }
+    get_next_token();
+    return e;
+}
+
+static void
+define_label(yasm_parser_nasm *parser_nasm, char *name, int local)
+{
+    if (!local) {
+       if (parser_nasm->locallabel_base)
+           yasm_xfree(parser_nasm->locallabel_base);
+       parser_nasm->locallabel_base_len = strlen(name);
+       parser_nasm->locallabel_base =
+           yasm_xmalloc(parser_nasm->locallabel_base_len+1);
+       strcpy(parser_nasm->locallabel_base, name);
+    }
+
+    yasm_symtab_define_label(p_symtab, name, parser_nasm->prev_bc, 1,
+                            cur_line);
+    yasm_xfree(name);
+}
+
+static int
+fix_directive_symrec(yasm_expr__item *ei, void *d)
+{
+    yasm_parser_nasm *parser_nasm = (yasm_parser_nasm *)d;
+    if (!ei || ei->type != YASM_EXPR_SYM)
+       return 0;
+
+    /* FIXME: Delete current symrec */
+    ei->data.sym =
+       yasm_symtab_use(p_symtab, yasm_symrec_get_name(ei->data.sym),
+                       cur_line);
+
+    return 0;
+}
+
+static void
+nasm_parser_directive(yasm_parser_nasm *parser_nasm, const char *name,
+                     yasm_valparamhead *valparams,
+                     yasm_valparamhead *objext_valparams)
+{
+    yasm_valparam *vp, *vp2;
+    unsigned long line = cur_line;
+
+    /* Handle (mostly) output-format independent directives here */
+    if (yasm__strcasecmp(name, "extern") == 0) {
+       vp = yasm_vps_first(valparams);
+       if (vp->val) {
+           yasm_objfmt_extern_declare(parser_nasm->objfmt, vp->val,
+                                      objext_valparams, line);
+       } else
+           yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid argument to [%s]"),
+                          "EXTERN");
+    } else if (yasm__strcasecmp(name, "global") == 0) {
+       vp = yasm_vps_first(valparams);
+       if (vp->val) {
+           yasm_objfmt_global_declare(parser_nasm->objfmt, vp->val,
+                                      objext_valparams, line);
+       } else
+           yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid argument to [%s]"),
+                          "GLOBAL");
+    } else if (yasm__strcasecmp(name, "common") == 0) {
+       vp = yasm_vps_first(valparams);
+       if (vp->val) {
+           vp2 = yasm_vps_next(vp);
+           if (!vp2 || (!vp2->val && !vp2->param))
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("no size specified in %s declaration"),
+                              "COMMON");
+           else {
+               if (vp2->val) {
+                   yasm_objfmt_common_declare(parser_nasm->objfmt, vp->val,
+                       p_expr_new_ident(yasm_expr_sym(
+                           yasm_symtab_use(p_symtab, vp2->val, line))),
+                       objext_valparams, line);
+               } else if (vp2->param) {
+                   yasm_objfmt_common_declare(parser_nasm->objfmt, vp->val,
+                                              vp2->param, objext_valparams,
+                                              line);
+                   vp2->param = NULL;
+               }
+           }
+       } else
+           yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid argument to [%s]"),
+                          "COMMON");
+    } else if (yasm__strcasecmp(name, "section") == 0 ||
+              yasm__strcasecmp(name, "segment") == 0) {
+       yasm_section *new_section =
+           yasm_objfmt_section_switch(parser_nasm->objfmt, valparams,
+                                      objext_valparams, line);
+       if (new_section) {
+           parser_nasm->cur_section = new_section;
+           parser_nasm->prev_bc = yasm_section_bcs_last(new_section);
+       } else
+           yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid argument to [%s]"),
+                          "SECTION");
+    } else if (yasm__strcasecmp(name, "absolute") == 0) {
+       /* it can be just an ID or a complete expression, so handle both. */
+       vp = yasm_vps_first(valparams);
+       if (vp->val)
+           parser_nasm->cur_section =
+               yasm_object_create_absolute(parser_nasm->object,
+                   p_expr_new_ident(yasm_expr_sym(
+                       yasm_symtab_use(p_symtab, vp->val, line))), line);
+       else if (vp->param) {
+           parser_nasm->cur_section =
+               yasm_object_create_absolute(parser_nasm->object, vp->param,
+                                           line);
+           vp->param = NULL;
+       }
+       parser_nasm->prev_bc = yasm_section_bcs_last(parser_nasm->cur_section);
+    } else if (yasm__strcasecmp(name, "align") == 0) {
+       /*@only@*/ yasm_expr *boundval;
+       /*@depedent@*/ yasm_intnum *boundintn;
+
+       /* it can be just an ID or a complete expression, so handle both. */
+       vp = yasm_vps_first(valparams);
+       if (vp->val)
+           boundval = p_expr_new_ident(yasm_expr_sym(
+               yasm_symtab_use(p_symtab, vp->val, line)));
+       else if (vp->param) {
+           boundval = vp->param;
+           vp->param = NULL;
+       }
+
+       /* Largest .align in the section specifies section alignment.
+        * Note: this doesn't match NASM behavior, but is a lot more
+        * intelligent!
+        */
+       boundintn = yasm_expr_get_intnum(&boundval, 0);
+       if (boundintn) {
+           unsigned long boundint = yasm_intnum_get_uint(boundintn);
+
+           /* Alignments must be a power of two. */
+           if (is_exp2(boundint)) {
+               if (boundint > yasm_section_get_align(parser_nasm->cur_section))
+                   yasm_section_set_align(parser_nasm->cur_section, boundint,
+                                          cur_line);
+           }
+       }
+
+       /* As this directive is called only when nop is used as fill, always
+        * use arch (nop) fill.
+        */
+       parser_nasm->prev_bc =
+           yasm_section_bcs_append(parser_nasm->cur_section,
+               yasm_bc_create_align(boundval, NULL, NULL,
+                   /*yasm_section_is_code(parser_nasm->cur_section) ?*/
+                       yasm_arch_get_fill(parser_nasm->arch)/* : NULL*/,
+                   cur_line));
+    } else if (yasm__strcasecmp(name, "cpu") == 0) {
+       yasm_vps_foreach(vp, valparams) {
+           if (vp->val)
+               yasm_arch_parse_cpu(parser_nasm->arch, vp->val,
+                                   strlen(vp->val));
+           else if (vp->param) {
+               const yasm_intnum *intcpu;
+               intcpu = yasm_expr_get_intnum(&vp->param, 0);
+               if (!intcpu)
+                   yasm_error_set(YASM_ERROR_SYNTAX,
+                                  N_("invalid argument to [%s]"), "CPU");
+               else {
+                   char strcpu[16];
+                   sprintf(strcpu, "%lu", yasm_intnum_get_uint(intcpu));
+                   yasm_arch_parse_cpu(parser_nasm->arch, strcpu,
+                                       strlen(strcpu));
+               }
+           }
+       }
+    } else if (!yasm_arch_parse_directive(parser_nasm->arch, name, valparams,
+                   objext_valparams, parser_nasm->object, line)) {
+       ;
+    } else if (!yasm_dbgfmt_directive(parser_nasm->dbgfmt, name,
+                                     parser_nasm->cur_section, valparams,
+                                     line)) {
+       ;
+    } else if (yasm_objfmt_directive(parser_nasm->objfmt, name, valparams,
+                                    objext_valparams, line)) {
+       yasm_error_set(YASM_ERROR_SYNTAX, N_("unrecognized directive [%s]"),
+                      name);
+    }
+
+    yasm_vps_delete(valparams);
+    if (objext_valparams)
+       yasm_vps_delete(objext_valparams);
+}
index 22387720c8c6920d04227faf1adf3254e23b184d..a5173bd56a6dd08152c1c71fc607526f9edcd5fa 100644 (file)
@@ -62,6 +62,8 @@ nasm_parser_do_parse(yasm_object *object, yasm_preproc *pp, yasm_arch *a,
     parser_nasm.save_input = save_input;
     parser_nasm.save_last = 0;
 
+    parser_nasm.peek_token = NONE;
+
     /* initialize scanner structure */
     yasm_scanner_initialize(&parser_nasm.s);
 
index 4b569553900ac6a58ab2be0749a2672c1042b941..d5d975addad498cb797b875285811abd9c9bcd1a 100644 (file)
 #ifndef YASM_NASM_PARSER_H
 #define YASM_NASM_PARSER_H
 
-#include "nasm-bison.h"
-
 #define YYCTYPE                unsigned char
 
 #define MAX_SAVED_LINE_LEN  80
 
+enum tokentype {
+    INTNUM = 258,
+    FLTNUM,
+    DIRECTIVE_NAME,
+    FILENAME,
+    STRING,
+    SIZE_OVERRIDE,
+    DECLARE_DATA,
+    RESERVE_SPACE,
+    INCBIN,
+    EQU,
+    TIMES,
+    SEG,
+    WRT,
+    NOSPLIT,
+    STRICT,
+    INSN,
+    PREFIX,
+    REG,
+    SEGREG,
+    TARGETMOD,
+    LEFT_OP,
+    RIGHT_OP,
+    SIGNDIV,
+    SIGNMOD,
+    START_SECTION_ID,
+    ID,
+    LOCAL_ID,
+    SPECIAL_ID,
+    LINE,
+    NONE               /* special token for lookahead */
+};
+
+typedef union {
+    unsigned int int_info;
+    char *str_val;
+    yasm_intnum *intn;
+    yasm_floatnum *flt;
+    unsigned long arch_data[4];
+    struct {
+       char *contents;
+       size_t len;
+    } str;
+} yystype;
+#define YYSTYPE yystype
+
 typedef struct yasm_parser_nasm {
     FILE *in;
     int debug;
@@ -54,7 +98,6 @@ typedef struct yasm_parser_nasm {
     /*@dependent@*/ yasm_symtab *symtab;
 
     /*@null@*/ yasm_bytecode *prev_bc;
-    yasm_bytecode *temp_bc;
 
     int save_input;
     YYCTYPE save_line[2][MAX_SAVED_LINE_LEN];
@@ -69,10 +112,36 @@ typedef struct yasm_parser_nasm {
        LINECHG2,
        INSTRUCTION
     } state;
+
+    int token;         /* enum tokentype or any character */
+    yystype tokval;
+    char tokch;                /* first character of token */
+
+    /* one token of lookahead; used sparingly */
+    int peek_token;    /* NONE if none */
+    yystype peek_tokval;
+    char peek_tokch;
 } yasm_parser_nasm;
 
 /* shorter access names to commonly used parser_nasm fields */
 #define p_symtab       (parser_nasm->symtab)
+#define curtok         (parser_nasm->token)
+#define curval         (parser_nasm->tokval)
+
+#define INTNUM_val             (curval.intn)
+#define FLTNUM_val             (curval.flt)
+#define DIRECTIVE_NAME_val     (curval.str_val)
+#define FILENAME_val           (curval.str_val)
+#define STRING_val             (curval.str)
+#define SIZE_OVERRIDE_val      (curval.int_info)
+#define DECLARE_DATA_val       (curval.int_info)
+#define RESERVE_SPACE_val      (curval.int_info)
+#define INSN_val               (curval.arch_data)
+#define PREFIX_val             (curval.arch_data)
+#define REG_val                        (curval.arch_data)
+#define SEGREG_val             (curval.arch_data)
+#define TARGETMOD_val          (curval.arch_data)
+#define ID_val                 (curval.str_val)
 
 #define cur_line       (yasm_linemap_get_current(parser_nasm->linemap))
 
@@ -80,7 +149,7 @@ typedef struct yasm_parser_nasm {
 #define p_expr_new_branch(o,r) yasm_expr_create_branch(o,r,cur_line)
 #define p_expr_new_ident(r)    yasm_expr_create_ident(r,cur_line)
 
-int nasm_parser_parse(void *parser_nasm_arg);
+void nasm_parser_parse(yasm_parser_nasm *parser_nasm);
 void nasm_parser_cleanup(yasm_parser_nasm *parser_nasm);
 int nasm_parser_lex(YYSTYPE *lvalp, yasm_parser_nasm *parser_nasm);
 
index 060b0bbb04bde20315e876abeace5b67eb2e4927..58d762b068ffd51e94da80a56c9f1cdd0d024beb 100644 (file)
@@ -33,7 +33,6 @@ RCSID("$Id$");
 #include <libyasm.h>
 
 #include "modules/parsers/nasm/nasm-parser.h"
-#include "modules/parsers/nasm/nasm-defs.h"
 
 
 #define BSIZE  8192
@@ -43,7 +42,8 @@ RCSID("$Id$");
 #define YYMARKER       (s->ptr)
 #define YYFILL(n)      {fill(parser_nasm, &cursor);}
 
-#define RETURN(i)      {s->cur = cursor; return i;}
+#define RETURN(i)      {s->cur = cursor; parser_nasm->tokch = s->tok[0]; \
+                        return i;}
 
 #define SCANINIT()     {s->tok = cursor;}
 
@@ -125,6 +125,15 @@ nasm_parser_lex(YYSTYPE *lvalp, yasm_parser_nasm *parser_nasm)
     size_t count, len;
     YYCTYPE savech;
 
+    /* Handle one token of lookahead */
+    if (parser_nasm->peek_token != NONE) {
+       int tok = parser_nasm->peek_token;
+       *lvalp = parser_nasm->peek_tokval;  /* structure copy */
+       parser_nasm->tokch = parser_nasm->peek_tokch;
+       parser_nasm->peek_token = NONE;
+       return tok;
+    }
+
     /* Catch EOF */
     if (s->eof && cursor == s->eof)
        return 0;
@@ -593,8 +602,6 @@ stringconst_scan:
            lvalp->str.len = count;
            if (parser_nasm->save_input)
                cursor = save_line(parser_nasm, cursor);
-           if (count == 1)
-               RETURN(ONECHARSTR);
            RETURN(STRING);
        }
 
@@ -603,8 +610,6 @@ stringconst_scan:
                strbuf[count] = '\0';
                lvalp->str.contents = (char *)strbuf;
                lvalp->str.len = count;
-               if (count == 1)
-                   RETURN(ONECHARSTR);
                RETURN(STRING);
            }