]> granicus.if.org Git - yasm/commitdiff
GAS parser: convert to recursive descent.
authorPeter Johnson <peter@tortall.net>
Sat, 30 Dec 2006 03:19:24 +0000 (03:19 -0000)
committerPeter Johnson <peter@tortall.net>
Sat, 30 Dec 2006 03:19:24 +0000 (03:19 -0000)
Remove all Bison supporting struts as we no longer need Bison.

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

18 files changed:
Makefile.am
Mkfiles/Makefile.dj
Mkfiles/Makefile.flat
Mkfiles/vc/modules/modules.vcproj
Mkfiles/vc8/bison.rules [deleted file]
Mkfiles/vc8/modules/modules.vcproj
Mkfiles/vc8/re2c/re2c.vcproj
Mkfiles/vc8/readme.vc8.txt
config/ylwrap [deleted file]
configure.ac
modules/parsers/gas/Makefile.inc
modules/parsers/gas/gas-bison.y [deleted file]
modules/parsers/gas/gas-defs.h [deleted file]
modules/parsers/gas/gas-parse.c [new file with mode: 0644]
modules/parsers/gas/gas-parser.c
modules/parsers/gas/gas-parser.h
modules/parsers/gas/gas-token.re
po/POTFILES.in

index 96afe83130835db08a547cbcc6515aecb0790d15..40c833813e58a99baba966a9466013ddd8f5700d 100644 (file)
@@ -75,7 +75,6 @@ EXTRA_DIST += Mkfiles/vc/re2c/re2c.vcproj
 EXTRA_DIST += Mkfiles/vc/re2c/run.bat
 EXTRA_DIST += Mkfiles/vc/gap/gap.vcproj
 EXTRA_DIST += Mkfiles/vc/gap/run.bat
-EXTRA_DIST += Mkfiles/vc8/bison.rules
 EXTRA_DIST += Mkfiles/vc8/crt_secure_no_deprecate.vsprops
 EXTRA_DIST += Mkfiles/vc8/yasm.sln
 EXTRA_DIST += Mkfiles/vc8/yasm.vcproj
index dd520685c4ce6b27529d03e30da3cf302cab3498..f886fd8954596d410de83658f20f0f74345ad407 100644 (file)
@@ -104,7 +104,7 @@ MODULES_PARSERS_OBJS= \
  modules/parsers/nasm/nasm-parse.o \
  nasm-token.o \
  modules/parsers/gas/gas-parser.o \
gas-bison.o \
modules/parsers/gas/gas-parse.o \
  gas-token.o
 YASM_MODULES+=parser_nasm
 YASM_MODULES+=parser_gas
index cb30bddee63e9090d855623af598c61f8dfc0c9c..ea64df346c2cca8d3553e6dbdce581921084e385 100644 (file)
@@ -107,7 +107,7 @@ MODULES_PARSERS_OBJS= \
  modules/parsers/nasm/nasm-parse.o \
  nasm-token.o \
  modules/parsers/gas/gas-parser.o \
gas-bison.o \
modules/parsers/gas/gas-parse.o \
  gas-token.o
 YASM_MODULES+=parser_nasm
 YASM_MODULES+=parser_gas
index cd2ce7ca0fd42d44f87ab8dec986a3840c52ca32..78535973b11937bfeaa3dcce67a52bd1b180bce2 100644 (file)
                                Name="parsers"\r
                                Filter="">\r
                                <File\r
-                                       RelativePath="..\..\..\gas-bison.c">\r
-                               </File>\r
-                               <File\r
-                                       RelativePath="..\..\..\gas-bison.h">\r
-                               </File>\r
-                               <File\r
-                                       RelativePath="..\..\..\modules\parsers\gas\gas-defs.h">\r
+                                       RelativePath="..\..\..\modules\parsers\gas\gas-parse.c">\r
                                </File>\r
                                <File\r
                                        RelativePath="..\..\..\modules\parsers\gas\gas-parser.c">\r
diff --git a/Mkfiles/vc8/bison.rules b/Mkfiles/vc8/bison.rules
deleted file mode 100644 (file)
index f8ce0f4..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<VisualStudioToolFile\r
-       Name="Bison"\r
-       Version="8.00"\r
-       >\r
-       <Rules>\r
-               <CustomBuildRule\r
-                       Name="Bison"\r
-                       DisplayName="Compiler compiler - bison"\r
-                       CommandLine="bison [AllOptions] [AdditionalOptions] [inputs]"\r
-                       Outputs="[$OutputStem].c;[$OutputStem].h"\r
-                       FileExtensions="*.y"\r
-                       ExecutionDescription="Executing bison..."\r
-                       ShowOnlyRuleProperties="false"\r
-                       >\r
-                       <Properties>\r
-                               <BooleanProperty\r
-                                       Name="OutputDefs"\r
-                                       DisplayName="Genereate extra .h file with parser defines"\r
-                                       Switch="-d"\r
-                                       DefaultValue="true"\r
-                               />\r
-                               <StringProperty\r
-                                       Name="OutputStem"\r
-                                       DisplayName="Output Stem"\r
-                                       Switch="-o &quot;[value].c&quot;"\r
-                                       DefaultValue="$(InputDir)$(InputName)"\r
-                               />\r
-                       </Properties>\r
-               </CustomBuildRule>\r
-       </Rules>\r
-</VisualStudioToolFile>\r
index c6c800610f6e23c397f0433e7d624057b12c2f9c..93e0ab8242573bf0ddfc312f4974bfc81c276142 100644 (file)
@@ -15,9 +15,6 @@
                />\r
        </Platforms>\r
        <ToolFiles>\r
-               <ToolFile\r
-                       RelativePath="..\bison.rules"\r
-               />\r
        </ToolFiles>\r
        <Configurations>\r
                <Configuration\r
@@ -36,9 +33,6 @@
                        <Tool\r
                                Name="VCCustomBuildTool"\r
                        />\r
-                       <Tool\r
-                               Name="Bison"\r
-                       />\r
                        <Tool\r
                                Name="VCXMLDataGeneratorTool"\r
                        />\r
                        <Tool\r
                                Name="VCCustomBuildTool"\r
                        />\r
-                       <Tool\r
-                               Name="Bison"\r
-                       />\r
                        <Tool\r
                                Name="VCXMLDataGeneratorTool"\r
                        />\r
                        <Tool\r
                                Name="VCCustomBuildTool"\r
                        />\r
-                       <Tool\r
-                               Name="Bison"\r
-                       />\r
                        <Tool\r
                                Name="VCXMLDataGeneratorTool"\r
                        />\r
                        <Tool\r
                                Name="VCCustomBuildTool"\r
                        />\r
-                       <Tool\r
-                               Name="Bison"\r
-                       />\r
                        <Tool\r
                                Name="VCXMLDataGeneratorTool"\r
                        />\r
                                Name="parsers"\r
                                >\r
                                <File\r
-                                       RelativePath="..\..\..\gas-bison.c"\r
-                                       >\r
-                               </File>\r
-                               <File\r
-                                       RelativePath="..\..\..\gas-bison.h"\r
-                                       >\r
-                               </File>\r
-                               <File\r
-                                       RelativePath="..\..\..\modules\parsers\gas\gas-bison.y"\r
-                                       >\r
-                                       <FileConfiguration\r
-                                               Name="Release|Win32"\r
-                                               ExcludedFromBuild="true"\r
-                                               >\r
-                                               <Tool\r
-                                                       Name="Bison"\r
-                                                       OutputStem="../../../gas-bison"\r
-                                               />\r
-                                       </FileConfiguration>\r
-                                       <FileConfiguration\r
-                                               Name="Release|x64"\r
-                                               ExcludedFromBuild="true"\r
-                                               >\r
-                                               <Tool\r
-                                                       Name="Bison"\r
-                                               />\r
-                                       </FileConfiguration>\r
-                                       <FileConfiguration\r
-                                               Name="Debug|Win32"\r
-                                               ExcludedFromBuild="true"\r
-                                               >\r
-                                               <Tool\r
-                                                       Name="Bison"\r
-                                                       OutputStem="../../../gas-bison"\r
-                                               />\r
-                                       </FileConfiguration>\r
-                                       <FileConfiguration\r
-                                               Name="Debug|x64"\r
-                                               ExcludedFromBuild="true"\r
-                                               >\r
-                                               <Tool\r
-                                                       Name="Bison"\r
-                                               />\r
-                                       </FileConfiguration>\r
-                               </File>\r
-                               <File\r
-                                       RelativePath="..\..\..\modules\parsers\gas\gas-defs.h"\r
+                                       RelativePath="..\..\..\modules\parsers\gas\gas-parse.c"\r
                                        >\r
                                </File>\r
                                <File\r
index daa8ff55aaf59de984491d64f695863f8be93b29..84de9b8b31bb04532f60941c7fcaa8470740992a 100644 (file)
@@ -13,9 +13,6 @@
                />\r
        </Platforms>\r
        <ToolFiles>\r
-               <ToolFile\r
-                       RelativePath="..\bison.rules"\r
-               />\r
        </ToolFiles>\r
        <Configurations>\r
                <Configuration\r
@@ -32,9 +29,6 @@
                        <Tool\r
                                Name="VCCustomBuildTool"\r
                        />\r
-                       <Tool\r
-                               Name="Bison"\r
-                       />\r
                        <Tool\r
                                Name="VCXMLDataGeneratorTool"\r
                        />\r
                        <Tool\r
                                Name="VCCustomBuildTool"\r
                        />\r
-                       <Tool\r
-                               Name="Bison"\r
-                       />\r
                        <Tool\r
                                Name="VCXMLDataGeneratorTool"\r
                        />\r
index 058397ed318e54cf6d8ed47e3efecea3a1a1d6a1..03741bfa6653287945d62ad6e745fedb6aef4681 100644 (file)
@@ -13,39 +13,12 @@ the Visual Studio 2005 64-bit tools, which are not installed by default.
 2. YASM Download\r
 ----------------\r
 \r
-The following files are not built by default on VC++ and are not contained\r
-in the YASM subversion repository (but they are included in the nightly\r
-YASM snapshots):\r
-\r
-    gas-bison.c\r
-    gas-bison.h\r
-\r
-However, if you want to build these files from source, follow these step:\r
-  1) Install bison.  This can be done in a number of ways, the easiest is\r
-     probably to download and run the Win32 Bison Setup program from\r
-     http://gnuwin32.sourceforge.net/packages/bison.htm\r
-  2) In Visual Studio, go to Tools|Options,\r
-     Projects and Solutions|VC++ Directories, and add the directory where\r
-     you installed Bison to the list of directories.\r
-  3) For each of the .y files in the build, right click, select Properties,\r
-     and change the "Excluded From Build" setting to No.  These files are:\r
-     modules/Source Files/gas-bison.y\r
-\r
-If you wish to build from the latest files in the subversion repository,\r
-you will need to add these files from the latest snapshot to the repository\r
-files. They should be placed in the YASM root directory.\r
-\r
-3. Building YASM with Microsoft VC8\r
------------------------------------\r
-\r
 First YASM needs to be downloaded and the files placed within a suitable\r
 directory, which will be called <yasm> here but can be named and located\r
-as you wish. If the Visual Studio 2005 project files have been obtained\r
-seperately the subdirectory 'vc8' and its subdirectories and files need to\r
-be placed in the 'Mkfiles' subdirectory within the YASM root directory.\r
+as you wish.\r
 \r
-If building from the subversion repository, obtain the additional files\r
-discussed above and place them in the YASM root directory.\r
+3. Building YASM with Microsoft VC8\r
+-----------------------------------\r
 \r
 Now locate and double click on the yasm.sln solution file in the 'Mkfiles/vc8'\r
 subdirectory to open the build project in the Visual Studio 2005 IDE and then\r
diff --git a/config/ylwrap b/config/ylwrap
deleted file mode 100755 (executable)
index 94c0f9e..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-#! /bin/sh
-# ylwrap - wrapper for lex/yacc invocations.
-# Copyright 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
-# Written by Tom Tromey <tromey@cygnus.com>.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Usage:
-#     ylwrap INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]...
-# * INPUT is the input file
-# * OUTPUT is file PROG generates
-# * DESIRED is file we actually want
-# * PROGRAM is program to run
-# * ARGS are passed to PROG
-# Any number of OUTPUT,DESIRED pairs may be used.
-
-# The input.
-input="$1"
-shift
-case "$input" in
- [\\/]* | ?:[\\/]*)
-    # Absolute path; do nothing.
-    ;;
- *)
-    # Relative path.  Make it absolute.
-    input="`pwd`/$input"
-    ;;
-esac
-
-# The directory holding the input.
-input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'`
-# Quote $INPUT_DIR so we can use it in a regexp.
-# FIXME: really we should care about more than `.' and `\'.
-input_rx=`echo "$input_dir" | sed -e 's,\\\\,\\\\\\\\,g' -e 's,\\.,\\\\.,g'`
-
-echo "got $input_rx"
-
-pairlist=
-while test "$#" -ne 0; do
-   if test "$1" = "--"; then
-      shift
-      break
-   fi
-   pairlist="$pairlist $1"
-   shift
-done
-
-# The program to run.
-prog="$1"
-shift
-# Make any relative path in $prog absolute.
-case "$prog" in
- [\\/]* | ?:[\\/]*) ;;
- *[\\/]*) prog="`pwd`/$prog" ;;
-esac
-
-# FIXME: add hostname here for parallel makes that run commands on
-# other machines.  But that might take us over the 14-char limit.
-dirname=ylwrap$$
-trap "cd `pwd`; rm -rf $dirname > /dev/null 2>&1" 1 2 3 15
-mkdir $dirname || exit 1
-
-cd $dirname
-
-$prog ${1+"$@"} "$input"
-status=$?
-
-if test $status -eq 0; then
-   set X $pairlist
-   shift
-   first=yes
-   # Since DOS filename conventions don't allow two dots,
-   # the DOS version of Bison writes out y_tab.c instead of y.tab.c
-   # and y_tab.h instead of y.tab.h. Test to see if this is the case.
-   y_tab_nodot="no"
-   if test -f y_tab.c || test -f y_tab.h; then
-      y_tab_nodot="yes"
-   fi
-
-   while test "$#" -ne 0; do
-      from="$1"
-      # Handle y_tab.c and y_tab.h output by DOS
-      if test $y_tab_nodot = "yes"; then
-        if test $from = "y.tab.c"; then
-           from="y_tab.c"
-        else
-           if test $from = "y.tab.h"; then
-              from="y_tab.h"
-           fi
-        fi
-      fi
-      if test -f "$from"; then
-         # If $2 is an absolute path name, then just use that,
-         # otherwise prepend `../'.
-         case "$2" in
-          [\\/]* | ?:[\\/]*) target="$2";;
-          *) target="../$2";;
-        esac
-        from_rx=`echo "$from" | sed -e 's,\\\\,\\\\\\\\,g' -e 's,\\.,\\\\.,g'`
-
-        # Edit out `#line' or `#' directives.  We don't want the
-        # resulting debug information to point at an absolute srcdir;
-        # it is better for it to just mention the .y file with no
-        # path.
-        sed -e "/^#/ s,$input_rx,," -e "/^#/ s,$from_rx,$2," "$from" > "$target" || status=$?
-      else
-        # A missing file is only an error for the first file.  This
-        # is a blatant hack to let us support using "yacc -d".  If -d
-        # is not specified, we don't want an error when the header
-        # file is "missing".
-        if test $first = yes; then
-           status=1
-        fi
-      fi
-      shift
-      shift
-      first=no
-   done
-else
-   status=$?
-fi
-
-# Remove the directory.
-cd ..
-rm -rf $dirname
-
-exit $status
index e15066fcbe50d88309cc8f45c987cc79f28c0a07..45ae2b1776b213ffcb65cb22c0de0ff53dcdadeb 100644 (file)
@@ -64,28 +64,6 @@ esac], enable_python="auto")
 #
 # Checks for programs.
 #
-AC_PROG_YACC
-# check for Bison in particular
-if test "$YACC" != "bison -y"; then
-       AC_MSG_WARN([You will need GNU Bison if you want to regenerate parsers.])
-       YACC=
-else
-       AC_MSG_CHECKING([bison version])
-       set `bison --version | grep 'GNU Bison' | sed -e 's/^@<:@A-Za-z() @:>@*//g' -e 's/\./ /'`
-       if test -z "$1" -o -z "$2"; then
-               AC_MSG_RESULT([unknown])
-               AC_MSG_WARN([You will need GNU Bison 1.25 or better if you want to regenerate parsers.])
-               YACC=
-       else
-               if test "$1" = "1" -a "$2" -lt "25"; then
-                       AC_MSG_RESULT([$1.$2])
-                       AC_MSG_WARN([You will need GNU Bison 1.25 or better if you want to regenerate parsers (found $1.$2).])
-                       YACC=
-               else
-                       AC_MSG_RESULT([$1.$2 (ok)])
-               fi
-       fi
-fi
 AC_PROG_CC_STDC
 AC_PROG_INSTALL
 AC_PROG_LN_S
index 84fd05470cd90551e784c464127e693b4560acca..9b651f7a44d06ce2b52ce53dd28f5b6e58212212 100644 (file)
@@ -2,9 +2,7 @@
 
 libyasm_a_SOURCES += modules/parsers/gas/gas-parser.c
 libyasm_a_SOURCES += modules/parsers/gas/gas-parser.h
-libyasm_a_SOURCES += modules/parsers/gas/gas-defs.h
-libyasm_a_SOURCES += modules/parsers/gas/gas-bison.y
-libyasm_a_SOURCES += gas-bison.h
+libyasm_a_SOURCES += modules/parsers/gas/gas-parse.c
 libyasm_a_SOURCES += gas-token.c
 
 YASM_MODULES += parser_gas
@@ -12,12 +10,8 @@ YASM_MODULES += parser_gas
 gas-token.c: $(srcdir)/modules/parsers/gas/gas-token.re re2c$(EXEEXT)
        $(top_builddir)/re2c$(EXEEXT) -b -o $@ $(srcdir)/modules/parsers/gas/gas-token.re
 
-BUILT_SOURCES += gas-bison.c
-BUILT_SOURCES += gas-bison.h
 BUILT_SOURCES += gas-token.c
 
-CLEANFILES += gas-bison.c
-CLEANFILES += gas-bison.h
 CLEANFILES += gas-token.c
 
 EXTRA_DIST += modules/parsers/gas/tests/Makefile.inc
diff --git a/modules/parsers/gas/gas-bison.y b/modules/parsers/gas/gas-bison.y
deleted file mode 100644 (file)
index d9bfc4c..0000000
+++ /dev/null
@@ -1,1086 +0,0 @@
-/*
- * GAS-compatible bison parser
- *
- *  Copyright (C) 2005  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.
- * 3. Neither the name of the author nor the names of other contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * 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/gas/gas-parser.h"
-#include "modules/parsers/gas/gas-defs.h"
-
-static void define_label(yasm_parser_gas *parser_gas, char *name, int local);
-static void define_lcomm(yasm_parser_gas *parser_gas, /*@only@*/ char *name,
-                        yasm_expr *size, /*@null@*/ yasm_expr *align);
-static yasm_section *gas_get_section
-    (yasm_parser_gas *parser_gas, /*@only@*/ char *name, /*@null@*/ char *flags,
-     /*@null@*/ char *type, /*@null@*/ yasm_valparamhead *objext_valparams,
-     int builtin);
-static void gas_switch_section
-    (yasm_parser_gas *parser_gas, /*@only@*/ char *name, /*@null@*/ char *flags,
-     /*@null@*/ char *type, /*@null@*/ yasm_valparamhead *objext_valparams,
-     int builtin);
-static yasm_bytecode *gas_parser_align
-    (yasm_parser_gas *parser_gas, yasm_section *sect, yasm_expr *boundval,
-     /*@null@*/ yasm_expr *fillval, /*@null@*/ yasm_expr *maxskipval,
-     int power2);
-static yasm_bytecode *gas_parser_dir_align(yasm_parser_gas *parser_gas,
-                                          yasm_valparamhead *valparams,
-                                          int power2);
-static yasm_bytecode *gas_parser_dir_fill
-    (yasm_parser_gas *parser_gas, /*@only@*/ yasm_expr *repeat,
-     /*@only@*/ /*@null@*/ yasm_expr *size,
-     /*@only@*/ /*@null@*/ yasm_expr *value);
-static void gas_parser_directive
-    (yasm_parser_gas *parser_gas, const char *name,
-     yasm_valparamhead *valparams,
-     /*@null@*/ yasm_valparamhead *objext_valparams);
-
-#define gas_parser_error(s)    \
-    yasm_error_set(YASM_ERROR_PARSE, "%s", s)
-#define YYPARSE_PARAM  parser_gas_arg
-#define YYLEX_PARAM    parser_gas_arg
-#define parser_gas     ((yasm_parser_gas *)parser_gas_arg)
-#define gas_parser_debug   (parser_gas->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_bytecode *bc;
-    yasm_valparamhead valparams;
-    yasm_datavalhead datavals;
-    yasm_dataval *dv;
-    struct {
-       yasm_insn_operands operands;
-       int num_operands;
-    } insn_operands;
-    yasm_insn_operand *insn_operand;
-    struct {
-       char *contents;
-       size_t len;
-    } str;
-}
-
-%token <intn> INTNUM
-%token <flt> FLTNUM
-%token <str> STRING
-%token <int_info> SIZE_OVERRIDE
-%token <int_info> DECLARE_DATA
-%token <int_info> RESERVE_SPACE
-%token <arch_data> INSN PREFIX REG REGGROUP SEGREG TARGETMOD
-%token LEFT_OP RIGHT_OP
-%token <str_val> ID DIR_ID LABEL
-%token LINE
-%token DIR_2BYTE DIR_4BYTE DIR_ALIGN DIR_ASCII DIR_ASCIZ DIR_BALIGN
-%token DIR_BSS DIR_BYTE DIR_COMM DIR_DATA DIR_DOUBLE DIR_ENDR DIR_EXTERN
-%token DIR_EQU DIR_FILE DIR_FILL DIR_FLOAT DIR_GLOBAL DIR_IDENT DIR_INT
-%token DIR_LINE DIR_LOC DIR_LOCAL DIR_LCOMM DIR_OCTA DIR_ORG DIR_P2ALIGN
-%token DIR_REPT DIR_SECTION DIR_SHORT DIR_SIZE DIR_SKIP DIR_SLEB128 DIR_STRING
-%token DIR_TEXT DIR_TFLOAT DIR_TYPE DIR_QUAD DIR_ULEB128 DIR_VALUE DIR_WEAK
-%token DIR_WORD DIR_ZERO
-
-%type <bc> lineexp instr
-
-%type <str_val> expr_id label_id
-%type <ea> memaddr
-%type <exp> expr regmemexpr
-%type <sym> explabel
-%type <valparams> dirvals dirvals2 dirstrvals dirstrvals2
-%type <datavals> strvals datavals strvals2 datavals2
-%type <insn_operands> operands
-%type <insn_operand> operand
-
-%left '-' '+'
-%left '|' '&' '^' '!'
-%left '*' '/' '%' LEFT_OP RIGHT_OP
-%nonassoc UNARYOP
-
-%%
-input: /* empty */
-    | input line    {
-       yasm_errwarn_propagate(parser_gas->errwarns, cur_line);
-       if (parser_gas->save_input)
-           yasm_linemap_add_source(parser_gas->linemap,
-               parser_gas->prev_bc,
-               (char *)parser_gas->save_line[parser_gas->save_last ^ 1]);
-       yasm_linemap_goto_next(parser_gas->linemap);
-       parser_gas->dir_line++; /* keep track for .line followed by .file */
-    }
-;
-
-line: '\n'
-    | linebcs '\n'
-    | error '\n'       {
-       yasm_error_set(YASM_ERROR_SYNTAX,
-                      N_("label or instruction expected at start of line"));
-       yyerrok;
-    }
-;
-
-linebcs: linebc
-    | linebc ';' linebcs
-;
-
-linebc: lineexp {
-       parser_gas->temp_bc =
-           yasm_section_bcs_append(parser_gas->cur_section, $1);
-       if (parser_gas->temp_bc)
-           parser_gas->prev_bc = parser_gas->temp_bc;
-    }
-;
-
-lineexp: instr
-    | label_id ':'             {
-       $$ = (yasm_bytecode *)NULL;
-       define_label(parser_gas, $1, 0);
-    }
-    | label_id ':' instr       {
-       $$ = $3;
-       define_label(parser_gas, $1, 0);
-    }
-    | LABEL            {
-       $$ = (yasm_bytecode *)NULL;
-       define_label(parser_gas, $1, 0);
-    }
-    | LABEL instr      {
-       $$ = $2;
-       define_label(parser_gas, $1, 0);
-    }
-    /* Line directive */
-    | DIR_LINE INTNUM {
-       $$ = (yasm_bytecode *)NULL;
-       if (yasm_intnum_sign($2) < 0)
-           yasm_error_set(YASM_ERROR_SYNTAX, N_("line number is negative"));
-       else {
-           parser_gas->dir_line = yasm_intnum_get_uint($2);
-           yasm_intnum_destroy($2);
-           if (parser_gas->dir_fileline == 3) {
-               /* Have both file and line */
-               yasm_linemap_set(parser_gas->linemap, NULL,
-                                parser_gas->dir_line, 1);
-           } else if (parser_gas->dir_fileline == 1) {
-               /* Had previous file directive only */
-               parser_gas->dir_fileline = 3;
-               yasm_linemap_set(parser_gas->linemap, parser_gas->dir_file,
-                                parser_gas->dir_line, 1);
-           } else {
-               /* Didn't see file yet */
-               parser_gas->dir_fileline = 2;
-           }
-       }
-    }
-    /* Macro directives */
-    | DIR_REPT expr {
-       yasm_intnum *intn = yasm_expr_get_intnum(&$2, 0);
-
-       $$ = (yasm_bytecode *)NULL;
-       if (!intn) {
-           yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
-                          N_("rept expression not absolute"));
-       } else if (yasm_intnum_sign(intn) < 0) {
-           yasm_error_set(YASM_ERROR_VALUE,
-                          N_("rept expression is negative"));
-       } else {
-           gas_rept *rept = yasm_xmalloc(sizeof(gas_rept));
-           STAILQ_INIT(&rept->lines);
-           rept->startline = cur_line;
-           rept->numrept = yasm_intnum_get_uint(intn);
-           rept->numdone = 0;
-           rept->line = NULL;
-           rept->linepos = 0;
-           rept->ended = 0;
-           rept->oldbuf = NULL;
-           rept->oldbuflen = 0;
-           rept->oldbufpos = 0;
-           parser_gas->rept = rept;
-       }
-    }
-    | DIR_ENDR {
-       $$ = (yasm_bytecode *)NULL;
-       /* Shouldn't ever get here unless we didn't get a DIR_REPT first */
-       yasm_error_set(YASM_ERROR_SYNTAX, N_("endr without matching rept"));
-    }
-    /* Alignment directives */
-    | DIR_ALIGN dirvals2 {
-       /* FIXME: Whether this is power-of-two or not depends on arch and
-        * objfmt.
-        */
-       $$ = gas_parser_dir_align(parser_gas, &$2, 0);
-    }
-    | DIR_P2ALIGN dirvals2 {
-       $$ = gas_parser_dir_align(parser_gas, &$2, 1);
-    }
-    | DIR_BALIGN dirvals2 {
-       $$ = gas_parser_dir_align(parser_gas, &$2, 0);
-    }
-    | DIR_ORG INTNUM {
-       /* TODO: support expr instead of intnum */
-       $$ = yasm_bc_create_org(yasm_intnum_get_uint($2), cur_line);
-    }
-    /* Data visibility directives */
-    | DIR_LOCAL label_id {
-       yasm_symtab_declare(parser_gas->symtab, $2, YASM_SYM_DLOCAL, cur_line);
-       yasm_xfree($2);
-       $$ = NULL;
-    }
-    | DIR_GLOBAL label_id {
-       yasm_objfmt_global_declare(parser_gas->objfmt, $2, NULL, cur_line);
-       yasm_xfree($2);
-       $$ = NULL;
-    }
-    | DIR_COMM label_id ',' expr {
-       /* If already explicitly declared local, treat like LCOMM */
-       /*@null@*/ /*@dependent@*/ yasm_symrec *sym =
-           yasm_symtab_get(parser_gas->symtab, $2);
-       if (sym && yasm_symrec_get_visibility(sym) == YASM_SYM_DLOCAL) {
-           define_lcomm(parser_gas, $2, $4, NULL);
-       } else {
-           yasm_objfmt_common_declare(parser_gas->objfmt, $2, $4, NULL,
-                                      cur_line);
-           yasm_xfree($2);
-       }
-       $$ = NULL;
-    }
-    | DIR_COMM label_id ',' expr ',' expr {
-       /* If already explicitly declared local, treat like LCOMM */
-       /*@null@*/ /*@dependent@*/ yasm_symrec *sym =
-           yasm_symtab_get(parser_gas->symtab, $2);
-       if (sym && yasm_symrec_get_visibility(sym)) {
-           define_lcomm(parser_gas, $2, $4, $6);
-       } else {
-           /* Give third parameter as objext valparam for use as alignment */
-           yasm_valparamhead vps;
-           yasm_valparam *vp;
-
-           yasm_vps_initialize(&vps);
-           vp = yasm_vp_create(NULL, $6);
-           yasm_vps_append(&vps, vp);
-
-           yasm_objfmt_common_declare(parser_gas->objfmt, $2, $4, &vps,
-                                      cur_line);
-
-           yasm_vps_delete(&vps);
-           yasm_xfree($2);
-       }
-       $$ = NULL;
-    }
-    | DIR_EXTERN label_id {
-       /* Go ahead and do it, even though all undef become extern */
-       yasm_objfmt_extern_declare(parser_gas->objfmt, $2, NULL, cur_line);
-       yasm_xfree($2);
-       $$ = NULL;
-    }
-    | DIR_WEAK label_id {
-       yasm_valparamhead vps;
-       yasm_valparam *vp;
-
-       yasm_vps_initialize(&vps);
-       vp = yasm_vp_create($2, NULL);
-       yasm_vps_append(&vps, vp);
-
-       yasm_objfmt_directive(parser_gas->objfmt, "weak", &vps, NULL,
-                             cur_line);
-
-       yasm_vps_delete(&vps);
-       $$ = NULL;
-    }
-    | DIR_LCOMM label_id ',' expr {
-       define_lcomm(parser_gas, $2, $4, NULL);
-       $$ = NULL;
-    }
-    | DIR_LCOMM label_id ',' expr ',' expr {
-       define_lcomm(parser_gas, $2, $4, $6);
-       $$ = NULL;
-    }
-    /* Integer data definition directives */
-    | DIR_ASCII strvals {
-       $$ = yasm_bc_create_data(&$2, 1, 0, parser_gas->arch, cur_line);
-    }
-    | DIR_ASCIZ strvals {
-       $$ = yasm_bc_create_data(&$2, 1, 1, parser_gas->arch, cur_line);
-    }
-    | DIR_BYTE datavals {
-       $$ = yasm_bc_create_data(&$2, 1, 0, parser_gas->arch, cur_line);
-    }
-    | DIR_SHORT datavals {
-       /* TODO: This should depend on arch */
-       $$ = yasm_bc_create_data(&$2, 2, 0, parser_gas->arch, cur_line);
-    }
-    | DIR_WORD datavals {
-       $$ = yasm_bc_create_data(&$2, yasm_arch_wordsize(parser_gas->arch)/8, 0,
-                                parser_gas->arch, cur_line);
-    }
-    | DIR_INT datavals {
-       /* TODO: This should depend on arch */
-       $$ = yasm_bc_create_data(&$2, 4, 0, parser_gas->arch, cur_line);
-    }
-    | DIR_VALUE datavals {
-       /* XXX: At least on x86, this is two bytes */
-       $$ = yasm_bc_create_data(&$2, 2, 0, parser_gas->arch, cur_line);
-    }
-    | DIR_2BYTE datavals {
-       $$ = yasm_bc_create_data(&$2, 2, 0, parser_gas->arch, cur_line);
-    }
-    | DIR_4BYTE datavals {
-       $$ = yasm_bc_create_data(&$2, 4, 0, parser_gas->arch, cur_line);
-    }
-    | DIR_QUAD datavals {
-       $$ = yasm_bc_create_data(&$2, 8, 0, parser_gas->arch, cur_line);
-    }
-    | DIR_OCTA datavals {
-       $$ = yasm_bc_create_data(&$2, 16, 0, parser_gas->arch, cur_line);
-    }
-    | DIR_ZERO expr {
-       yasm_datavalhead dvs;
-
-       yasm_dvs_initialize(&dvs);
-       yasm_dvs_append(&dvs, yasm_dv_create_expr(
-           p_expr_new_ident(yasm_expr_int(yasm_intnum_create_uint(0)))));
-       $$ = yasm_bc_create_data(&dvs, 1, 0, parser_gas->arch, cur_line);
-
-       yasm_bc_set_multiple($$, $2);
-    }
-    | DIR_SLEB128 datavals {
-       $$ = yasm_bc_create_leb128(&$2, 1, cur_line);
-    }
-    | DIR_ULEB128 datavals {
-       $$ = yasm_bc_create_leb128(&$2, 0, cur_line);
-    }
-    /* Floating point data definition directives */
-    | DIR_FLOAT datavals {
-       $$ = yasm_bc_create_data(&$2, 4, 0, parser_gas->arch, cur_line);
-    }
-    | DIR_DOUBLE datavals {
-       $$ = yasm_bc_create_data(&$2, 8, 0, parser_gas->arch, cur_line);
-    }
-    | DIR_TFLOAT datavals {
-       $$ = yasm_bc_create_data(&$2, 10, 0, parser_gas->arch, cur_line);
-    }
-    /* Empty space / fill data definition directives */
-    | DIR_SKIP expr {
-       $$ = yasm_bc_create_reserve($2, 1, cur_line);
-    }
-    | DIR_SKIP expr ',' expr {
-       yasm_datavalhead dvs;
-
-       yasm_dvs_initialize(&dvs);
-       yasm_dvs_append(&dvs, yasm_dv_create_expr($4));
-       $$ = yasm_bc_create_data(&dvs, 1, 0, parser_gas->arch, cur_line);
-
-       yasm_bc_set_multiple($$, $2);
-    }
-    /* fill data definition directive */
-    | DIR_FILL expr {
-       $$ = gas_parser_dir_fill(parser_gas, $2, NULL, NULL);
-    }
-    | DIR_FILL expr ',' expr {
-       $$ = gas_parser_dir_fill(parser_gas, $2, $4, NULL);
-    }
-    | DIR_FILL expr ',' expr ',' expr {
-       $$ = gas_parser_dir_fill(parser_gas, $2, $4, $6);
-    }
-    /* Section directives */
-    | DIR_TEXT {
-       gas_switch_section(parser_gas, yasm__xstrdup(".text"), NULL, NULL,
-                          NULL, 1);
-       $$ = NULL;
-    }
-    | DIR_DATA {
-       gas_switch_section(parser_gas, yasm__xstrdup(".data"), NULL, NULL,
-                          NULL, 1);
-       $$ = NULL;
-    }
-    | DIR_BSS {
-       gas_switch_section(parser_gas, yasm__xstrdup(".bss"), NULL, NULL, NULL,
-                          1);
-       $$ = NULL;
-    }
-    | DIR_SECTION label_id {
-       gas_switch_section(parser_gas, $2, NULL, NULL, NULL, 0);
-       $$ = NULL;
-    }
-    | DIR_SECTION label_id ',' STRING {
-       gas_switch_section(parser_gas, $2, $4.contents, NULL, NULL, 0);
-       yasm_xfree($4.contents);
-       $$ = NULL;
-    }
-    | DIR_SECTION label_id ',' STRING ',' '@' label_id {
-       gas_switch_section(parser_gas, $2, $4.contents, $7, NULL, 0);
-       yasm_xfree($4.contents);
-       $$ = NULL;
-    }
-    | DIR_SECTION label_id ',' STRING ',' '@' label_id ',' dirvals {
-       gas_switch_section(parser_gas, $2, $4.contents, $7, &$9, 0);
-       yasm_xfree($4.contents);
-       $$ = NULL;
-    }
-    /* Other directives */
-    | DIR_IDENT dirstrvals {
-       yasm_objfmt_directive(parser_gas->objfmt, "ident", &$2, NULL,
-                             cur_line);
-       yasm_vps_delete(&$2);
-       $$ = NULL;
-    }
-    | DIR_FILE INTNUM STRING {
-       yasm_valparamhead vps;
-       yasm_valparam *vp;
-
-       yasm_vps_initialize(&vps);
-       vp = yasm_vp_create(NULL, p_expr_new_ident(yasm_expr_int($2)));
-       yasm_vps_append(&vps, vp);
-       vp = yasm_vp_create($3.contents, NULL);
-       yasm_vps_append(&vps, vp);
-
-       yasm_dbgfmt_directive(parser_gas->dbgfmt, "file",
-                             parser_gas->cur_section, &vps, cur_line);
-
-       yasm_vps_delete(&vps);
-       $$ = NULL;
-    }
-    | DIR_FILE STRING {
-       yasm_valparamhead vps;
-       yasm_valparam *vp;
-
-       /* This form also sets the assembler's internal line number */
-       if (parser_gas->dir_fileline == 3) {
-           /* Have both file and line */
-           const char *old_fn;
-           unsigned long old_line;
-
-           yasm_linemap_lookup(parser_gas->linemap, cur_line, &old_fn,
-                               &old_line);
-           yasm_linemap_set(parser_gas->linemap, $2.contents,
-                            old_line, 1);
-       } else if (parser_gas->dir_fileline == 2) {
-           /* Had previous line directive only */
-           parser_gas->dir_fileline = 3;
-           yasm_linemap_set(parser_gas->linemap, $2.contents,
-                            parser_gas->dir_line, 1);
-       } else {
-           /* Didn't see line yet, save file */
-           parser_gas->dir_fileline = 1;
-           if (parser_gas->dir_file)
-               yasm_xfree(parser_gas->dir_file);
-           parser_gas->dir_file = yasm__xstrdup($2.contents);
-       }
-
-       /* Pass change along to debug format */
-       yasm_vps_initialize(&vps);
-       vp = yasm_vp_create($2.contents, NULL);
-       yasm_vps_append(&vps, vp);
-
-       yasm_dbgfmt_directive(parser_gas->dbgfmt, "file",
-                             parser_gas->cur_section, &vps, cur_line);
-
-       yasm_vps_delete(&vps);
-       $$ = NULL;
-    }
-    | DIR_LOC INTNUM INTNUM {
-       yasm_valparamhead vps;
-       yasm_valparam *vp;
-
-       yasm_vps_initialize(&vps);
-       vp = yasm_vp_create(NULL, p_expr_new_ident(yasm_expr_int($2)));
-       yasm_vps_append(&vps, vp);
-       vp = yasm_vp_create(NULL, p_expr_new_ident(yasm_expr_int($3)));
-       yasm_vps_append(&vps, vp);
-
-       yasm_dbgfmt_directive(parser_gas->dbgfmt, "loc",
-                             parser_gas->cur_section, &vps, cur_line);
-
-       yasm_vps_delete(&vps);
-       $$ = NULL;
-    }
-    | DIR_LOC INTNUM INTNUM INTNUM {
-       yasm_valparamhead vps;
-       yasm_valparam *vp;
-
-       yasm_vps_initialize(&vps);
-       vp = yasm_vp_create(NULL, p_expr_new_ident(yasm_expr_int($2)));
-       yasm_vps_append(&vps, vp);
-       vp = yasm_vp_create(NULL, p_expr_new_ident(yasm_expr_int($3)));
-       yasm_vps_append(&vps, vp);
-       vp = yasm_vp_create(NULL, p_expr_new_ident(yasm_expr_int($4)));
-       yasm_vps_append(&vps, vp);
-
-       yasm_dbgfmt_directive(parser_gas->dbgfmt, "loc",
-                             parser_gas->cur_section, &vps, cur_line);
-
-       yasm_vps_delete(&vps);
-       $$ = NULL;
-    }
-    | DIR_TYPE label_id ',' '@' label_id {
-       yasm_valparamhead vps;
-       yasm_valparam *vp;
-
-       yasm_vps_initialize(&vps);
-       vp = yasm_vp_create($2, NULL);
-       yasm_vps_append(&vps, vp);
-       vp = yasm_vp_create($5, NULL);
-       yasm_vps_append(&vps, vp);
-
-       yasm_objfmt_directive(parser_gas->objfmt, "type", &vps, NULL,
-                             cur_line);
-
-       yasm_vps_delete(&vps);
-       $$ = NULL;
-    }
-    | DIR_SIZE label_id ',' expr {
-       yasm_valparamhead vps;
-       yasm_valparam *vp;
-
-       yasm_vps_initialize(&vps);
-       vp = yasm_vp_create($2, NULL);
-       yasm_vps_append(&vps, vp);
-       vp = yasm_vp_create(NULL, $4);
-       yasm_vps_append(&vps, vp);
-
-       yasm_objfmt_directive(parser_gas->objfmt, "size", &vps, NULL,
-                             cur_line);
-
-       yasm_vps_delete(&vps);
-       $$ = NULL;
-    }
-    | DIR_ID dirvals   {
-       yasm_warn_set(YASM_WARN_GENERAL, N_("directive `%s' not recognized"),
-                     $1);
-       $$ = (yasm_bytecode *)NULL;
-       yasm_xfree($1);
-       yasm_vps_delete(&$2);
-    }
-    | DIR_ID error     {
-       yasm_warn_set(YASM_WARN_GENERAL, N_("directive `%s' not recognized"),
-                     $1);
-       $$ = (yasm_bytecode *)NULL;
-       yasm_xfree($1);
-    }
-    | label_id '=' expr        {
-       $$ = (yasm_bytecode *)NULL;
-       yasm_symtab_define_equ(p_symtab, $1, $3, cur_line);
-       yasm_xfree($1);
-    }
-;
-
-instr: INSN            {
-       $$ = yasm_bc_create_insn(parser_gas->arch, $1, 0, NULL, cur_line);
-    }
-    | INSN operands    {
-       $$ = yasm_bc_create_insn(parser_gas->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]);
-    }
-    | PREFIX {
-       $$ = yasm_bc_create_empty_insn(parser_gas->arch, cur_line);
-       yasm_bc_insn_add_prefix($$, $1);
-    }
-    | SEGREG {
-       $$ = yasm_bc_create_empty_insn(parser_gas->arch, cur_line);
-       yasm_bc_insn_add_seg_prefix($$, $1[0]);
-    }
-    | ID {
-       yasm_error_set(YASM_ERROR_SYNTAX,
-                      N_("instruction not recognized: `%s'"), $1);
-       $$ = NULL;
-    }
-    | ID operands {
-       yasm_error_set(YASM_ERROR_SYNTAX,
-                      N_("instruction not recognized: `%s'"), $1);
-       $$ = NULL;
-    }
-    | ID error {
-       yasm_error_set(YASM_ERROR_SYNTAX,
-                      N_("instruction not recognized: `%s'"), $1);
-       $$ = NULL;
-    }
-;
-
-dirvals: /* empty */   { yasm_vps_initialize(&$$); }
-    | dirvals2
-;
-
-dirvals2: expr                 {
-       yasm_valparam *vp = yasm_vp_create(NULL, $1);
-       yasm_vps_initialize(&$$);
-       yasm_vps_append(&$$, vp);
-    }
-    | dirvals2 ',' expr        {
-       yasm_valparam *vp = yasm_vp_create(NULL, $3);
-       yasm_vps_append(&$1, vp);
-       $$ = $1;
-    }
-    | dirvals2 ',' ',' expr    {
-       yasm_valparam *vp = yasm_vp_create(NULL, NULL);
-       yasm_vps_append(&$1, vp);
-       vp = yasm_vp_create(NULL, $4);
-       yasm_vps_append(&$1, vp);
-       $$ = $1;
-    }
-;
-
-dirstrvals: /* empty */        { yasm_vps_initialize(&$$); }
-    | dirstrvals2
-;
-
-dirstrvals2: STRING    {
-       yasm_valparam *vp = yasm_vp_create($1.contents, NULL);
-       yasm_vps_initialize(&$$);
-       yasm_vps_append(&$$, vp);
-    }
-    | dirstrvals2 ',' STRING   {
-       yasm_valparam *vp = yasm_vp_create($3.contents, NULL);
-       yasm_vps_append(&$1, vp);
-       $$ = $1;
-    }
-;
-
-strvals: /* empty */   { yasm_dvs_initialize(&$$); }
-    | strvals2
-;
-
-strvals2: STRING               {
-       yasm_dataval *dv = yasm_dv_create_string($1.contents, $1.len);
-       yasm_dvs_initialize(&$$);
-       yasm_dvs_append(&$$, dv);
-    }
-    | strvals2 ',' STRING      {
-       yasm_dataval *dv = yasm_dv_create_string($3.contents, $3.len);
-       yasm_dvs_append(&$1, dv);
-       $$ = $1;
-    }
-;
-
-datavals: /* empty */  { yasm_dvs_initialize(&$$); }
-    | datavals2
-;
-
-datavals2: expr                        {
-       yasm_dataval *dv = yasm_dv_create_expr($1);
-       yasm_dvs_initialize(&$$);
-       yasm_dvs_append(&$$, dv);
-    }
-    | datavals2 ',' expr       {
-       yasm_dataval *dv = yasm_dv_create_expr($3);
-       yasm_dvs_append(&$1, dv);
-       $$ = $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;
-    }
-;
-
-regmemexpr: '(' REG ')'            {
-       $$ = p_expr_new_ident(yasm_expr_reg($2[0]));
-    }
-    | '(' ',' REG ')'      {
-       $$ = p_expr_new(yasm_expr_reg($3[0]), YASM_EXPR_MUL,
-                       yasm_expr_int(yasm_intnum_create_uint(1)));
-    }
-    | '(' ',' INTNUM ')'    {
-       if (yasm_intnum_get_uint($3) != 1)
-           yasm_warn_set(YASM_WARN_GENERAL,
-                         N_("scale factor of %u without an index register"),
-                         yasm_intnum_get_uint($3));
-       $$ = p_expr_new(yasm_expr_int(yasm_intnum_create_uint(0)),
-                       YASM_EXPR_MUL, yasm_expr_int($3));
-    }
-    | '(' REG ',' REG ')'  {
-       $$ = p_expr_new(yasm_expr_reg($2[0]), YASM_EXPR_ADD,
-           yasm_expr_expr(p_expr_new(yasm_expr_reg($4[0]), YASM_EXPR_MUL,
-               yasm_expr_int(yasm_intnum_create_uint(1)))));
-    }
-    | '(' ',' REG ',' INTNUM ')'  {
-       $$ = p_expr_new(yasm_expr_reg($3[0]), YASM_EXPR_MUL,
-                       yasm_expr_int($5));
-    }
-    | '(' REG ',' REG ',' INTNUM ')'  {
-       $$ = p_expr_new(yasm_expr_reg($2[0]), YASM_EXPR_ADD,
-           yasm_expr_expr(p_expr_new(yasm_expr_reg($4[0]), YASM_EXPR_MUL,
-                                     yasm_expr_int($6))));
-    }
-;
-
-/* memory addresses */
-memaddr: expr              {
-       $$ = yasm_arch_ea_create(parser_gas->arch, $1);
-    }
-    | regmemexpr           {
-       $$ = yasm_arch_ea_create(parser_gas->arch, $1);
-       yasm_ea_set_strong($$, 1);
-    }
-    | expr regmemexpr      {
-       $$ = yasm_arch_ea_create(parser_gas->arch,
-                                p_expr_new_tree($2, YASM_EXPR_ADD, $1));
-       yasm_ea_set_strong($$, 1);
-    }
-    | SEGREG ':' memaddr  {
-       $$ = $3;
-       yasm_ea_set_segreg($$, $1[0]);
-    }
-;
-
-operand: memaddr           { $$ = yasm_operand_create_mem($1); }
-    | REG                  { $$ = yasm_operand_create_reg($1[0]); }
-    | SEGREG               { $$ = yasm_operand_create_segreg($1[0]); }
-    | REGGROUP             { $$ = yasm_operand_create_reg($1[0]); }
-    | REGGROUP '(' INTNUM ')'  {
-       unsigned long reg =
-           yasm_arch_reggroup_get_reg(parser_gas->arch, $1[0],
-                                      yasm_intnum_get_uint($3));
-       if (reg == 0) {
-           yasm_error_set(YASM_ERROR_SYNTAX, N_("bad register index `%u'"),
-                          yasm_intnum_get_uint($3));
-           $$ = yasm_operand_create_reg($1[0]);
-       } else
-           $$ = yasm_operand_create_reg(reg);
-       yasm_intnum_destroy($3);
-    }
-    | '$' expr             { $$ = yasm_operand_create_imm($2); }
-    | '*' REG              {
-       $$ = yasm_operand_create_reg($2[0]);
-       $$->deref = 1;
-    }
-    | '*' memaddr          {
-       $$ = yasm_operand_create_mem($2);
-       $$->deref = 1;
-    }
-;
-
-/* Expressions */
-expr: INTNUM           { $$ = p_expr_new_ident(yasm_expr_int($1)); }
-    | FLTNUM           { $$ = p_expr_new_ident(yasm_expr_float($1)); }
-    | explabel         { $$ = p_expr_new_ident(yasm_expr_sym($1)); }
-    | 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_AND, $3); }
-    | expr '!' expr    { $$ = p_expr_new_tree($1, YASM_EXPR_NOR, $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 '%' expr    { $$ = p_expr_new_tree($1, YASM_EXPR_MOD, $3); }
-    | '+' expr %prec UNARYOP   { $$ = $2; }
-    | '-' expr %prec UNARYOP   { $$ = p_expr_new_branch(YASM_EXPR_NEG, $2); }
-    | '~' expr %prec UNARYOP   { $$ = p_expr_new_branch(YASM_EXPR_NOT, $2); }
-    | '(' expr ')'     { $$ = $2; }
-;
-
-explabel: expr_id      {
-       /* "." references the current assembly position */
-       if ($1[1] == '\0' && $1[0] == '.')
-           $$ = yasm_symtab_define_curpos(p_symtab, ".", parser_gas->prev_bc,
-                                          cur_line);
-       else
-           $$ = yasm_symtab_use(p_symtab, $1, cur_line);
-       yasm_xfree($1);
-    }
-    | expr_id '@' label_id {
-       /* TODO: this is needed for shared objects, e.g. sym@PLT */
-       $$ = yasm_symtab_use(p_symtab, $1, cur_line);
-       yasm_xfree($1);
-       yasm_xfree($3);
-    }
-;
-
-expr_id: label_id
-    | DIR_DATA { $$ = yasm__xstrdup(".data"); }
-    | DIR_TEXT { $$ = yasm__xstrdup(".text"); }
-    | DIR_BSS  { $$ = yasm__xstrdup(".bss"); }
-;
-
-label_id: ID | DIR_ID;
-
-%%
-/*@=usedef =nullassign =memtrans =usereleased =compdef =mustfree@*/
-
-#undef parser_gas
-
-static void
-define_label(yasm_parser_gas *parser_gas, char *name, int local)
-{
-    if (!local) {
-       if (parser_gas->locallabel_base)
-           yasm_xfree(parser_gas->locallabel_base);
-       parser_gas->locallabel_base_len = strlen(name);
-       parser_gas->locallabel_base =
-           yasm_xmalloc(parser_gas->locallabel_base_len+1);
-       strcpy(parser_gas->locallabel_base, name);
-    }
-
-    yasm_symtab_define_label(p_symtab, name, parser_gas->prev_bc, 1,
-                            cur_line);
-    yasm_xfree(name);
-}
-
-static void
-define_lcomm(yasm_parser_gas *parser_gas, /*@only@*/ char *name,
-            yasm_expr *size, /*@null@*/ yasm_expr *align)
-{
-    /* Put into .bss section. */
-    /*@dependent@*/ yasm_section *bss =
-       gas_get_section(parser_gas, yasm__xstrdup(".bss"), NULL, NULL, NULL, 1);
-
-    if (align) {
-       /* XXX: assume alignment is in bytes, not power-of-two */
-       yasm_section_bcs_append(bss, gas_parser_align(parser_gas, bss, align,
-                               NULL, NULL, 0));
-    }
-
-    yasm_symtab_define_label(p_symtab, name, yasm_section_bcs_last(bss), 1,
-                            cur_line);
-    yasm_section_bcs_append(bss, yasm_bc_create_reserve(size, 1, cur_line));
-    yasm_xfree(name);
-}
-
-static yasm_section *
-gas_get_section(yasm_parser_gas *parser_gas, char *name,
-               /*@null@*/ char *flags, /*@null@*/ char *type,
-               /*@null@*/ yasm_valparamhead *objext_valparams,
-               int builtin)
-{
-    yasm_valparamhead vps;
-    yasm_valparam *vp;
-    char *gasflags;
-    yasm_section *new_section;
-
-    yasm_vps_initialize(&vps);
-    vp = yasm_vp_create(name, NULL);
-    yasm_vps_append(&vps, vp);
-
-    if (!builtin) {
-       if (flags) {
-           gasflags = yasm_xmalloc(5+strlen(flags));
-           strcpy(gasflags, "gas_");
-           strcat(gasflags, flags);
-       } else
-           gasflags = yasm__xstrdup("gas_");
-       vp = yasm_vp_create(gasflags, NULL);
-       yasm_vps_append(&vps, vp);
-       if (type) {
-           vp = yasm_vp_create(type, NULL);
-           yasm_vps_append(&vps, vp);
-       }
-    }
-
-    new_section = yasm_objfmt_section_switch(parser_gas->objfmt, &vps,
-                                            objext_valparams, cur_line);
-
-    yasm_vps_delete(&vps);
-    return new_section;
-}
-
-static void
-gas_switch_section(yasm_parser_gas *parser_gas, char *name,
-                  /*@null@*/ char *flags, /*@null@*/ char *type,
-                  /*@null@*/ yasm_valparamhead *objext_valparams,
-                  int builtin)
-{
-    yasm_section *new_section;
-
-    new_section = gas_get_section(parser_gas, yasm__xstrdup(name), flags, type,
-                                 objext_valparams, builtin);
-    if (new_section) {
-       parser_gas->cur_section = new_section;
-       parser_gas->prev_bc = yasm_section_bcs_last(new_section);
-    } else
-       yasm_error_set(YASM_ERROR_GENERAL, N_("invalid section name `%s'"),
-                      name);
-
-    yasm_xfree(name);
-
-    if (objext_valparams)
-       yasm_vps_delete(objext_valparams);
-}
-
-static yasm_bytecode *
-gas_parser_align(yasm_parser_gas *parser_gas, yasm_section *sect,
-                yasm_expr *boundval, /*@null@*/ yasm_expr *fillval,
-                /*@null@*/ yasm_expr *maxskipval, int power2)
-{
-    yasm_intnum *boundintn;
-
-    /* Convert power of two to number of bytes if necessary */
-    if (power2)
-       boundval = yasm_expr_create(YASM_EXPR_SHL,
-                                   yasm_expr_int(yasm_intnum_create_uint(1)),
-                                   yasm_expr_expr(boundval), cur_line);
-
-    /* Largest .align in the section specifies section alignment. */
-    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(sect))
-               yasm_section_set_align(sect, boundint, cur_line);
-       }
-    }
-
-    return yasm_bc_create_align(boundval, fillval, maxskipval,
-                               yasm_section_is_code(sect) ?
-                                   yasm_arch_get_fill(parser_gas->arch) : NULL,
-                               cur_line);
-}
-
-static yasm_bytecode *
-gas_parser_dir_align(yasm_parser_gas *parser_gas, yasm_valparamhead *valparams,
-                    int power2)
-{
-    /*@dependent@*/ yasm_valparam *bound, *fill = NULL, *maxskip = NULL;
-    yasm_expr *boundval, *fillval = NULL, *maxskipval = NULL;
-
-    bound = yasm_vps_first(valparams);
-    boundval = bound->param;
-    bound->param = NULL;
-    if (bound && boundval) {
-       fill = yasm_vps_next(bound);
-    } else {
-       yasm_error_set(YASM_ERROR_SYNTAX,
-                      N_("align directive must specify alignment"));
-       return NULL;
-    }
-
-    if (fill) {
-       fillval = fill->param;
-       fill->param = NULL;
-       maxskip = yasm_vps_next(fill);
-    }
-
-    if (maxskip) {
-       maxskipval = maxskip->param;
-       maxskip->param = NULL;
-    }
-
-    yasm_vps_delete(valparams);
-
-    return gas_parser_align(parser_gas, parser_gas->cur_section, boundval,
-                           fillval, maxskipval, power2);
-}
-
-static yasm_bytecode *
-gas_parser_dir_fill(yasm_parser_gas *parser_gas, /*@only@*/ yasm_expr *repeat,
-                   /*@only@*/ /*@null@*/ yasm_expr *size,
-                   /*@only@*/ /*@null@*/ yasm_expr *value)
-{
-    yasm_datavalhead dvs;
-    yasm_bytecode *bc;
-    unsigned int ssize;
-
-    if (size) {
-       /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
-       intn = yasm_expr_get_intnum(&size, 0);
-       if (!intn) {
-           yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
-                          N_("size must be an absolute expression"));
-           yasm_expr_destroy(repeat);
-           yasm_expr_destroy(size);
-           if (value)
-               yasm_expr_destroy(value);
-           return NULL;
-       }
-       ssize = yasm_intnum_get_uint(intn);
-    } else
-       ssize = 1;
-
-    if (!value)
-       value = yasm_expr_create_ident(
-           yasm_expr_int(yasm_intnum_create_uint(0)), cur_line);
-
-    yasm_dvs_initialize(&dvs);
-    yasm_dvs_append(&dvs, yasm_dv_create_expr(value));
-    bc = yasm_bc_create_data(&dvs, ssize, 0, parser_gas->arch, cur_line);
-
-    yasm_bc_set_multiple(bc, repeat);
-
-    return bc;
-}
-
-static void
-gas_parser_directive(yasm_parser_gas *parser_gas, const char *name,
-                     yasm_valparamhead *valparams,
-                     yasm_valparamhead *objext_valparams)
-{
-    unsigned long line = cur_line;
-
-    /* Handle (mostly) output-format independent directives here */
-    if (!yasm_arch_parse_directive(parser_gas->arch, name, valparams,
-                   objext_valparams, parser_gas->object, line)) {
-       ;
-    } else if (yasm_objfmt_directive(parser_gas->objfmt, name, valparams,
-                                    objext_valparams, line)) {
-       yasm_error_set(YASM_ERROR_GENERAL, N_("unrecognized directive [%s]"),
-                      name);
-    }
-
-    yasm_vps_delete(valparams);
-    if (objext_valparams)
-       yasm_vps_delete(objext_valparams);
-}
diff --git a/modules/parsers/gas/gas-defs.h b/modules/parsers/gas/gas-defs.h
deleted file mode 100644 (file)
index 5991a5f..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/* $Id$
- * Variable name redefinitions for GAS-compatible parser
- *
- *  Copyright (C) 2005  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.
- * 3. Neither the name of the author nor the names of other contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * 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       gas_parser__create_buffer
-#define yy_delete_buffer       gas_parser__delete_buffer
-#define yy_init_buffer         gas_parser__init_buffer
-#define yy_load_buffer_state   gas_parser__load_buffer_state
-#define yy_switch_to_buffer    gas_parser__switch_to_buffer
-#define yyact                  gas_parser_act
-#define yyback                 gas_parser_back
-#define yybgin                 gas_parser_bgin
-#define yychar                 gas_parser_char
-#define yychk                  gas_parser_chk
-#define yycrank                        gas_parser_crank
-#define yydebug                        gas_parser_debug
-#define yydef                  gas_parser_def
-#define yyerrflag              gas_parser_errflag
-#define yyerror                        gas_parser_error
-#define yyestate               gas_parser_estate
-#define yyexca                 gas_parser_exca
-#define yyextra                        gas_parser_extra
-#define yyfnd                  gas_parser_fnd
-#define yyin                   gas_parser_in
-#define yyinput                        gas_parser_input
-#define yyleng                 gas_parser_leng
-#define yylex                  gas_parser_lex
-#define yylineno               gas_parser_lineno
-#define yylook                 gas_parser_look
-#define yylsp                  gas_parser_lsp
-#define yylstate               gas_parser_lstate
-#define yylval                 gas_parser_lval
-#define yymatch                        gas_parser_match
-#define yymorfg                        gas_parser_morfg
-#define yynerrs                        gas_parser_nerrs
-#define yyolsp                 gas_parser_olsp
-#define yyout                  gas_parser_out
-#define yyoutput               gas_parser_output
-#define yypact                 gas_parser_pact
-#define yyparse                        gas_parser_parse
-#define yypgo                  gas_parser_pgo
-#define yyprevious             gas_parser_previous
-#define yyps                   gas_parser_ps
-#define yypv                   gas_parser_pv
-#define yyr1                   gas_parser_r1
-#define yyr2                   gas_parser_r2
-#define yyreds                 gas_parser_reds
-#define yyrestart              gas_parser_restart
-#define yys                    gas_parser_s
-#define yysbuf                 gas_parser_sbuf
-#define yysptr                 gas_parser_sptr
-#define yystate                        gas_parser_state
-#define yysvec                 gas_parser_svec
-#define yytchar                        gas_parser_tchar
-#define yytext                 gas_parser_text
-#define yytmp                  gas_parser_tmp
-#define yytoks                 gas_parser_toks
-#define yytop                  gas_parser_top
-#define yyunput                        gas_parser_unput
-#define yyv                    gas_parser_v
-#define yyval                  gas_parser_val
-#define yyvstop                        gas_parser_vstop
-/*#define yywrap                       gas_parser_wrap*/
diff --git a/modules/parsers/gas/gas-parse.c b/modules/parsers/gas/gas-parse.c
new file mode 100644 (file)
index 0000000..e8cc6e9
--- /dev/null
@@ -0,0 +1,1534 @@
+/*
+ * GAS-compatible parser
+ *
+ *  Copyright (C) 2005  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.
+ * 3. Neither the name of the author nor the names of other contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * 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>
+
+#include <limits.h>
+#include <math.h>
+
+#include "modules/parsers/gas/gas-parser.h"
+
+static yasm_bytecode *parse_line(yasm_parser_gas *parser_gas);
+static yasm_bytecode *parse_instr(yasm_parser_gas *parser_gas);
+static int parse_dirvals(yasm_parser_gas *parser_gas, yasm_valparamhead *vps);
+static int parse_dirstrvals(yasm_parser_gas *parser_gas,
+                           yasm_valparamhead *vps);
+static int parse_datavals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs);
+static int parse_strvals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs);
+static yasm_effaddr *parse_memaddr(yasm_parser_gas *parser_gas);
+static yasm_insn_operand *parse_operand(yasm_parser_gas *parser_gas);
+static yasm_expr *parse_expr(yasm_parser_gas *parser_gas);
+static yasm_expr *parse_expr0(yasm_parser_gas *parser_gas);
+static yasm_expr *parse_expr1(yasm_parser_gas *parser_gas);
+static yasm_expr *parse_expr2(yasm_parser_gas *parser_gas);
+
+static void define_label(yasm_parser_gas *parser_gas, char *name, int local);
+static void define_lcomm(yasm_parser_gas *parser_gas, /*@only@*/ char *name,
+                        yasm_expr *size, /*@null@*/ yasm_expr *align);
+static yasm_section *gas_get_section
+    (yasm_parser_gas *parser_gas, /*@only@*/ char *name, /*@null@*/ char *flags,
+     /*@null@*/ char *type, /*@null@*/ yasm_valparamhead *objext_valparams,
+     int builtin);
+static void gas_switch_section
+    (yasm_parser_gas *parser_gas, /*@only@*/ char *name, /*@null@*/ char *flags,
+     /*@null@*/ char *type, /*@null@*/ yasm_valparamhead *objext_valparams,
+     int builtin);
+static yasm_bytecode *gas_parser_align
+    (yasm_parser_gas *parser_gas, yasm_section *sect, yasm_expr *boundval,
+     /*@null@*/ yasm_expr *fillval, /*@null@*/ yasm_expr *maxskipval,
+     int power2);
+static yasm_bytecode *gas_parser_dir_fill
+    (yasm_parser_gas *parser_gas, /*@only@*/ yasm_expr *repeat,
+     /*@only@*/ /*@null@*/ yasm_expr *size,
+     /*@only@*/ /*@null@*/ yasm_expr *value);
+static void gas_parser_directive
+    (yasm_parser_gas *parser_gas, const char *name,
+     yasm_valparamhead *valparams,
+     /*@null@*/ yasm_valparamhead *objext_valparams);
+
+#define is_eol_tok(tok)        ((tok) == '\n' || (tok) == ';' || (tok) == 0)
+#define is_eol()       is_eol_tok(curtok)
+
+#define get_next_token()    (curtok = gas_parser_lex(&curval, parser_gas))
+
+static void
+get_peek_token(yasm_parser_gas *parser_gas)
+{
+    char savech = parser_gas->tokch;
+    if (parser_gas->peek_token != NONE)
+       yasm_internal_error(N_("only can have one token of lookahead"));
+    parser_gas->peek_token =
+       gas_parser_lex(&parser_gas->peek_tokval, parser_gas);
+    parser_gas->peek_tokch = parser_gas->tokch;
+    parser_gas->tokch = savech;
+}
+
+static void
+destroy_curtok_(yasm_parser_gas *parser_gas)
+{
+    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 ID:
+       case LABEL:
+           yasm_xfree(curval.str_val);
+           break;
+       case STRING:
+           yasm_xfree(curval.str.contents);
+           break;
+       default:
+           break;
+    }
+    curtok = NONE;         /* sanity */
+}
+#define destroy_curtok()    destroy_curtok_(parser_gas)
+
+/* 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_gas *parser_gas)
+{
+    if (is_eol())
+       return;
+
+    yasm_error_set(YASM_ERROR_SYNTAX,
+       N_("junk at end of line, first unrecognized character is `%c'"),
+       parser_gas->tokch);
+
+    do {
+       destroy_curtok();
+       get_next_token();
+    } while (!is_eol());
+}
+#define demand_eol() demand_eol_(parser_gas)
+
+static int
+expect_(yasm_parser_gas *parser_gas, 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 STRING:            str = "expected string"; break;
+       case INSN:              str = "expected instruction"; break;
+       case PREFIX:            str = "expected instruction prefix"; break;
+       case REG:               str = "expected register"; break;
+       case REGGROUP:          str = "expected register group"; 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 ID:                str = "expected identifier"; break;
+       case LABEL:             str = "expected label"; break;
+       case LINE:
+       case DIR_ALIGN:
+       case DIR_ASCII:
+       case DIR_COMM:
+       case DIR_DATA:
+       case DIR_ENDR:
+       case DIR_EXTERN:
+       case DIR_EQU:
+       case DIR_FILE:
+       case DIR_FILL:
+       case DIR_GLOBAL:
+       case DIR_IDENT:
+       case DIR_LEB128:
+       case DIR_LINE:
+       case DIR_LOC:
+       case DIR_LOCAL:
+       case DIR_LCOMM:
+       case DIR_ORG:
+       case DIR_REPT:
+       case DIR_SECTION:
+       case DIR_SECTNAME:
+       case DIR_SIZE:
+       case DIR_SKIP:
+       case DIR_TYPE:
+       case DIR_WEAK:
+       case DIR_ZERO:
+           str = "expected directive";
+           break;
+       default:
+           strch[10] = token;
+           str = strch;
+           break;
+    }
+    yasm_error_set(YASM_ERROR_PARSE, str);
+    destroy_curtok();
+    return 0;
+}
+#define expect(token) expect_(parser_gas, token)
+
+void
+gas_parser_parse(yasm_parser_gas *parser_gas)
+{
+    while (get_next_token() != 0) {
+       yasm_bytecode *bc = NULL, *temp_bc;
+       
+       if (!is_eol()) {
+           bc = parse_line(parser_gas);
+           demand_eol();
+       }
+
+       yasm_errwarn_propagate(parser_gas->errwarns, cur_line);
+
+       temp_bc = yasm_section_bcs_append(parser_gas->cur_section, bc);
+       if (temp_bc)
+           parser_gas->prev_bc = temp_bc;
+       if (curtok == ';')
+           continue;       /* don't advance line number until \n */
+       if (parser_gas->save_input)
+           yasm_linemap_add_source(parser_gas->linemap,
+               temp_bc,
+               (char *)parser_gas->save_line[parser_gas->save_last ^ 1]);
+       yasm_linemap_goto_next(parser_gas->linemap);
+       parser_gas->dir_line++; /* keep track for .line followed by .file */
+    }
+}
+
+static yasm_bytecode *
+parse_line(yasm_parser_gas *parser_gas)
+{
+    yasm_bytecode *bc;
+    yasm_expr *e;
+    yasm_intnum *intn;
+    yasm_datavalhead dvs;
+    yasm_valparamhead vps;
+    yasm_valparam *vp;
+    unsigned int ival;
+    char *id;
+
+    bc = parse_instr(parser_gas);
+    if (bc)
+       return bc;
+
+    switch (curtok) {
+       case ID:
+           id = ID_val;
+           get_next_token(); /* ID */
+           if (curtok == ':') {
+               /* Label */
+               get_next_token(); /* : */
+               define_label(parser_gas, id, 0);
+               return parse_instr(parser_gas);
+           } else if (curtok == '=') {
+               /* EQU */
+               get_next_token(); /* = */
+               e = parse_expr(parser_gas);
+               if (e)
+                   yasm_symtab_define_equ(p_symtab, id, e, cur_line);
+               else
+                   yasm_error_set(YASM_ERROR_SYNTAX,
+                                  N_("expression expected after `%s'"), "=");
+               yasm_xfree(id);
+               return NULL;
+           }
+           /* must be an error at this point */
+           if (id[0] == '.')
+               yasm_warn_set(YASM_WARN_GENERAL,
+                             N_("directive `%s' not recognized"), id);
+           else
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("instruction not recognized: `%s'"), id);
+           yasm_xfree(id);
+           return NULL;
+       case LABEL:
+           define_label(parser_gas, LABEL_val, 0);
+           get_next_token(); /* LABEL */
+           return parse_instr(parser_gas);
+
+       /* Line directive */
+       case DIR_LINE:
+           get_next_token(); /* DIR_LINE */
+
+           if (!expect(INTNUM)) return NULL;
+           if (yasm_intnum_sign(INTNUM_val) < 0) {
+               get_next_token(); /* INTNUM */
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("line number is negative"));
+               return NULL;
+           }
+
+           parser_gas->dir_line = yasm_intnum_get_uint(INTNUM_val);
+           yasm_intnum_destroy(INTNUM_val);
+           get_next_token(); /* INTNUM */
+           if (parser_gas->dir_fileline == 3) {
+               /* Have both file and line */
+               yasm_linemap_set(parser_gas->linemap, NULL,
+                                parser_gas->dir_line, 1);
+           } else if (parser_gas->dir_fileline == 1) {
+               /* Had previous file directive only */
+               parser_gas->dir_fileline = 3;
+               yasm_linemap_set(parser_gas->linemap, parser_gas->dir_file,
+                                parser_gas->dir_line, 1);
+           } else {
+               /* Didn't see file yet */
+               parser_gas->dir_fileline = 2;
+           }
+           return NULL;
+
+       /* Macro directives */
+       case DIR_REPT:
+           get_next_token(); /* DIR_REPT */
+           e = parse_expr(parser_gas);
+           if (!e) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("expression expected after `%s'"),
+                              ".rept");
+               return NULL;
+           }
+           intn = yasm_expr_get_intnum(&e, 0);
+
+           if (!intn) {
+               yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
+                              N_("rept expression not absolute"));
+           } else if (yasm_intnum_sign(intn) < 0) {
+               yasm_error_set(YASM_ERROR_VALUE,
+                              N_("rept expression is negative"));
+           } else {
+               gas_rept *rept = yasm_xmalloc(sizeof(gas_rept));
+               STAILQ_INIT(&rept->lines);
+               rept->startline = cur_line;
+               rept->numrept = yasm_intnum_get_uint(intn);
+               rept->numdone = 0;
+               rept->line = NULL;
+               rept->linepos = 0;
+               rept->ended = 0;
+               rept->oldbuf = NULL;
+               rept->oldbuflen = 0;
+               rept->oldbufpos = 0;
+               parser_gas->rept = rept;
+           }
+           return NULL;
+       case DIR_ENDR:
+           get_next_token(); /* DIR_ENDR */
+           /* Shouldn't ever get here unless we didn't get a DIR_REPT first */
+           yasm_error_set(YASM_ERROR_SYNTAX, N_("endr without matching rept"));
+           return NULL;
+
+       /* Alignment directives */
+       case DIR_ALIGN:
+       {
+           yasm_expr *bound, *fill=NULL, *maxskip=NULL;
+
+           ival = DIR_ALIGN_val;
+           get_next_token(); /* DIR_ALIGN */
+
+           bound = parse_expr(parser_gas);
+           if (!bound) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_(".align directive must specify alignment"));
+               return NULL;
+           }
+
+           if (curtok == ',') {
+               get_next_token(); /* ',' */
+               fill = parse_expr(parser_gas);
+               if (curtok == ',') {
+                   get_next_token(); /* ',' */
+                   maxskip = parse_expr(parser_gas);
+               }
+           }
+
+           return gas_parser_align(parser_gas, parser_gas->cur_section, bound,
+                                   fill, maxskip, (int)ival);
+       }
+       case DIR_ORG:
+           get_next_token(); /* DIR_ORG */
+           if (!expect(INTNUM)) return NULL;
+           /* TODO: support expr instead of intnum */
+           bc = yasm_bc_create_org(yasm_intnum_get_uint(INTNUM_val), cur_line);
+           yasm_intnum_destroy(INTNUM_val);
+           get_next_token(); /* INTNUM */
+           return bc;
+    
+       /* Data visibility directives */
+       case DIR_LOCAL:
+           get_next_token(); /* DIR_LOCAL */
+           if (!expect(ID)) return NULL;
+           yasm_symtab_declare(parser_gas->symtab, ID_val, YASM_SYM_DLOCAL,
+                               cur_line);
+           yasm_xfree(ID_val);
+           get_next_token(); /* ID */
+           return NULL;
+       case DIR_GLOBAL:
+           get_next_token(); /* DIR_GLOBAL */
+           if (!expect(ID)) return NULL;
+           yasm_objfmt_global_declare(parser_gas->objfmt, ID_val, NULL,
+                                      cur_line);
+           yasm_xfree(ID_val);
+           get_next_token(); /* ID */
+           return NULL;
+       case DIR_COMM:
+       case DIR_LCOMM:
+       {
+           yasm_expr *align = NULL;
+           /*@null@*/ /*@dependent@*/ yasm_symrec *sym;
+           int is_lcomm = curtok == DIR_LCOMM;
+
+           get_next_token(); /* DIR_LOCAL */
+
+           if (!expect(ID)) return NULL;
+           id = ID_val;
+           get_next_token(); /* ID */
+           if (!expect(',')) {
+               yasm_xfree(id);
+               return NULL;
+           }
+           get_next_token(); /* , */
+           e = parse_expr(parser_gas);
+           if (!e) {
+               yasm_error_set(YASM_ERROR_SYNTAX, N_("size expected for `%s'"),
+                              ".COMM");
+               return NULL;
+           }
+           if (curtok == ',') {
+               /* Optional alignment expression */
+               get_next_token(); /* ',' */
+               align = parse_expr(parser_gas);
+           }
+           /* If already explicitly declared local, treat like LCOMM */
+           if (is_lcomm
+               || ((sym = yasm_symtab_get(parser_gas->symtab, id))
+                   && yasm_symrec_get_visibility(sym) == YASM_SYM_DLOCAL)) {
+               define_lcomm(parser_gas, id, e, align);
+           } else if (align) {
+               /* Give third parameter as objext valparam */
+               yasm_vps_initialize(&vps);
+               vp = yasm_vp_create(NULL, align);
+               yasm_vps_append(&vps, vp);
+
+               yasm_objfmt_common_declare(parser_gas->objfmt, id, e, &vps,
+                                          cur_line);
+
+               yasm_vps_delete(&vps);
+               yasm_xfree(id);
+           } else {
+               yasm_objfmt_common_declare(parser_gas->objfmt, id, e, NULL,
+                                          cur_line);
+               yasm_xfree(id);
+           }
+           return NULL;
+       }
+       case DIR_EXTERN:
+           get_next_token(); /* DIR_EXTERN */
+           if (!expect(ID)) return NULL;
+           /* Go ahead and do it, even though all undef become extern */
+           yasm_objfmt_extern_declare(parser_gas->objfmt, ID_val, NULL,
+                                      cur_line);
+           yasm_xfree(ID_val);
+           get_next_token(); /* ID */
+           return NULL;
+       case DIR_WEAK:
+           get_next_token(); /* DIR_EXTERN */
+           if (!expect(ID)) return NULL;
+
+           yasm_vps_initialize(&vps);
+           vp = yasm_vp_create(ID_val, NULL);
+           yasm_vps_append(&vps, vp);
+           get_next_token(); /* ID */
+
+           yasm_objfmt_directive(parser_gas->objfmt, "weak", &vps, NULL,
+                                 cur_line);
+
+           yasm_vps_delete(&vps);
+           return NULL;
+
+       /* Integer data definition directives */
+       case DIR_ASCII:
+           ival = DIR_ASCII_val;
+           get_next_token(); /* DIR_ASCII */
+           if (!parse_strvals(parser_gas, &dvs))
+               return NULL;
+           return yasm_bc_create_data(&dvs, 1, (int)ival, parser_gas->arch,
+                                      cur_line);
+       case DIR_DATA:
+           ival = DIR_DATA_val;
+           get_next_token(); /* DIR_DATA */
+           if (!parse_datavals(parser_gas, &dvs))
+               return NULL;
+           return yasm_bc_create_data(&dvs, ival, 0, parser_gas->arch,
+                                      cur_line);
+       case DIR_LEB128:
+           ival = DIR_LEB128_val;
+           get_next_token(); /* DIR_LEB128 */
+           if (!parse_datavals(parser_gas, &dvs))
+               return NULL;
+           return yasm_bc_create_leb128(&dvs, (int)ival, cur_line);
+
+       /* Empty space / fill data definition directives */
+       case DIR_ZERO:
+           get_next_token(); /* DIR_ZERO */
+           e = parse_expr(parser_gas);
+           if (!e) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("expression expected after `%s'"), ".ZERO");
+               return NULL;
+           }
+
+           yasm_dvs_initialize(&dvs);
+           yasm_dvs_append(&dvs, yasm_dv_create_expr(
+               p_expr_new_ident(yasm_expr_int(yasm_intnum_create_uint(0)))));
+           bc = yasm_bc_create_data(&dvs, 1, 0, parser_gas->arch, cur_line);
+           yasm_bc_set_multiple(bc, e);
+           return bc;
+       case DIR_SKIP:
+       {
+           yasm_expr *e_val;
+
+           get_next_token(); /* DIR_SKIP */
+           e = parse_expr(parser_gas);
+           if (!e) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("expression expected after `%s'"), ".SKIP");
+               return NULL;
+           }
+           if (curtok != ',')
+               return yasm_bc_create_reserve(e, 1, cur_line);
+           get_next_token(); /* ',' */
+           e_val = parse_expr(parser_gas);
+           yasm_dvs_initialize(&dvs);
+           yasm_dvs_append(&dvs, yasm_dv_create_expr(e_val));
+           bc = yasm_bc_create_data(&dvs, 1, 0, parser_gas->arch, cur_line);
+
+           yasm_bc_set_multiple(bc, e);
+           return bc;
+       }
+
+       /* fill data definition directive */
+       case DIR_FILL:
+       {
+           yasm_expr *sz=NULL, *val=NULL;
+           get_next_token(); /* DIR_FILL */
+           e = parse_expr(parser_gas);
+           if (!e) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("expression expected after `%s'"), ".FILL");
+               return NULL;
+           }
+           if (curtok == ',') {
+               get_next_token(); /* ',' */
+               sz = parse_expr(parser_gas);
+               if (curtok == ',') {
+                   get_next_token(); /* ',' */
+                   val = parse_expr(parser_gas);
+               }
+           }
+           return gas_parser_dir_fill(parser_gas, e, sz, val);
+       }
+
+       /* Section directives */
+       case DIR_SECTNAME:
+           gas_switch_section(parser_gas, DIR_SECTNAME_val, NULL, NULL, NULL,
+                              1);
+           get_next_token(); /* DIR_SECTNAME */
+           return NULL;
+       case DIR_SECTION:
+       {
+           /* DIR_SECTION ID ',' STRING ',' '@' ID ',' dirvals */
+           char *sectname, *flags = NULL, *type = NULL;
+           yasm_valparamhead objext_vps;
+           int have_vps = 0;
+
+           get_next_token(); /* DIR_SECTION */
+
+           if (!expect(ID)) return NULL;
+           sectname = ID_val;
+           get_next_token(); /* ID */
+
+           if (curtok == ',') {
+               get_next_token(); /* ',' */
+               if (!expect(STRING)) {
+                   yasm_error_set(YASM_ERROR_SYNTAX,
+                                  N_("flag string expected"));
+                   yasm_xfree(sectname);
+                   return NULL;
+               }
+               flags = STRING_val.contents;
+               get_next_token(); /* STRING */
+           }
+
+           if (curtok == ',') {
+               get_next_token(); /* ',' */
+               if (!expect('@')) {
+                   yasm_xfree(sectname);
+                   yasm_xfree(flags);
+                   return NULL;
+               }
+               get_next_token(); /* '@' */
+               if (!expect(ID)) {
+                   yasm_xfree(sectname);
+                   yasm_xfree(flags);
+                   return NULL;
+               }
+               type = ID_val;
+               get_next_token(); /* ID */
+           }
+
+           if (curtok == ',') {
+               get_next_token(); /* ',' */
+               if (parse_dirvals(parser_gas, &vps))
+                   have_vps = 1;
+           }
+
+           gas_switch_section(parser_gas, sectname, flags, type,
+                              have_vps ? &vps : NULL, 0);
+           yasm_xfree(flags);
+           return NULL;
+       }
+
+       /* Other directives */
+       case DIR_IDENT:
+           get_next_token(); /* DIR_IDENT */
+           if (!parse_dirstrvals(parser_gas, &vps))
+               return NULL;
+           yasm_objfmt_directive(parser_gas->objfmt, "ident", &vps, NULL,
+                                 cur_line);
+           yasm_vps_delete(&vps);
+           return NULL;
+       case DIR_FILE:
+           get_next_token(); /* DIR_FILE */
+           if (curtok == STRING) {
+               /* No file number; this form also sets the assembler's
+                * internal line number.
+                */
+               char *filename = STRING_val.contents;
+               get_next_token(); /* STRING */
+               if (parser_gas->dir_fileline == 3) {
+                   /* Have both file and line */
+                   const char *old_fn;
+                   unsigned long old_line;
+
+                   yasm_linemap_lookup(parser_gas->linemap, cur_line, &old_fn,
+                                       &old_line);
+                   yasm_linemap_set(parser_gas->linemap, filename, old_line,
+                                    1);
+               } else if (parser_gas->dir_fileline == 2) {
+                   /* Had previous line directive only */
+                   parser_gas->dir_fileline = 3;
+                   yasm_linemap_set(parser_gas->linemap, filename,
+                                    parser_gas->dir_line, 1);
+               } else {
+                   /* Didn't see line yet, save file */
+                   parser_gas->dir_fileline = 1;
+                   if (parser_gas->dir_file)
+                       yasm_xfree(parser_gas->dir_file);
+                   parser_gas->dir_file = yasm__xstrdup(filename);
+               }
+
+               /* Pass change along to debug format */
+               yasm_vps_initialize(&vps);
+               vp = yasm_vp_create(filename, NULL);
+               yasm_vps_append(&vps, vp);
+
+               yasm_dbgfmt_directive(parser_gas->dbgfmt, "file",
+                                     parser_gas->cur_section, &vps, cur_line);
+
+               yasm_vps_delete(&vps);
+               return NULL;
+           }
+
+           /* fileno filename form */
+           yasm_vps_initialize(&vps);
+
+           if (!expect(INTNUM)) return NULL;
+           vp = yasm_vp_create(NULL,
+                               p_expr_new_ident(yasm_expr_int(INTNUM_val)));
+           yasm_vps_append(&vps, vp);
+           get_next_token(); /* INTNUM */
+
+           if (!expect(STRING)) {
+               yasm_vps_delete(&vps);
+               return NULL;
+           }
+           vp = yasm_vp_create(STRING_val.contents, NULL);
+           yasm_vps_append(&vps, vp);
+           get_next_token(); /* STRING */
+
+           yasm_dbgfmt_directive(parser_gas->dbgfmt, "file",
+                                 parser_gas->cur_section, &vps, cur_line);
+
+           yasm_vps_delete(&vps);
+           return NULL;
+       case DIR_LOC:
+           /* INTNUM INTNUM INTNUM */
+           get_next_token(); /* DIR_LOC */
+           yasm_vps_initialize(&vps);
+
+           if (!expect(INTNUM)) return NULL;
+           vp = yasm_vp_create(NULL,
+                               p_expr_new_ident(yasm_expr_int(INTNUM_val)));
+           yasm_vps_append(&vps, vp);
+           get_next_token(); /* INTNUM */
+
+           if (!expect(INTNUM)) {
+               yasm_vps_delete(&vps);
+               return NULL;
+           }
+           vp = yasm_vp_create(NULL,
+                               p_expr_new_ident(yasm_expr_int(INTNUM_val)));
+           yasm_vps_append(&vps, vp);
+           get_next_token(); /* INTNUM */
+
+           if (!expect(INTNUM)) {
+               yasm_vps_delete(&vps);
+               return NULL;
+           }
+           vp = yasm_vp_create(NULL,
+                               p_expr_new_ident(yasm_expr_int(INTNUM_val)));
+           yasm_vps_append(&vps, vp);
+           get_next_token(); /* INTNUM */
+
+           yasm_dbgfmt_directive(parser_gas->dbgfmt, "loc",
+                                 parser_gas->cur_section, &vps, cur_line);
+
+           yasm_vps_delete(&vps);
+           return NULL;
+       case DIR_TYPE:
+           /* ID ',' '@' ID */
+           get_next_token(); /* DIR_TYPE */
+           yasm_vps_initialize(&vps);
+
+           if (!expect(ID)) return NULL;
+           vp = yasm_vp_create(ID_val, NULL);
+           yasm_vps_append(&vps, vp);
+           get_next_token(); /* ID */
+
+           if (!expect(',')) {
+               yasm_vps_delete(&vps);
+               return NULL;
+           }
+           get_next_token(); /* ',' */
+
+           if (!expect('@')) {
+               yasm_vps_delete(&vps);
+               return NULL;
+           }
+           get_next_token(); /* '@' */
+
+           if (!expect(ID)) {
+               yasm_vps_delete(&vps);
+               return NULL;
+           }
+           vp = yasm_vp_create(ID_val, NULL);
+           yasm_vps_append(&vps, vp);
+           get_next_token(); /* ID */
+
+           yasm_objfmt_directive(parser_gas->objfmt, "type", &vps, NULL,
+                                 cur_line);
+
+           yasm_vps_delete(&vps);
+           return NULL;
+       case DIR_SIZE:
+           /* ID ',' expr */
+           get_next_token(); /* DIR_SIZE */
+           yasm_vps_initialize(&vps);
+
+           if (!expect(ID)) return NULL;
+           vp = yasm_vp_create(ID_val, NULL);
+           yasm_vps_append(&vps, vp);
+           get_next_token(); /* ID */
+
+           if (!expect(',')) {
+               yasm_vps_delete(&vps);
+               return NULL;
+           }
+           get_next_token(); /* ',' */
+
+           e = parse_expr(parser_gas);
+           if (!e) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("expression expected for `.size'"));
+               yasm_vps_delete(&vps);
+               return NULL;
+           }
+           vp = yasm_vp_create(NULL, e);
+           yasm_vps_append(&vps, vp);
+
+           yasm_objfmt_directive(parser_gas->objfmt, "size", &vps, NULL,
+                                 cur_line);
+
+           yasm_vps_delete(&vps);
+           return NULL;
+       default:
+           yasm_error_set(YASM_ERROR_SYNTAX,
+               N_("label or instruction expected at start of line"));
+           return NULL;
+    }
+}
+
+static yasm_bytecode *
+parse_instr(yasm_parser_gas *parser_gas)
+{
+    yasm_bytecode *bc;
+
+    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_gas->arch, insn.arch_data,
+                                          0, NULL, cur_line);
+           }
+
+           /* parse operands */
+           yasm_ops_initialize(&operands);
+           for (;;) {
+               yasm_insn_operand *op = parse_operand(parser_gas);
+               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_gas->arch, insn.arch_data,
+                                      num_operands, &operands, cur_line);
+       }
+       case PREFIX:
+       {
+           yystype prefix = curval;    /* structure copy */
+           get_next_token(); /* PREFIX */
+           bc = parse_instr(parser_gas);
+           if (!bc)
+               bc = yasm_bc_create_empty_insn(parser_gas->arch, cur_line);
+           yasm_bc_insn_add_prefix(bc, prefix.arch_data);
+           return bc;
+       }
+       case SEGREG:
+       {
+           unsigned long segreg = SEGREG_val[0];
+           get_next_token(); /* SEGREG */
+           bc = parse_instr(parser_gas);
+           if (!bc)
+               bc = yasm_bc_create_empty_insn(parser_gas->arch, cur_line);
+           yasm_bc_insn_add_seg_prefix(bc, segreg);
+       }
+       default:
+           return NULL;
+    }
+}
+
+static int
+parse_dirvals(yasm_parser_gas *parser_gas, yasm_valparamhead *vps)
+{
+    yasm_expr *e;
+    yasm_valparam *vp;
+    int num = 0;
+
+    yasm_vps_initialize(vps);
+
+    for (;;) {
+       e = parse_expr(parser_gas);
+       vp = yasm_vp_create(NULL, e);
+       yasm_vps_append(vps, vp);
+       num++;
+       if (curtok != ',')
+           break;
+       get_next_token(); /* ',' */
+    }
+    return num;
+}
+
+static int
+parse_dirstrvals(yasm_parser_gas *parser_gas, yasm_valparamhead *vps)
+{
+    char *s;
+    yasm_valparam *vp;
+    int num = 0;
+
+    yasm_vps_initialize(vps);
+
+    for (;;) {
+       if (!expect(STRING)) {
+           yasm_vps_delete(vps);
+           yasm_vps_initialize(vps);
+           return 0;
+       }
+       vp = yasm_vp_create(STRING_val.contents, NULL);
+       yasm_vps_append(vps, vp);
+       get_next_token(); /* STRING */
+       num++;
+       if (curtok != ',')
+           break;
+       get_next_token(); /* ',' */
+    }
+    return num;
+}
+
+static int
+parse_datavals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs)
+{
+    yasm_expr *e;
+    yasm_dataval *dv;
+    int num = 0;
+
+    yasm_dvs_initialize(dvs);
+
+    for (;;) {
+       e = parse_expr(parser_gas);
+       if (!e) {
+           yasm_dvs_delete(dvs);
+           yasm_dvs_initialize(dvs);
+           return 0;
+       }
+       dv = yasm_dv_create_expr(e);
+       yasm_dvs_append(dvs, dv);
+       num++;
+       if (curtok != ',')
+           break;
+       get_next_token(); /* ',' */
+    }
+    return num;
+}
+
+static int
+parse_strvals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs)
+{
+    char *s;
+    yasm_dataval *dv;
+    int num = 0;
+
+    yasm_dvs_initialize(dvs);
+
+    for (;;) {
+       if (!expect(STRING)) {
+           yasm_dvs_delete(dvs);
+           yasm_dvs_initialize(dvs);
+           return 0;
+       }
+       dv = yasm_dv_create_string(STRING_val.contents, STRING_val.len);
+       yasm_dvs_append(dvs, dv);
+       get_next_token(); /* STRING */
+       num++;
+       if (curtok != ',')
+           break;
+       get_next_token(); /* ',' */
+    }
+    return num;
+}
+
+/* instruction operands */
+/* memory addresses */
+static yasm_effaddr *
+parse_memaddr(yasm_parser_gas *parser_gas)
+{
+    yasm_effaddr *ea = NULL;
+    yasm_expr *e1, *e2;
+    int strong = 0;
+
+    if (curtok == SEGREG) {
+       unsigned long segreg = SEGREG_val[0];
+       get_next_token(); /* SEGREG */
+       if (!expect(':')) return NULL;
+       get_next_token(); /* ':' */
+       ea = parse_memaddr(parser_gas);
+       if (!ea)
+           return NULL;
+       yasm_ea_set_segreg(ea, segreg);
+       return ea;
+    }
+
+    /* We want to parse a leading expression, except when it's actually
+     * just a memory address (with no preceding expression) such as
+     * (REG...) or (,...).
+     */
+    get_peek_token(parser_gas);
+    if (curtok != '(' || (parser_gas->peek_token != REG
+                         && parser_gas->peek_token != ','))
+       e1 = parse_expr(parser_gas);
+    else
+       e1 = NULL;
+
+    if (curtok == '(') {
+       unsigned long reg = ULONG_MAX;
+       yasm_intnum *scale = NULL;
+
+       get_next_token(); /* '(' */
+
+       /* base register */
+       if (curtok == REG) {
+           e2 = p_expr_new_ident(yasm_expr_reg(REG_val[0]));
+           get_next_token(); /* REG */
+       } else
+           e2 = p_expr_new_ident(yasm_expr_int(yasm_intnum_create_uint(0)));
+
+       if (curtok == ')')
+           goto done;
+
+       if (!expect(',')) {
+           yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid memory expression"));
+           if (e1) yasm_expr_destroy(e1);
+           yasm_expr_destroy(e2);
+           return NULL;
+       }
+       get_next_token(); /* ',' */
+
+       if (curtok == ')')
+           goto done;
+
+       /* index register */
+       if (curtok == REG) {
+           reg = REG_val[0];
+           get_next_token(); /* REG */
+           if (curtok != ',') {
+               scale = yasm_intnum_create_uint(1);
+               goto done;
+           }
+           get_next_token(); /* ',' */
+       }
+
+       /* scale */
+       if (!expect(INTNUM)) {
+           yasm_error_set(YASM_ERROR_SYNTAX, N_("non-integer scale"));
+           if (e1) yasm_expr_destroy(e1);
+           yasm_expr_destroy(e2);
+           return NULL;
+       }
+       scale = INTNUM_val;
+       get_next_token(); /* INTNUM */
+
+done:
+       if (!expect(')')) {
+           yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid memory expression"));
+           if (scale) yasm_intnum_destroy(scale);
+           if (e1) yasm_expr_destroy(e1);
+           yasm_expr_destroy(e2);
+           return NULL;
+       }
+       get_next_token(); /* ')' */
+
+       if (scale) {
+           if (reg == ULONG_MAX) {
+               if (yasm_intnum_get_uint(scale) != 1)
+                   yasm_warn_set(YASM_WARN_GENERAL,
+                       N_("scale factor of %u without an index register"),
+                       yasm_intnum_get_uint(scale));
+               yasm_intnum_destroy(scale);
+           } else
+               e2 = p_expr_new(yasm_expr_expr(e2), YASM_EXPR_ADD,
+                   yasm_expr_expr(p_expr_new(yasm_expr_reg(reg), YASM_EXPR_MUL,
+                                             yasm_expr_int(scale))));
+       }
+
+       if (e1) {
+           /* Ordering is critical here to correctly detecting presence of
+            * RIP in RIP-relative expressions.
+            */
+           e1 = p_expr_new_tree(e2, YASM_EXPR_ADD, e1);
+       } else
+           e1 = e2;
+       strong = 1;
+    }
+
+    if (!e1)
+       return NULL;
+    ea = yasm_arch_ea_create(parser_gas->arch, e1);
+    if (strong)
+       yasm_ea_set_strong(ea, 1);
+    return ea;
+}
+
+static yasm_insn_operand *
+parse_operand(yasm_parser_gas *parser_gas)
+{
+    yasm_effaddr *ea;
+    yasm_insn_operand *op;
+    unsigned long reg;
+
+    switch (curtok) {
+       case REG:
+           reg = REG_val[0];
+           get_next_token(); /* REG */
+           return yasm_operand_create_reg(reg);
+       case SEGREG:
+           /* need to see if it's really a memory address */
+           get_peek_token(parser_gas);
+           if (parser_gas->peek_token == ':') {
+               ea = parse_memaddr(parser_gas);
+               if (!ea)
+                   return NULL;
+               return yasm_operand_create_mem(ea);
+           }
+           reg = SEGREG_val[0];
+           get_next_token(); /* SEGREG */
+           return yasm_operand_create_segreg(reg);
+       case REGGROUP:
+       {
+           unsigned long regindex;
+           reg = REGGROUP_val[0];
+           get_next_token(); /* REGGROUP */
+           if (curtok != '(')
+               return yasm_operand_create_reg(reg);
+           get_next_token(); /* '(' */
+           if (!expect(INTNUM)) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("integer register index expected"));
+               return NULL;
+           }
+           regindex = yasm_intnum_get_uint(INTNUM_val);
+           get_next_token(); /* INTNUM */
+           if (!expect(')')) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                   N_("missing closing parenthesis for register index"));
+               return NULL;
+           }
+           get_next_token(); /* ')' */
+           reg = yasm_arch_reggroup_get_reg(parser_gas->arch, reg, regindex);
+           if (reg == 0) {
+               yasm_error_set(YASM_ERROR_SYNTAX, N_("bad register index `%u'"),
+                              regindex);
+               return NULL;
+           }
+           return yasm_operand_create_reg(reg);
+       }
+       case '$':
+       {
+           yasm_expr *e;
+           get_next_token(); /* '$' */
+           e = parse_expr(parser_gas);
+           if (!e) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("expression missing after `%s'"), "$");
+               return NULL;
+           }
+           return yasm_operand_create_imm(e);
+       }
+       case '*':
+           get_next_token(); /* '*' */
+           if (curtok == REG) {
+               op = yasm_operand_create_reg(REG_val[0]);
+               get_next_token(); /* REG */
+           } else {
+               ea = parse_memaddr(parser_gas);
+               if (!ea) {
+                   yasm_error_set(YASM_ERROR_SYNTAX,
+                                  N_("expression missing after `%s'"), "*");
+                   return NULL;
+               }
+               op = yasm_operand_create_mem(ea);
+           }
+           op->deref = 1;
+           return op;
+       default:
+           ea = parse_memaddr(parser_gas);
+           if (!ea)
+               return NULL;
+           return yasm_operand_create_mem(ea);
+    }
+}
+
+/* Expression grammar parsed is:
+ *
+ * expr  : expr0 [ {+,-} expr0...]
+ * expr0 : expr1 [ {|,^,&,!} expr1...]
+ * expr1 : expr2 [ {*,/,%,<<,>>} expr2...]
+ * expr2 : { ~,+,- } expr2
+ *       | (expr)
+ *       | symbol
+ *       | number
+ */
+
+static yasm_expr *
+parse_expr(yasm_parser_gas *parser_gas)
+{
+    yasm_expr *e, *f;
+    e = parse_expr0(parser_gas);
+    if (!e)
+       return NULL;
+
+    while (curtok == '+' || curtok == '-') {
+       int op = curtok;
+       get_next_token();
+       f = parse_expr0(parser_gas);
+       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_expr0(yasm_parser_gas *parser_gas)
+{
+    yasm_expr *e, *f;
+    e = parse_expr1(parser_gas);
+    if (!e)
+       return NULL;
+
+    while (curtok == '|' || curtok == '^' || curtok == '&' || curtok == '!') {
+       int op = curtok;
+       get_next_token();
+       f = parse_expr1(parser_gas);
+       if (!f) {
+           yasm_expr_destroy(e);
+           return NULL;
+       }
+
+       switch (op) {
+           case '|': e = p_expr_new_tree(e, YASM_EXPR_OR, f); break;
+           case '^': e = p_expr_new_tree(e, YASM_EXPR_XOR, f); break;
+           case '&': e = p_expr_new_tree(e, YASM_EXPR_AND, f); break;
+           case '!': e = p_expr_new_tree(e, YASM_EXPR_NOR, f); break;
+       }
+    }
+    return e;
+}
+
+static yasm_expr *
+parse_expr1(yasm_parser_gas *parser_gas)
+{
+    yasm_expr *e, *f;
+    e = parse_expr2(parser_gas);
+    if (!e)
+       return NULL;
+
+    while (curtok == '*' || curtok == '/' || curtok == '%' || curtok == LEFT_OP
+          || curtok == RIGHT_OP) {
+       int op = curtok;
+       get_next_token();
+       f = parse_expr2(parser_gas);
+       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 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_expr2(yasm_parser_gas *parser_gas)
+{
+    yasm_expr *e;
+    yasm_symrec *sym;
+
+    switch (curtok) {
+       case '+':
+           get_next_token();
+           return parse_expr2(parser_gas);
+       case '-':
+           get_next_token();
+           e = parse_expr2(parser_gas);
+           if (!e)
+               return NULL;
+           return p_expr_new_branch(YASM_EXPR_NEG, e);
+       case '~':
+           get_next_token();
+           e = parse_expr2(parser_gas);
+           if (!e)
+               return NULL;
+           return p_expr_new_branch(YASM_EXPR_NOT, e);
+       case '(':
+           get_next_token();
+           e = parse_expr(parser_gas);
+           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));
+           get_next_token();
+           return e;
+       case FLTNUM:
+           e = p_expr_new_ident(yasm_expr_float(FLTNUM_val));
+           get_next_token();
+           return e;
+       case ID:
+       case DIR_SECTNAME:
+       {
+           char *name = ID_val;
+           get_next_token(); /* ID */
+           if (curtok == '@') {
+               /* TODO: this is needed for shared objects, e.g. sym@PLT */
+               get_next_token(); /* '@' */
+               if (!expect(ID)) {
+                   yasm_error_set(YASM_ERROR_SYNTAX,
+                                  N_("expected identifier after `@'"));
+                   yasm_xfree(name);
+                   return NULL;
+               }
+               yasm_xfree(ID_val);
+               get_next_token(); /* ID */
+               sym = yasm_symtab_use(p_symtab, name, cur_line);
+               yasm_xfree(name);
+               return p_expr_new_ident(yasm_expr_sym(sym));
+           }
+
+           /* "." references the current assembly position */
+           if (name[1] == '\0' && name[0] == '.')
+               sym = yasm_symtab_define_curpos(p_symtab, ".",
+                                               parser_gas->prev_bc, cur_line);
+           else
+               sym = yasm_symtab_use(p_symtab, name, cur_line);
+           yasm_xfree(name);
+           return p_expr_new_ident(yasm_expr_sym(sym));
+       }
+       default:
+           return NULL;
+    }
+}
+
+static void
+define_label(yasm_parser_gas *parser_gas, char *name, int local)
+{
+    if (!local) {
+       if (parser_gas->locallabel_base)
+           yasm_xfree(parser_gas->locallabel_base);
+       parser_gas->locallabel_base_len = strlen(name);
+       parser_gas->locallabel_base =
+           yasm_xmalloc(parser_gas->locallabel_base_len+1);
+       strcpy(parser_gas->locallabel_base, name);
+    }
+
+    yasm_symtab_define_label(p_symtab, name, parser_gas->prev_bc, 1,
+                            cur_line);
+    yasm_xfree(name);
+}
+
+static void
+define_lcomm(yasm_parser_gas *parser_gas, /*@only@*/ char *name,
+            yasm_expr *size, /*@null@*/ yasm_expr *align)
+{
+    /* Put into .bss section. */
+    /*@dependent@*/ yasm_section *bss =
+       gas_get_section(parser_gas, yasm__xstrdup(".bss"), NULL, NULL, NULL, 1);
+
+    if (align) {
+       /* XXX: assume alignment is in bytes, not power-of-two */
+       yasm_section_bcs_append(bss, gas_parser_align(parser_gas, bss, align,
+                               NULL, NULL, 0));
+    }
+
+    yasm_symtab_define_label(p_symtab, name, yasm_section_bcs_last(bss), 1,
+                            cur_line);
+    yasm_section_bcs_append(bss, yasm_bc_create_reserve(size, 1, cur_line));
+    yasm_xfree(name);
+}
+
+static yasm_section *
+gas_get_section(yasm_parser_gas *parser_gas, char *name,
+               /*@null@*/ char *flags, /*@null@*/ char *type,
+               /*@null@*/ yasm_valparamhead *objext_valparams,
+               int builtin)
+{
+    yasm_valparamhead vps;
+    yasm_valparam *vp;
+    char *gasflags;
+    yasm_section *new_section;
+
+    yasm_vps_initialize(&vps);
+    vp = yasm_vp_create(name, NULL);
+    yasm_vps_append(&vps, vp);
+
+    if (!builtin) {
+       if (flags) {
+           gasflags = yasm_xmalloc(5+strlen(flags));
+           strcpy(gasflags, "gas_");
+           strcat(gasflags, flags);
+       } else
+           gasflags = yasm__xstrdup("gas_");
+       vp = yasm_vp_create(gasflags, NULL);
+       yasm_vps_append(&vps, vp);
+       if (type) {
+           vp = yasm_vp_create(type, NULL);
+           yasm_vps_append(&vps, vp);
+       }
+    }
+
+    new_section = yasm_objfmt_section_switch(parser_gas->objfmt, &vps,
+                                            objext_valparams, cur_line);
+
+    yasm_vps_delete(&vps);
+    return new_section;
+}
+
+static void
+gas_switch_section(yasm_parser_gas *parser_gas, char *name,
+                  /*@null@*/ char *flags, /*@null@*/ char *type,
+                  /*@null@*/ yasm_valparamhead *objext_valparams,
+                  int builtin)
+{
+    yasm_section *new_section;
+
+    new_section = gas_get_section(parser_gas, yasm__xstrdup(name), flags, type,
+                                 objext_valparams, builtin);
+    if (new_section) {
+       parser_gas->cur_section = new_section;
+       parser_gas->prev_bc = yasm_section_bcs_last(new_section);
+    } else
+       yasm_error_set(YASM_ERROR_GENERAL, N_("invalid section name `%s'"),
+                      name);
+
+    yasm_xfree(name);
+
+    if (objext_valparams)
+       yasm_vps_delete(objext_valparams);
+}
+
+static yasm_bytecode *
+gas_parser_align(yasm_parser_gas *parser_gas, yasm_section *sect,
+                yasm_expr *boundval, /*@null@*/ yasm_expr *fillval,
+                /*@null@*/ yasm_expr *maxskipval, int power2)
+{
+    yasm_intnum *boundintn;
+
+    /* Convert power of two to number of bytes if necessary */
+    if (power2)
+       boundval = yasm_expr_create(YASM_EXPR_SHL,
+                                   yasm_expr_int(yasm_intnum_create_uint(1)),
+                                   yasm_expr_expr(boundval), cur_line);
+
+    /* Largest .align in the section specifies section alignment. */
+    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(sect))
+               yasm_section_set_align(sect, boundint, cur_line);
+       }
+    }
+
+    return yasm_bc_create_align(boundval, fillval, maxskipval,
+                               yasm_section_is_code(sect) ?
+                                   yasm_arch_get_fill(parser_gas->arch) : NULL,
+                               cur_line);
+}
+
+static yasm_bytecode *
+gas_parser_dir_fill(yasm_parser_gas *parser_gas, /*@only@*/ yasm_expr *repeat,
+                   /*@only@*/ /*@null@*/ yasm_expr *size,
+                   /*@only@*/ /*@null@*/ yasm_expr *value)
+{
+    yasm_datavalhead dvs;
+    yasm_bytecode *bc;
+    unsigned int ssize;
+
+    if (size) {
+       /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
+       intn = yasm_expr_get_intnum(&size, 0);
+       if (!intn) {
+           yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
+                          N_("size must be an absolute expression"));
+           yasm_expr_destroy(repeat);
+           yasm_expr_destroy(size);
+           if (value)
+               yasm_expr_destroy(value);
+           return NULL;
+       }
+       ssize = yasm_intnum_get_uint(intn);
+    } else
+       ssize = 1;
+
+    if (!value)
+       value = yasm_expr_create_ident(
+           yasm_expr_int(yasm_intnum_create_uint(0)), cur_line);
+
+    yasm_dvs_initialize(&dvs);
+    yasm_dvs_append(&dvs, yasm_dv_create_expr(value));
+    bc = yasm_bc_create_data(&dvs, ssize, 0, parser_gas->arch, cur_line);
+
+    yasm_bc_set_multiple(bc, repeat);
+
+    return bc;
+}
+
+static void
+gas_parser_directive(yasm_parser_gas *parser_gas, const char *name,
+                     yasm_valparamhead *valparams,
+                     yasm_valparamhead *objext_valparams)
+{
+    unsigned long line = cur_line;
+
+    /* Handle (mostly) output-format independent directives here */
+    if (!yasm_arch_parse_directive(parser_gas->arch, name, valparams,
+                   objext_valparams, parser_gas->object, line)) {
+       ;
+    } else if (yasm_objfmt_directive(parser_gas->objfmt, name, valparams,
+                                    objext_valparams, line)) {
+       yasm_error_set(YASM_ERROR_GENERAL, N_("unrecognized directive [%s]"),
+                      name);
+    }
+
+    yasm_vps_delete(valparams);
+    if (objext_valparams)
+       yasm_vps_delete(objext_valparams);
+}
index 8160fc16904d3c9609d1fa25ac5cf5c77f9c8ed0..75c90ed365c9b231f5fe7c770ded1d94692c8482 100644 (file)
@@ -69,6 +69,8 @@ gas_parser_do_parse(yasm_object *object, yasm_preproc *pp, yasm_arch *a,
     parser_gas.save_input = save_input;
     parser_gas.save_last = 0;
 
+    parser_gas.peek_token = NONE;
+
     /* initialize scanner structure */
     yasm_scanner_initialize(&parser_gas.s);
 
index 4105d5b164ccb1b455a5d16e4422e95ebd2bbd8a..23c51df3f49a0fd015540a99edf47da0a6211f91 100644 (file)
 #ifndef YASM_GAS_PARSER_H
 #define YASM_GAS_PARSER_H
 
-#include "gas-bison.h"
-
 #define YYCTYPE                unsigned char
 
 #define MAX_SAVED_LINE_LEN  80
 
+enum tokentype {
+    INTNUM = 258,
+    FLTNUM,
+    STRING,
+    INSN,
+    PREFIX,
+    REG,
+    REGGROUP,
+    SEGREG,
+    TARGETMOD,
+    LEFT_OP,
+    RIGHT_OP,
+    ID,
+    LABEL,
+    LINE,
+    DIR_ALIGN,
+    DIR_ASCII,
+    DIR_COMM,
+    DIR_DATA,
+    DIR_ENDR,
+    DIR_EXTERN,
+    DIR_EQU,
+    DIR_FILE,
+    DIR_FILL,
+    DIR_GLOBAL,
+    DIR_IDENT,
+    DIR_LEB128,
+    DIR_LINE,
+    DIR_LOC,
+    DIR_LOCAL,
+    DIR_LCOMM,
+    DIR_ORG,
+    DIR_REPT,
+    DIR_SECTION,
+    DIR_SECTNAME,
+    DIR_SIZE,
+    DIR_SKIP,
+    DIR_TYPE,
+    DIR_WEAK,
+    DIR_ZERO,
+    NONE
+};
+
+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 gas_rept_line {
     STAILQ_ENTRY(gas_rept_line) link;
     YYCTYPE *data;             /* line characters */
@@ -96,11 +150,39 @@ typedef struct yasm_parser_gas {
        INSTDIR
     } 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;
+
     /*@null@*/ gas_rept *rept;
 } yasm_parser_gas;
 
 /* shorter access names to commonly used parser_gas fields */
 #define p_symtab       (parser_gas->symtab)
+#define curtok         (parser_gas->token)
+#define curval         (parser_gas->tokval)
+
+#define INTNUM_val             (curval.intn)
+#define FLTNUM_val             (curval.flt)
+#define STRING_val             (curval.str)
+#define INSN_val               (curval.arch_data)
+#define PREFIX_val             (curval.arch_data)
+#define REG_val                        (curval.arch_data)
+#define REGGROUP_val           (curval.arch_data)
+#define SEGREG_val             (curval.arch_data)
+#define TARGETMOD_val          (curval.arch_data)
+#define ID_val                 (curval.str_val)
+#define LABEL_val              (curval.str_val)
+#define DIR_ALIGN_val          (curval.int_info)
+#define DIR_ASCII_val          (curval.int_info)
+#define DIR_DATA_val           (curval.int_info)
+#define DIR_LEB128_val         (curval.int_info)
+#define DIR_SECTNAME_val       (curval.str_val)
 
 #define cur_line       (yasm_linemap_get_current(parser_gas->linemap))
 
@@ -109,7 +191,7 @@ typedef struct yasm_parser_gas {
 #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 gas_parser_parse(void *parser_gas_arg);
+void gas_parser_parse(yasm_parser_gas *parser_gas);
 void gas_parser_cleanup(yasm_parser_gas *parser_gas);
 int gas_parser_lex(YYSTYPE *lvalp, yasm_parser_gas *parser_gas);
 
index d9a2c214995365d8bc1e2aa6f9ca4a0bef4c1055..4f4e21844426a0ce8cd01a4f01b3ddf7059d697d 100644 (file)
@@ -34,7 +34,6 @@ RCSID("$Id$");
 #include <libyasm.h>
 
 #include "modules/parsers/gas/gas-parser.h"
-#include "modules/parsers/gas/gas-defs.h"
 
 
 #define BSIZE  8192
@@ -44,7 +43,8 @@ RCSID("$Id$");
 #define YYMARKER       (s->ptr)
 #define YYFILL(n)      {cursor = fill(parser_gas, cursor);}
 
-#define RETURN(i)      {s->cur = cursor; return i;}
+#define RETURN(i)      {s->cur = cursor; parser_gas->tokch = s->tok[0]; \
+                        return i;}
 
 #define SCANINIT()     {s->tok = cursor;}
 
@@ -248,6 +248,15 @@ gas_parser_lex(YYSTYPE *lvalp, yasm_parser_gas *parser_gas)
     int linestart;
     gas_rept_line *new_line;
 
+    /* Handle one token of lookahead */
+    if (parser_gas->peek_token != NONE) {
+       int tok = parser_gas->peek_token;
+       *lvalp = parser_gas->peek_tokval;  /* structure copy */
+       parser_gas->tokch = parser_gas->peek_tokch;
+       parser_gas->peek_token = NONE;
+       return tok;
+    }
+
     /* Catch EOF */
     if (s->eof && cursor == s->eof)
        return 0;
@@ -338,68 +347,172 @@ scan:
        }
 
        /* arch-independent directives */
-       '.2byte'        { parser_gas->state = INSTDIR; RETURN(DIR_2BYTE); }
-       '.4byte'        { parser_gas->state = INSTDIR; RETURN(DIR_4BYTE); }
-       '.8byte'        { parser_gas->state = INSTDIR; RETURN(DIR_QUAD); }
-       '.align'        { parser_gas->state = INSTDIR; RETURN(DIR_ALIGN); }
-       '.ascii'        { parser_gas->state = INSTDIR; RETURN(DIR_ASCII); }
-       '.asciz'        { parser_gas->state = INSTDIR; RETURN(DIR_ASCIZ); }
-       '.balign'       { parser_gas->state = INSTDIR; RETURN(DIR_BALIGN); }
-       '.bss'          { parser_gas->state = INSTDIR; RETURN(DIR_BSS); }
-       '.byte'         { parser_gas->state = INSTDIR; RETURN(DIR_BYTE); }
-       '.comm'         { parser_gas->state = INSTDIR; RETURN(DIR_COMM); }
-       '.data'         { parser_gas->state = INSTDIR; RETURN(DIR_DATA); }
-       '.double'       { parser_gas->state = INSTDIR; RETURN(DIR_DOUBLE); }
-       '.endr'         { parser_gas->state = INSTDIR; RETURN(DIR_ENDR); }
-       '.equ'          { parser_gas->state = INSTDIR; RETURN(DIR_EQU); }
-       '.extern'       { parser_gas->state = INSTDIR; RETURN(DIR_EXTERN); }
-       '.file'         { parser_gas->state = INSTDIR; RETURN(DIR_FILE); }
-       '.fill'         { parser_gas->state = INSTDIR; RETURN(DIR_FILL); }
-       '.float'        { parser_gas->state = INSTDIR; RETURN(DIR_FLOAT); }
+       /*  alignment directives */
+       '.align'        {
+           /* FIXME: Whether this is power-of-two or not depends on arch and
+            * objfmt.
+            */
+           lvalp->int_info = 0;
+           parser_gas->state = INSTDIR; RETURN(DIR_ALIGN);
+       }
+       '.p2align'      {
+           lvalp->int_info = 1;
+           parser_gas->state = INSTDIR; RETURN(DIR_ALIGN);
+       }
+       '.balign'       {
+           lvalp->int_info = 0;
+           parser_gas->state = INSTDIR; RETURN(DIR_ALIGN);
+       }
+       '.org'          { parser_gas->state = INSTDIR; RETURN(DIR_ORG); }
+       /*  data visibility directives */
+       '.local'        { parser_gas->state = INSTDIR; RETURN(DIR_LOCAL); }
        '.global'       { parser_gas->state = INSTDIR; RETURN(DIR_GLOBAL); }
        '.globl'        { parser_gas->state = INSTDIR; RETURN(DIR_GLOBAL); }
-       '.hword'        { parser_gas->state = INSTDIR; RETURN(DIR_SHORT); }
-       '.ident'        { parser_gas->state = INSTDIR; RETURN(DIR_IDENT); }
-       '.int'          { parser_gas->state = INSTDIR; RETURN(DIR_INT); }
+       '.comm'         { parser_gas->state = INSTDIR; RETURN(DIR_COMM); }
        '.lcomm'        { parser_gas->state = INSTDIR; RETURN(DIR_LCOMM); }
-       '.line'         { parser_gas->state = INSTDIR; RETURN(DIR_LINE); }
-       '.loc'          { parser_gas->state = INSTDIR; RETURN(DIR_LOC); }
-       '.local'        { parser_gas->state = INSTDIR; RETURN(DIR_LOCAL); }
-       '.long'         { parser_gas->state = INSTDIR; RETURN(DIR_INT); }
-       '.octa'         { parser_gas->state = INSTDIR; RETURN(DIR_OCTA); }
-       '.org'          { parser_gas->state = INSTDIR; RETURN(DIR_ORG); }
-       '.p2align'      { parser_gas->state = INSTDIR; RETURN(DIR_P2ALIGN); }
-       '.rept'         { parser_gas->state = INSTDIR; RETURN(DIR_REPT); }
+       '.extern'       { parser_gas->state = INSTDIR; RETURN(DIR_EXTERN); }
+       '.weak'         { parser_gas->state = INSTDIR; RETURN(DIR_WEAK); }
+       /*  integer data declaration directives */
+       '.byte'         {
+           lvalp->int_info = 1;
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       '.2byte'        {
+           lvalp->int_info = 2;
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       '.4byte'        {
+           lvalp->int_info = 4;
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       '.8byte'        {
+           lvalp->int_info = 8;
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       '.16byte'       {
+           lvalp->int_info = 16;
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       '.short'        {
+           lvalp->int_info = 2; /* TODO: This should depend on arch */
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       '.int'          {
+           lvalp->int_info = 4; /* TODO: This should depend on arch */
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       '.long'         {
+           lvalp->int_info = 4; /* TODO: This should depend on arch */
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       '.hword'        {
+           lvalp->int_info = 2; /* TODO: This should depend on arch */
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       '.word'         {
+           lvalp->int_info = yasm_arch_wordsize(parser_gas->arch)/8;
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       '.quad'         {
+           lvalp->int_info = 8;
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       '.octa'         {
+           lvalp->int_info = 16;
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       '.value'        {
+           lvalp->int_info = 2; /* XXX: At least on x86, this is 2 bytes */
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       /*  ASCII data declaration directives */
+       '.ascii'        {
+           lvalp->int_info = 0; /* do not add terminating zero */
+           parser_gas->state = INSTDIR; RETURN(DIR_ASCII);
+       }
+       '.asciz'        {
+           lvalp->int_info = 1; /* add terminating zero */
+           parser_gas->state = INSTDIR; RETURN(DIR_ASCII);
+       }
+       '.string'       {
+           lvalp->int_info = 1; /* add terminating zero */
+           parser_gas->state = INSTDIR; RETURN(DIR_ASCII);
+       }
+       /*  LEB128 integer data declaration directives */
+       '.sleb128'      {
+           lvalp->int_info = 1; /* signed */
+           parser_gas->state = INSTDIR; RETURN(DIR_LEB128);
+       }
+       '.uleb128'      {
+           lvalp->int_info = 0; /* unsigned */
+           parser_gas->state = INSTDIR; RETURN(DIR_LEB128);
+       }
+       /*  floating point data declaration directives */
+       '.float'        {
+           lvalp->int_info = 4;
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       '.single'       {
+           lvalp->int_info = 4;
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       '.double'       {
+           lvalp->int_info = 8;
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       '.tfloat'       {
+           lvalp->int_info = 10;
+           parser_gas->state = INSTDIR; RETURN(DIR_DATA);
+       }
+       /*  section directives */
+       '.bss'          {
+           lvalp->str_val = yasm__xstrdup(".bss");
+           RETURN(DIR_SECTNAME);
+       }
+       '.data'         {
+           lvalp->str_val = yasm__xstrdup(".data");
+           RETURN(DIR_SECTNAME);
+       }
+       '.text'         {
+           lvalp->str_val = yasm__xstrdup(".text");
+           RETURN(DIR_SECTNAME);
+       }
        '.section'      {
            parser_gas->state = SECTION_DIRECTIVE;
            RETURN(DIR_SECTION);
        }
-       '.set'          { parser_gas->state = INSTDIR; RETURN(DIR_EQU); }
-       '.short'        { parser_gas->state = INSTDIR; RETURN(DIR_SHORT); }
-       '.single'       { parser_gas->state = INSTDIR; RETURN(DIR_FLOAT); }
-       '.size'         { parser_gas->state = INSTDIR; RETURN(DIR_SIZE); }
+       /* macro directives */
+       '.rept'         { parser_gas->state = INSTDIR; RETURN(DIR_REPT); }
+       '.endr'         { parser_gas->state = INSTDIR; RETURN(DIR_ENDR); }
+       /* empty space/fill directives */
        '.skip'         { parser_gas->state = INSTDIR; RETURN(DIR_SKIP); }
-       '.sleb128'      { parser_gas->state = INSTDIR; RETURN(DIR_SLEB128); }
        '.space'        { parser_gas->state = INSTDIR; RETURN(DIR_SKIP); }
-       '.string'       { parser_gas->state = INSTDIR; RETURN(DIR_ASCIZ); }
-       '.text'         { parser_gas->state = INSTDIR; RETURN(DIR_TEXT); }
-       '.tfloat'       { parser_gas->state = INSTDIR; RETURN(DIR_TFLOAT); }
-       '.type'         { parser_gas->state = INSTDIR; RETURN(DIR_TYPE); }
-       '.quad'         { parser_gas->state = INSTDIR; RETURN(DIR_QUAD); }
-       '.uleb128'      { parser_gas->state = INSTDIR; RETURN(DIR_ULEB128); }
-       '.value'        { parser_gas->state = INSTDIR; RETURN(DIR_VALUE); }
-       '.weak'         { parser_gas->state = INSTDIR; RETURN(DIR_WEAK); }
-       '.word'         { parser_gas->state = INSTDIR; RETURN(DIR_WORD); }
+       '.fill'         { parser_gas->state = INSTDIR; RETURN(DIR_FILL); }
        '.zero'         { parser_gas->state = INSTDIR; RETURN(DIR_ZERO); }
-
-       /* label or maybe directive */
-       [.][a-zA-Z0-9_$.]* {
-           lvalp->str_val = yasm__xstrndup(TOK, TOKLEN);
-           RETURN(DIR_ID);
+       /* other directives */
+       '.code16'       {
+           yasm_arch_set_var(parser_gas->arch, "mode_bits", 16);
+           goto scan;
+       }
+       '.code32'       {
+           yasm_arch_set_var(parser_gas->arch, "mode_bits", 32);
+           goto scan;
        }
+       '.code64'       {
+           yasm_arch_set_var(parser_gas->arch, "mode_bits", 64);
+           goto scan;
+       }
+       '.equ'          { parser_gas->state = INSTDIR; RETURN(DIR_EQU); }
+       '.file'         { parser_gas->state = INSTDIR; RETURN(DIR_FILE); }
+       '.ident'        { parser_gas->state = INSTDIR; RETURN(DIR_IDENT); }
+       '.line'         { parser_gas->state = INSTDIR; RETURN(DIR_LINE); }
+       '.loc'          { parser_gas->state = INSTDIR; RETURN(DIR_LOC); }
+       '.set'          { parser_gas->state = INSTDIR; RETURN(DIR_EQU); }
+       '.size'         { parser_gas->state = INSTDIR; RETURN(DIR_SIZE); }
+       '.type'         { parser_gas->state = INSTDIR; RETURN(DIR_TYPE); }
 
-       /* label */
-       [_][a-zA-Z0-9_$.]* {
+       /* label or maybe directive */
+       [_.][a-zA-Z0-9_$.]* {
            lvalp->str_val = yasm__xstrndup(TOK, TOKLEN);
            RETURN(ID);
        }
index 4a63c425d9006d362ff0d95c64bc55f16573f209..797ecffa7f4b402d49d31079f09dd54f5c2f3243 100644 (file)
@@ -6,7 +6,6 @@
 
 frontends/yasm/yasm-options.c
 frontends/yasm/yasm.c
-gas-bison.c
 gas-token.c
 #lc3bid.c
 libyasm/bc-align.c
@@ -49,6 +48,7 @@ modules/objfmts/elf/elf-x86-x86.c
 modules/objfmts/elf/elf.c
 modules/objfmts/rdf/rdf-objfmt.c
 modules/objfmts/xdf/xdf-objfmt.c
+modules/parsers/gas/gas-parse.c
 modules/parsers/gas/gas-parser.c
 modules/parsers/nasm/nasm-parse.c
 modules/preprocs/nasm/nasm-pp.c