Home | History | Annotate | Download | only in gas
      1 /*
      2  * GAS-compatible parser
      3  *
      4  *  Copyright (C) 2005-2007  Peter Johnson
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. Neither the name of the author nor the names of other contributors
     15  *    may be used to endorse or promote products derived from this
     16  *    software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
     19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
     22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28  * POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 #include <util.h>
     31 
     32 #include <libyasm.h>
     33 
     34 #include <ctype.h>
     35 #include <limits.h>
     36 #include <math.h>
     37 
     38 #include "modules/parsers/gas/gas-parser.h"
     39 
     40 typedef struct dir_lookup {
     41     const char *name;
     42     yasm_bytecode * (*handler) (yasm_parser_gas *, unsigned int);
     43     unsigned int param;
     44     enum gas_parser_state newstate;
     45 } dir_lookup;
     46 
     47 static void cpp_line_marker(yasm_parser_gas *parser_gas);
     48 static void nasm_line_marker(yasm_parser_gas *parser_gas);
     49 static yasm_bytecode *parse_instr(yasm_parser_gas *parser_gas);
     50 static int parse_dirvals(yasm_parser_gas *parser_gas, yasm_valparamhead *vps);
     51 static int parse_datavals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs);
     52 static int parse_strvals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs);
     53 static yasm_effaddr *parse_memaddr(yasm_parser_gas *parser_gas);
     54 static yasm_insn_operand *parse_operand(yasm_parser_gas *parser_gas);
     55 static yasm_expr *parse_expr(yasm_parser_gas *parser_gas);
     56 static yasm_expr *parse_expr0(yasm_parser_gas *parser_gas);
     57 static yasm_expr *parse_expr1(yasm_parser_gas *parser_gas);
     58 static yasm_expr *parse_expr2(yasm_parser_gas *parser_gas);
     59 
     60 static void define_label(yasm_parser_gas *parser_gas, char *name, int local);
     61 static void define_lcomm(yasm_parser_gas *parser_gas, /*@only@*/ char *name,
     62                          yasm_expr *size, /*@null@*/ yasm_expr *align);
     63 static yasm_section *gas_get_section
     64     (yasm_parser_gas *parser_gas, /*@only@*/ char *name, /*@null@*/ char *flags,
     65      /*@null@*/ char *type, /*@null@*/ yasm_valparamhead *objext_valparams,
     66      int builtin);
     67 static void gas_switch_section
     68     (yasm_parser_gas *parser_gas, /*@only@*/ const char *name,
     69      /*@null@*/ char *flags, /*@null@*/ char *type,
     70      /*@null@*/ yasm_valparamhead *objext_valparams, int builtin);
     71 static yasm_bytecode *gas_parser_align
     72     (yasm_parser_gas *parser_gas, yasm_section *sect, yasm_expr *boundval,
     73      /*@null@*/ yasm_expr *fillval, /*@null@*/ yasm_expr *maxskipval,
     74      int power2);
     75 static yasm_bytecode *gas_parser_dir_fill
     76     (yasm_parser_gas *parser_gas, /*@only@*/ yasm_expr *repeat,
     77      /*@only@*/ /*@null@*/ yasm_expr *size,
     78      /*@only@*/ /*@null@*/ yasm_expr *value);
     79 
     80 #define is_eol_tok(tok) ((tok) == '\n' || (tok) == ';' || (tok) == 0)
     81 #define is_eol()        is_eol_tok(curtok)
     82 
     83 #define get_next_token()    (curtok = gas_parser_lex(&curval, parser_gas))
     84 
     85 static void
     86 get_peek_token(yasm_parser_gas *parser_gas)
     87 {
     88     char savech = parser_gas->tokch;
     89     if (parser_gas->peek_token != NONE)
     90         yasm_internal_error(N_("can only have one token of lookahead"));
     91     parser_gas->peek_token =
     92         gas_parser_lex(&parser_gas->peek_tokval, parser_gas);
     93     parser_gas->peek_tokch = parser_gas->tokch;
     94     parser_gas->tokch = savech;
     95 }
     96 
     97 static void
     98 destroy_curtok_(yasm_parser_gas *parser_gas)
     99 {
    100     if (curtok < 256)
    101         ;
    102     else switch ((enum tokentype)curtok) {
    103         case INTNUM:
    104             yasm_intnum_destroy(curval.intn);
    105             break;
    106         case FLTNUM:
    107             yasm_floatnum_destroy(curval.flt);
    108             break;
    109         case ID:
    110         case LABEL:
    111         case STRING:
    112             yasm_xfree(curval.str.contents);
    113             break;
    114         default:
    115             break;
    116     }
    117     curtok = NONE;          /* sanity */
    118 }
    119 #define destroy_curtok()    destroy_curtok_(parser_gas)
    120 
    121 /* Eat all remaining tokens to EOL, discarding all of them.  If there's any
    122  * intervening tokens, generates an error (junk at end of line).
    123  */
    124 static void
    125 demand_eol_(yasm_parser_gas *parser_gas)
    126 {
    127     if (is_eol())
    128         return;
    129 
    130     yasm_error_set(YASM_ERROR_SYNTAX,
    131         N_("junk at end of line, first unrecognized character is `%c'"),
    132         parser_gas->tokch);
    133 
    134     do {
    135         destroy_curtok();
    136         get_next_token();
    137     } while (!is_eol());
    138 }
    139 #define demand_eol() demand_eol_(parser_gas)
    140 
    141 static int
    142 expect_(yasm_parser_gas *parser_gas, int token)
    143 {
    144     static char strch[] = "` '";
    145     const char *str;
    146 
    147     if (curtok == token)
    148         return 1;
    149 
    150     switch (token) {
    151         case INTNUM:            str = "integer"; break;
    152         case FLTNUM:            str = "floating point value"; break;
    153         case STRING:            str = "string"; break;
    154         case REG:               str = "register"; break;
    155         case REGGROUP:          str = "register group"; break;
    156         case SEGREG:            str = "segment register"; break;
    157         case TARGETMOD:         str = "target modifier"; break;
    158         case LEFT_OP:           str = "<<"; break;
    159         case RIGHT_OP:          str = ">>"; break;
    160         case ID:                str = "identifier"; break;
    161         case LABEL:             str = "label"; break;
    162         default:
    163             strch[1] = token;
    164             str = strch;
    165             break;
    166     }
    167     yasm_error_set(YASM_ERROR_PARSE, "expected %s", str);
    168     destroy_curtok();
    169     return 0;
    170 }
    171 #define expect(token) expect_(parser_gas, token)
    172 
    173 static yasm_bytecode *
    174 parse_line(yasm_parser_gas *parser_gas)
    175 {
    176     yasm_bytecode *bc;
    177     yasm_expr *e;
    178     yasm_valparamhead vps;
    179     char *id;
    180     const dir_lookup *dir;
    181 
    182     if (is_eol())
    183         return NULL;
    184 
    185     bc = parse_instr(parser_gas);
    186     if (bc)
    187         return bc;
    188 
    189     switch (curtok) {
    190         case ID:
    191             id = ID_val;
    192 
    193             /* See if it's a gas-specific directive */
    194             dir = (const dir_lookup *)HAMT_search(parser_gas->dirs, id);
    195             if (dir) {
    196                 parser_gas->state = dir->newstate;
    197                 get_next_token(); /* ID */
    198                 return dir->handler(parser_gas, dir->param);
    199             }
    200 
    201             get_next_token(); /* ID */
    202             if (curtok == ':') {
    203                 /* Label */
    204                 parser_gas->state = INITIAL;
    205                 get_next_token(); /* : */
    206                 define_label(parser_gas, id, 0);
    207                 return parse_line(parser_gas);
    208             } else if (curtok == '=') {
    209                 /* EQU */
    210                 /* TODO: allow redefinition, assigning to . (same as .org) */
    211                 parser_gas->state = INITIAL;
    212                 get_next_token(); /* = */
    213                 e = parse_expr(parser_gas);
    214                 if (e)
    215                     yasm_symtab_define_equ(p_symtab, id, e, cur_line);
    216                 else
    217                     yasm_error_set(YASM_ERROR_SYNTAX,
    218                                    N_("expression expected after `%s'"), "=");
    219                 yasm_xfree(id);
    220                 return NULL;
    221             }
    222 
    223             /* possibly a directive; try to parse it */
    224             parse_dirvals(parser_gas, &vps);
    225             if (!yasm_object_directive(p_object, id, "gas", &vps, NULL,
    226                                        cur_line)) {
    227                 yasm_vps_delete(&vps);
    228                 yasm_xfree(id);
    229                 return NULL;
    230             }
    231             yasm_vps_delete(&vps);
    232             if (id[0] == '.')
    233                 yasm_warn_set(YASM_WARN_GENERAL,
    234                               N_("directive `%s' not recognized"), id);
    235             else
    236                 yasm_error_set(YASM_ERROR_SYNTAX,
    237                                N_("instruction not recognized: `%s'"), id);
    238             yasm_xfree(id);
    239             return NULL;
    240         case LABEL:
    241             define_label(parser_gas, LABEL_val, 0);
    242             get_next_token(); /* LABEL */
    243             return parse_line(parser_gas);
    244         case CPP_LINE_MARKER:
    245             get_next_token();
    246             cpp_line_marker(parser_gas);
    247             return NULL;
    248         case NASM_LINE_MARKER:
    249             get_next_token();
    250             nasm_line_marker(parser_gas);
    251             return NULL;
    252         default:
    253             yasm_error_set(YASM_ERROR_SYNTAX,
    254                 N_("label or instruction expected at start of line"));
    255             return NULL;
    256     }
    257 }
    258 
    259 /*
    260     Handle line markers generated by cpp.
    261 
    262     We expect a positive integer (line) followed by a string (filename). If we
    263     fail to find either of these, we treat the line as a comment. There is a
    264     possibility of false positives (mistaking a comment for a line marker, when
    265     the comment is not intended as a line marker) but this cannot be avoided
    266     without adding a filter to the input before passing it to cpp.
    267 
    268     This function is only called if the preprocessor was 'cpp', since the
    269     CPP_LINE_MARKER token isn't generated for any other preprocessor. With any
    270     other preprocessor, anything after a '#' is always treated as a comment.
    271 */
    272 static void
    273 cpp_line_marker(yasm_parser_gas *parser_gas)
    274 {
    275     yasm_valparamhead vps;
    276     yasm_valparam *vp;
    277     unsigned long line;
    278     char *filename;
    279 
    280     /* Line number. */
    281     if (curtok != INTNUM) {
    282         /* Skip over a comment. */
    283         while (curtok != '\n')
    284             get_next_token();
    285 
    286         return;
    287     }
    288 
    289     if (yasm_intnum_sign(INTNUM_val) < 0) {
    290         get_next_token(); /* INTNUM */
    291         yasm_error_set(YASM_ERROR_SYNTAX,
    292                        N_("line number is negative"));
    293         return;
    294     }
    295 
    296     line = yasm_intnum_get_uint(INTNUM_val);
    297 
    298     /*
    299         Set to (line - 1) since the directive indicates that the *next* line
    300         will have the number given.
    301 
    302         cpp should never produce line=0, but the if keeps us safe just incase.
    303     */
    304     if (line != 0)
    305         line--;
    306 
    307     yasm_intnum_destroy(INTNUM_val);
    308     get_next_token(); /* INTNUM */
    309 
    310     /* File name, in quotes. */
    311     if (curtok != STRING) {
    312         /* Skip over a comment. */
    313         while (curtok != '\n')
    314             get_next_token();
    315 
    316         return;
    317     }
    318 
    319     filename = STRING_val.contents;
    320     get_next_token();
    321 
    322     /* Set linemap. */
    323     yasm_linemap_set(parser_gas->linemap, filename, 0, line, 1);
    324 
    325     /*
    326         The first line marker in the file (which should be on the first line
    327         of the file) will give us the name of the source file. This information
    328         needs to be passed on to the debug format module.
    329     */
    330     if (parser_gas->seen_line_marker == 0) {
    331         parser_gas->seen_line_marker = 1;
    332 
    333         yasm_vps_initialize(&vps);
    334         vp = yasm_vp_create_string(NULL, filename);
    335         yasm_vps_append(&vps, vp);
    336 
    337         yasm_object_directive(p_object, ".file", "gas", &vps, NULL, cur_line);
    338 
    339         yasm_vps_delete(&vps);
    340     } else
    341         yasm_xfree(filename);
    342 
    343     /* Skip flags. */
    344     while (1) {
    345         switch (curtok) {
    346             case INTNUM:
    347                 break;
    348 
    349             case '\n':
    350                 return;
    351 
    352             default:
    353                 yasm_error_set(YASM_ERROR_SYNTAX,
    354                     N_("junk at end of cpp line marker"));
    355                 return;
    356         }
    357         get_next_token();
    358     }
    359 }
    360 
    361 /*
    362     Handle line markers generated by the nasm preproc.
    363 
    364     We expect a positive integer (line) followed by a plus sign, followed by
    365     another positive integer, followed by a string (filename).
    366 
    367     This function is only called if the preprocessor was 'nasm', since the
    368     NASM_LINE_MARKER token isn't generated for any other preprocessor.
    369 */
    370 static void
    371 nasm_line_marker(yasm_parser_gas *parser_gas)
    372 {
    373     yasm_valparamhead vps;
    374     yasm_valparam *vp;
    375     unsigned long line, incr;
    376     char *filename;
    377 
    378     /* Line number. */
    379     if (!expect(INTNUM)) return;
    380 
    381     if (yasm_intnum_sign(INTNUM_val) < 0) {
    382         get_next_token(); /* INTNUM */
    383         yasm_error_set(YASM_ERROR_SYNTAX,
    384                        N_("line number is negative"));
    385         return;
    386     }
    387 
    388     line = yasm_intnum_get_uint(INTNUM_val);
    389 
    390     /*
    391         Set to (line - 1) since the directive indicates that the *next* line
    392         will have the number given.
    393 
    394         cpp should never produce line=0, but the if keeps us safe just incase.
    395     */
    396     if (line != 0)
    397         line--;
    398 
    399     yasm_intnum_destroy(INTNUM_val);
    400     get_next_token(); /* INTNUM */
    401 
    402     if (!expect('+')) return;
    403     get_next_token(); /* + */
    404 
    405     /* Line number increment. */
    406     if (!expect(INTNUM)) return;
    407 
    408     if (yasm_intnum_sign(INTNUM_val) < 0) {
    409         get_next_token(); /* INTNUM */
    410         yasm_error_set(YASM_ERROR_SYNTAX,
    411                        N_("line increment is negative"));
    412         return;
    413     }
    414 
    415     incr = yasm_intnum_get_uint(INTNUM_val);
    416     yasm_intnum_destroy(INTNUM_val);
    417 
    418     /* File name is not in quotes, so need to switch to a different tokenizer
    419      * state.
    420      */
    421     parser_gas->state = NASM_FILENAME;
    422     get_next_token(); /* INTNUM */
    423     if (!expect(STRING)) {
    424         parser_gas->state = INITIAL;
    425         return;
    426     }
    427 
    428     filename = STRING_val.contents;
    429 
    430     /* Set linemap. */
    431     yasm_linemap_set(parser_gas->linemap, filename, 0, line, incr);
    432 
    433     /*
    434         The first line marker in the file (which should be on the first line
    435         of the file) will give us the name of the source file. This information
    436         needs to be passed on to the debug format module.
    437     */
    438     if (parser_gas->seen_line_marker == 0) {
    439         parser_gas->seen_line_marker = 1;
    440 
    441         yasm_vps_initialize(&vps);
    442         vp = yasm_vp_create_string(NULL, filename);
    443         yasm_vps_append(&vps, vp);
    444 
    445         yasm_object_directive(p_object, ".file", "gas", &vps, NULL, cur_line);
    446 
    447         yasm_vps_delete(&vps);
    448     } else
    449         yasm_xfree(filename);
    450 
    451     /* We need to poke back on the \n that was consumed by the tokenizer */
    452     parser_gas->peek_token = '\n';
    453     get_next_token();
    454 }
    455 
    456 /* Line directive */
    457 static yasm_bytecode *
    458 dir_line(yasm_parser_gas *parser_gas, unsigned int param)
    459 {
    460     if (!expect(INTNUM)) return NULL;
    461     if (yasm_intnum_sign(INTNUM_val) < 0) {
    462         get_next_token(); /* INTNUM */
    463         yasm_error_set(YASM_ERROR_SYNTAX,
    464                        N_("line number is negative"));
    465         return NULL;
    466     }
    467 
    468     parser_gas->dir_line = yasm_intnum_get_uint(INTNUM_val);
    469     yasm_intnum_destroy(INTNUM_val);
    470     get_next_token(); /* INTNUM */
    471 
    472     if (parser_gas->dir_fileline == 3) {
    473         /* Have both file and line */
    474         yasm_linemap_set(parser_gas->linemap, NULL, 0,
    475                          parser_gas->dir_line, 1);
    476     } else if (parser_gas->dir_fileline == 1) {
    477         /* Had previous file directive only */
    478         parser_gas->dir_fileline = 3;
    479         yasm_linemap_set(parser_gas->linemap, parser_gas->dir_file, 0,
    480                          parser_gas->dir_line, 1);
    481     } else {
    482         /* Didn't see file yet */
    483         parser_gas->dir_fileline = 2;
    484     }
    485     return NULL;
    486 }
    487 
    488 /* Alignment directives */
    489 
    490 static yasm_bytecode *
    491 dir_align(yasm_parser_gas *parser_gas, unsigned int param)
    492 {
    493     yasm_expr *bound, *fill=NULL, *maxskip=NULL;
    494 
    495     bound = parse_expr(parser_gas);
    496     if (!bound) {
    497         yasm_error_set(YASM_ERROR_SYNTAX,
    498                        N_(".align directive must specify alignment"));
    499         return NULL;
    500     }
    501 
    502     if (curtok == ',') {
    503         get_next_token(); /* ',' */
    504         fill = parse_expr(parser_gas);
    505         if (curtok == ',') {
    506             get_next_token(); /* ',' */
    507             maxskip = parse_expr(parser_gas);
    508         }
    509     }
    510 
    511     return gas_parser_align(parser_gas, cursect, bound, fill, maxskip,
    512                             (int)param);
    513 }
    514 
    515 static yasm_bytecode *
    516 dir_org(yasm_parser_gas *parser_gas, unsigned int param)
    517 {
    518     yasm_intnum *start, *value=NULL;
    519     yasm_bytecode *bc;
    520 
    521     /* TODO: support expr instead of intnum */
    522     if (!expect(INTNUM)) return NULL;
    523     start = INTNUM_val;
    524     get_next_token(); /* INTNUM */
    525 
    526     if (curtok == ',') {
    527         get_next_token(); /* ',' */
    528         /* TODO: support expr instead of intnum */
    529         if (!expect(INTNUM)) return NULL;
    530         value = INTNUM_val;
    531         get_next_token(); /* INTNUM */
    532     }
    533     if (value) {
    534         bc = yasm_bc_create_org(yasm_intnum_get_uint(start),
    535                                 yasm_intnum_get_uint(value), cur_line);
    536         yasm_intnum_destroy(value);
    537     } else
    538         bc = yasm_bc_create_org(yasm_intnum_get_uint(start), 0,
    539                                 cur_line);
    540     yasm_intnum_destroy(start);
    541     return bc;
    542 }
    543 
    544 /* Data visibility directives */
    545 
    546 static yasm_bytecode *
    547 dir_local(yasm_parser_gas *parser_gas, unsigned int param)
    548 {
    549     if (!expect(ID)) return NULL;
    550     yasm_symtab_declare(p_symtab, ID_val, YASM_SYM_DLOCAL, cur_line);
    551     yasm_xfree(ID_val);
    552     get_next_token(); /* ID */
    553     return NULL;
    554 }
    555 
    556 static yasm_bytecode *
    557 dir_comm(yasm_parser_gas *parser_gas, unsigned int is_lcomm)
    558 {
    559     yasm_expr *align = NULL;
    560     /*@null@*/ /*@dependent@*/ yasm_symrec *sym;
    561     char *id;
    562     yasm_expr *e;
    563 
    564     if (!expect(ID)) return NULL;
    565     id = ID_val;
    566     get_next_token(); /* ID */
    567     if (!expect(',')) {
    568         yasm_xfree(id);
    569         return NULL;
    570     }
    571     get_next_token(); /* , */
    572     e = parse_expr(parser_gas);
    573     if (!e) {
    574         yasm_error_set(YASM_ERROR_SYNTAX, N_("size expected for `%s'"),
    575                        ".COMM");
    576         return NULL;
    577     }
    578     if (curtok == ',') {
    579         /* Optional alignment expression */
    580         get_next_token(); /* ',' */
    581         align = parse_expr(parser_gas);
    582     }
    583     /* If already explicitly declared local, treat like LCOMM */
    584     if (is_lcomm
    585         || ((sym = yasm_symtab_get(p_symtab, id))
    586             && yasm_symrec_get_visibility(sym) == YASM_SYM_DLOCAL)) {
    587         define_lcomm(parser_gas, id, e, align);
    588     } else if (align) {
    589         /* Give third parameter as objext valparam */
    590         yasm_valparamhead *extvps = yasm_vps_create();
    591         yasm_valparam *vp = yasm_vp_create_expr(NULL, align);
    592         yasm_vps_append(extvps, vp);
    593 
    594         sym = yasm_symtab_declare(p_symtab, id, YASM_SYM_COMMON,
    595                                   cur_line);
    596         yasm_symrec_set_common_size(sym, e);
    597         yasm_symrec_set_objext_valparams(sym, extvps);
    598 
    599         yasm_xfree(id);
    600     } else {
    601         sym = yasm_symtab_declare(p_symtab, id, YASM_SYM_COMMON,
    602                                   cur_line);
    603         yasm_symrec_set_common_size(sym, e);
    604         yasm_xfree(id);
    605     }
    606     return NULL;
    607 }
    608 
    609 /* Integer data definition directives */
    610 
    611 static yasm_bytecode *
    612 dir_ascii(yasm_parser_gas *parser_gas, unsigned int withzero)
    613 {
    614     yasm_datavalhead dvs;
    615     if (!parse_strvals(parser_gas, &dvs))
    616         return NULL;
    617     return yasm_bc_create_data(&dvs, 1, (int)withzero, p_object->arch,
    618                                cur_line);
    619 }
    620 
    621 static yasm_bytecode *
    622 dir_data(yasm_parser_gas *parser_gas, unsigned int size)
    623 {
    624     yasm_datavalhead dvs;
    625     if (!parse_datavals(parser_gas, &dvs))
    626         return NULL;
    627     return yasm_bc_create_data(&dvs, size, 0, p_object->arch, cur_line);
    628 }
    629 
    630 static yasm_bytecode *
    631 dir_leb128(yasm_parser_gas *parser_gas, unsigned int sign)
    632 {
    633     yasm_datavalhead dvs;
    634     if (!parse_datavals(parser_gas, &dvs))
    635         return NULL;
    636     return yasm_bc_create_leb128(&dvs, (int)sign, cur_line);
    637 }
    638 
    639 /* Empty space / fill data definition directives */
    640 
    641 static yasm_bytecode *
    642 dir_zero(yasm_parser_gas *parser_gas, unsigned int param)
    643 {
    644     yasm_bytecode *bc;
    645     yasm_datavalhead dvs;
    646     yasm_expr *e = parse_expr(parser_gas);
    647     if (!e) {
    648         yasm_error_set(YASM_ERROR_SYNTAX,
    649                        N_("expression expected after `%s'"), ".ZERO");
    650         return NULL;
    651     }
    652 
    653     yasm_dvs_initialize(&dvs);
    654     yasm_dvs_append(&dvs, yasm_dv_create_expr(
    655         p_expr_new_ident(yasm_expr_int(yasm_intnum_create_uint(0)))));
    656     bc = yasm_bc_create_data(&dvs, 1, 0, p_object->arch, cur_line);
    657     yasm_bc_set_multiple(bc, e);
    658     return bc;
    659 }
    660 
    661 static yasm_bytecode *
    662 dir_skip(yasm_parser_gas *parser_gas, unsigned int param)
    663 {
    664     yasm_expr *e, *e_val;
    665     yasm_bytecode *bc;
    666     yasm_datavalhead dvs;
    667 
    668     e = parse_expr(parser_gas);
    669     if (!e) {
    670         yasm_error_set(YASM_ERROR_SYNTAX,
    671                        N_("expression expected after `%s'"), ".SKIP");
    672         return NULL;
    673     }
    674     if (curtok != ',')
    675         return yasm_bc_create_reserve(e, 1, cur_line);
    676     get_next_token(); /* ',' */
    677     e_val = parse_expr(parser_gas);
    678     yasm_dvs_initialize(&dvs);
    679     yasm_dvs_append(&dvs, yasm_dv_create_expr(e_val));
    680     bc = yasm_bc_create_data(&dvs, 1, 0, p_object->arch, cur_line);
    681 
    682     yasm_bc_set_multiple(bc, e);
    683     return bc;
    684 }
    685 
    686 /* fill data definition directive */
    687 static yasm_bytecode *
    688 dir_fill(yasm_parser_gas *parser_gas, unsigned int param)
    689 {
    690     yasm_expr *sz=NULL, *val=NULL;
    691     yasm_expr *e = parse_expr(parser_gas);
    692     if (!e) {
    693         yasm_error_set(YASM_ERROR_SYNTAX,
    694                        N_("expression expected after `%s'"), ".FILL");
    695         return NULL;
    696     }
    697     if (curtok == ',') {
    698         get_next_token(); /* ',' */
    699         sz = parse_expr(parser_gas);
    700         if (curtok == ',') {
    701             get_next_token(); /* ',' */
    702             val = parse_expr(parser_gas);
    703         }
    704     }
    705     return gas_parser_dir_fill(parser_gas, e, sz, val);
    706 }
    707 
    708 /* Section directives */
    709 
    710 static yasm_bytecode *
    711 dir_bss_section(yasm_parser_gas *parser_gas, unsigned int param)
    712 {
    713     gas_switch_section(parser_gas, ".bss", NULL, NULL, NULL, 1);
    714     return NULL;
    715 }
    716 
    717 static yasm_bytecode *
    718 dir_data_section(yasm_parser_gas *parser_gas, unsigned int param)
    719 {
    720     gas_switch_section(parser_gas, ".data", NULL, NULL, NULL, 1);
    721     return NULL;
    722 }
    723 
    724 static yasm_bytecode *
    725 dir_text_section(yasm_parser_gas *parser_gas, unsigned int param)
    726 {
    727     gas_switch_section(parser_gas, ".text", NULL, NULL, NULL, 1);
    728     return NULL;
    729 }
    730 
    731 static yasm_bytecode *
    732 dir_section(yasm_parser_gas *parser_gas, unsigned int param)
    733 {
    734     /* DIR_SECTION ID ',' STRING ',' '@' ID ',' dirvals */
    735     char *sectname, *flags = NULL, *type = NULL;
    736     yasm_valparamhead vps;
    737     int have_vps = 0;
    738 
    739     if (!expect(ID)) return NULL;
    740     sectname = ID_val;
    741     get_next_token(); /* ID */
    742 
    743     if (curtok == ',') {
    744         get_next_token(); /* ',' */
    745         if (!expect(STRING)) {
    746             yasm_error_set(YASM_ERROR_SYNTAX,
    747                            N_("flag string expected"));
    748             yasm_xfree(sectname);
    749             return NULL;
    750         }
    751         flags = STRING_val.contents;
    752         get_next_token(); /* STRING */
    753     }
    754 
    755     if (curtok == ',') {
    756         get_next_token(); /* ',' */
    757         if (!expect('@')) {
    758             yasm_xfree(sectname);
    759             yasm_xfree(flags);
    760             return NULL;
    761         }
    762         get_next_token(); /* '@' */
    763         if (!expect(ID)) {
    764             yasm_xfree(sectname);
    765             yasm_xfree(flags);
    766             return NULL;
    767         }
    768         type = ID_val;
    769         get_next_token(); /* ID */
    770     }
    771 
    772     if (curtok == ',') {
    773         get_next_token(); /* ',' */
    774         if (parse_dirvals(parser_gas, &vps))
    775             have_vps = 1;
    776     }
    777 
    778     gas_switch_section(parser_gas, sectname, flags, type,
    779                        have_vps ? &vps : NULL, 0);
    780     yasm_xfree(sectname);
    781     yasm_xfree(flags);
    782     return NULL;
    783 }
    784 
    785 /* Other directives */
    786 
    787 static yasm_bytecode *
    788 dir_equ(yasm_parser_gas *parser_gas, unsigned int param)
    789 {
    790     yasm_expr *e;
    791     char *id;
    792 
    793     /* ID ',' expr */
    794     if (!expect(ID)) return NULL;
    795     id = ID_val;
    796     get_next_token(); /* ID */
    797     if (!expect(',')) {
    798         yasm_xfree(id);
    799         return NULL;
    800     }
    801     get_next_token(); /* ',' */
    802     e = parse_expr(parser_gas);
    803     if (e)
    804         yasm_symtab_define_equ(p_symtab, id, e, cur_line);
    805     else
    806         yasm_error_set(YASM_ERROR_SYNTAX,
    807                        N_("expression expected after `%s'"), ",");
    808     yasm_xfree(id);
    809     return NULL;
    810 }
    811 
    812 static yasm_bytecode *
    813 dir_file(yasm_parser_gas *parser_gas, unsigned int param)
    814 {
    815     yasm_valparamhead vps;
    816     yasm_valparam *vp;
    817 
    818     if (curtok == STRING) {
    819         /* No file number; this form also sets the assembler's
    820          * internal line number.
    821          */
    822         char *filename = STRING_val.contents;
    823 
    824         get_next_token(); /* STRING */
    825         if (parser_gas->dir_fileline == 3) {
    826             /* Have both file and line */
    827             const char *old_fn;
    828             unsigned long old_line;
    829 
    830             yasm_linemap_lookup(parser_gas->linemap, cur_line, &old_fn,
    831                                 &old_line);
    832             yasm_linemap_set(parser_gas->linemap, filename, 0, old_line,
    833                              1);
    834         } else if (parser_gas->dir_fileline == 2) {
    835             /* Had previous line directive only */
    836             parser_gas->dir_fileline = 3;
    837             yasm_linemap_set(parser_gas->linemap, filename, 0,
    838                              parser_gas->dir_line, 1);
    839         } else {
    840             /* Didn't see line yet, save file */
    841             parser_gas->dir_fileline = 1;
    842             if (parser_gas->dir_file)
    843                 yasm_xfree(parser_gas->dir_file);
    844             parser_gas->dir_file = yasm__xstrdup(filename);
    845         }
    846 
    847         /* Pass change along to debug format */
    848         yasm_vps_initialize(&vps);
    849         vp = yasm_vp_create_string(NULL, filename);
    850         yasm_vps_append(&vps, vp);
    851 
    852         yasm_object_directive(p_object, ".file", "gas", &vps, NULL,
    853                               cur_line);
    854 
    855         yasm_vps_delete(&vps);
    856         return NULL;
    857     }
    858 
    859     /* fileno filename form */
    860     yasm_vps_initialize(&vps);
    861 
    862     if (!expect(INTNUM)) return NULL;
    863     vp = yasm_vp_create_expr(NULL,
    864         p_expr_new_ident(yasm_expr_int(INTNUM_val)));
    865     yasm_vps_append(&vps, vp);
    866     get_next_token(); /* INTNUM */
    867 
    868     if (!expect(STRING)) {
    869         yasm_vps_delete(&vps);
    870         return NULL;
    871     }
    872     vp = yasm_vp_create_string(NULL, STRING_val.contents);
    873     yasm_vps_append(&vps, vp);
    874     get_next_token(); /* STRING */
    875 
    876     yasm_object_directive(p_object, ".file", "gas", &vps, NULL,
    877                           cur_line);
    878 
    879     yasm_vps_delete(&vps);
    880     return NULL;
    881 }
    882 
    883 
    884 static yasm_bytecode *
    885 dir_intel_syntax(yasm_parser_gas *parser_gas, unsigned int param)
    886 {
    887     parser_gas->intel_syntax = 1;
    888 
    889     do {
    890         destroy_curtok();
    891         get_next_token();
    892     } while (!is_eol());
    893     return NULL;
    894 }
    895 
    896 static yasm_bytecode *
    897 dir_att_syntax(yasm_parser_gas *parser_gas, unsigned int param)
    898 {
    899     parser_gas->intel_syntax = 0;
    900     return NULL;
    901 }
    902 
    903 static yasm_bytecode *
    904 parse_instr(yasm_parser_gas *parser_gas)
    905 {
    906     yasm_bytecode *bc;
    907     char *id;
    908     size_t id_len;
    909     uintptr_t prefix;
    910 
    911     if (parser_gas->intel_syntax) {
    912         bc = parse_instr_intel(parser_gas);
    913         if (bc) {
    914             yasm_warn_disable(YASM_WARN_UNREC_CHAR);
    915              do {
    916                 destroy_curtok();
    917                 get_next_token();
    918             } while (!is_eol());
    919             yasm_warn_enable(YASM_WARN_UNREC_CHAR);
    920         }
    921         return bc;
    922     }
    923 
    924     if (curtok != ID)
    925         return NULL;
    926 
    927     id = ID_val;
    928     id_len = ID_len;
    929 
    930     /* instructions/prefixes must start with a letter */
    931     if (!isalpha(id[0]))
    932         return NULL;
    933 
    934     /* check to be sure it's not a label or equ */
    935     get_peek_token(parser_gas);
    936     if (parser_gas->peek_token == ':' || parser_gas->peek_token == '=')
    937         return NULL;
    938 
    939     switch (yasm_arch_parse_check_insnprefix
    940             (p_object->arch, ID_val, ID_len, cur_line, &bc, &prefix)) {
    941         case YASM_ARCH_INSN:
    942         {
    943             yasm_insn *insn;
    944 
    945             /* Propagate errors in case we got a warning from the arch */
    946             yasm_errwarn_propagate(parser_gas->errwarns, cur_line);
    947 
    948             insn = yasm_bc_get_insn(bc);
    949 
    950             yasm_xfree(id);
    951             get_next_token();   /* ID */
    952             if (is_eol())
    953                 return bc;      /* no operands */
    954 
    955             /* parse operands */
    956             for (;;) {
    957                 yasm_insn_operand *op = parse_operand(parser_gas);
    958                 if (!op) {
    959                     yasm_error_set(YASM_ERROR_SYNTAX,
    960                                    N_("expression syntax error"));
    961                     yasm_bc_destroy(bc);
    962                     return NULL;
    963                 }
    964                 yasm_insn_ops_append(insn, op);
    965 
    966                 if (is_eol())
    967                     break;
    968                 if (!expect(',')) {
    969                     yasm_bc_destroy(bc);
    970                     return NULL;
    971                 }
    972                 get_next_token();
    973             }
    974             return bc;
    975         }
    976         case YASM_ARCH_PREFIX:
    977             /* Propagate errors in case we got a warning from the arch */
    978             yasm_errwarn_propagate(parser_gas->errwarns, cur_line);
    979 
    980             yasm_xfree(id);
    981             get_next_token();   /* ID */
    982             bc = parse_instr(parser_gas);
    983             if (!bc)
    984                 bc = yasm_arch_create_empty_insn(p_object->arch, cur_line);
    985             yasm_insn_add_prefix(yasm_bc_get_insn(bc), prefix);
    986             return bc;
    987         default:
    988             break;
    989     }
    990 
    991     /* Check for segment register used as prefix */
    992     switch (yasm_arch_parse_check_regtmod(p_object->arch, ID_val, ID_len,
    993                                           &prefix)) {
    994         case YASM_ARCH_SEGREG:
    995             yasm_xfree(id);
    996             get_next_token();   /* ID */
    997             bc = parse_instr(parser_gas);
    998             if (!bc)
    999                 bc = yasm_arch_create_empty_insn(p_object->arch, cur_line);
   1000             yasm_insn_add_seg_prefix(yasm_bc_get_insn(bc), prefix);
   1001             return bc;
   1002         default:
   1003             return NULL;
   1004     }
   1005 }
   1006 
   1007 static int
   1008 parse_dirvals(yasm_parser_gas *parser_gas, yasm_valparamhead *vps)
   1009 {
   1010     yasm_valparam *vp;
   1011     yasm_expr *e;
   1012     int num = 0;
   1013 
   1014     yasm_vps_initialize(vps);
   1015 
   1016     for (;;) {
   1017         switch (curtok) {
   1018             case ID:
   1019                 get_peek_token(parser_gas);
   1020                 switch (parser_gas->peek_token) {
   1021                     case '+': case '-':
   1022                     case '|': case '^': case '&': case '!':
   1023                     case '*': case '/': case '%': case LEFT_OP: case RIGHT_OP:
   1024                         e = parse_expr(parser_gas);
   1025                         vp = yasm_vp_create_expr(NULL, e);
   1026                         break;
   1027                     default:
   1028                         /* Just an ID */
   1029                         vp = yasm_vp_create_id(NULL, ID_val, '\0');
   1030                         get_next_token(); /* ID */
   1031                         break;
   1032                 }
   1033                 break;
   1034             case STRING:
   1035                 vp = yasm_vp_create_string(NULL, STRING_val.contents);
   1036                 get_next_token(); /* STRING */
   1037                 break;
   1038             case REG:
   1039                 e = p_expr_new_ident(yasm_expr_reg(REG_val));
   1040                 vp = yasm_vp_create_expr(NULL, e);
   1041                 get_next_token(); /* REG */
   1042                 break;
   1043             case '@':
   1044                 /* XXX: is throwing it away *really* the right thing? */
   1045                 get_next_token(); /* @ */
   1046                 continue;
   1047             default:
   1048                 e = parse_expr(parser_gas);
   1049                 if (!e)
   1050                     return num;
   1051                 vp = yasm_vp_create_expr(NULL, e);
   1052                 break;
   1053         }
   1054         yasm_vps_append(vps, vp);
   1055         num++;
   1056         if (curtok == ',')
   1057             get_next_token(); /* ',' */
   1058     }
   1059     return num;
   1060 }
   1061 
   1062 static int
   1063 parse_datavals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs)
   1064 {
   1065     yasm_expr *e;
   1066     yasm_dataval *dv;
   1067     int num = 0;
   1068 
   1069     yasm_dvs_initialize(dvs);
   1070 
   1071     for (;;) {
   1072         e = parse_expr(parser_gas);
   1073         if (!e) {
   1074             yasm_dvs_delete(dvs);
   1075             yasm_dvs_initialize(dvs);
   1076             return 0;
   1077         }
   1078         dv = yasm_dv_create_expr(e);
   1079         yasm_dvs_append(dvs, dv);
   1080         num++;
   1081         if (curtok != ',')
   1082             break;
   1083         get_next_token(); /* ',' */
   1084     }
   1085     return num;
   1086 }
   1087 
   1088 static int
   1089 parse_strvals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs)
   1090 {
   1091     yasm_dataval *dv;
   1092     int num = 0;
   1093 
   1094     yasm_dvs_initialize(dvs);
   1095 
   1096     for (;;) {
   1097         if (!expect(STRING)) {
   1098             yasm_dvs_delete(dvs);
   1099             yasm_dvs_initialize(dvs);
   1100             return 0;
   1101         }
   1102         dv = yasm_dv_create_string(STRING_val.contents, STRING_val.len);
   1103         yasm_dvs_append(dvs, dv);
   1104         get_next_token(); /* STRING */
   1105         num++;
   1106         if (curtok != ',')
   1107             break;
   1108         get_next_token(); /* ',' */
   1109     }
   1110     return num;
   1111 }
   1112 
   1113 /* instruction operands */
   1114 /* memory addresses */
   1115 static yasm_effaddr *
   1116 parse_memaddr(yasm_parser_gas *parser_gas)
   1117 {
   1118     yasm_effaddr *ea = NULL;
   1119     yasm_expr *e1, *e2;
   1120     int strong = 0;
   1121 
   1122     if (curtok == SEGREG) {
   1123         uintptr_t segreg = SEGREG_val;
   1124         get_next_token(); /* SEGREG */
   1125         if (!expect(':')) return NULL;
   1126         get_next_token(); /* ':' */
   1127         ea = parse_memaddr(parser_gas);
   1128         if (!ea)
   1129             return NULL;
   1130         yasm_ea_set_segreg(ea, segreg);
   1131         return ea;
   1132     }
   1133 
   1134     /* We want to parse a leading expression, except when it's actually
   1135      * just a memory address (with no preceding expression) such as
   1136      * (REG...) or (,...).
   1137      */
   1138     get_peek_token(parser_gas);
   1139     if (curtok != '(' || (parser_gas->peek_token != REG
   1140                           && parser_gas->peek_token != ','))
   1141         e1 = parse_expr(parser_gas);
   1142     else
   1143         e1 = NULL;
   1144 
   1145     if (curtok == '(') {
   1146         int havereg = 0;
   1147         uintptr_t reg = 0;
   1148         yasm_intnum *scale = NULL;
   1149 
   1150         get_next_token(); /* '(' */
   1151 
   1152         /* base register */
   1153         if (curtok == REG) {
   1154             e2 = p_expr_new_ident(yasm_expr_reg(REG_val));
   1155             get_next_token(); /* REG */
   1156         } else
   1157             e2 = p_expr_new_ident(yasm_expr_int(yasm_intnum_create_uint(0)));
   1158 
   1159         if (curtok == ')')
   1160             goto done;
   1161 
   1162         if (!expect(',')) {
   1163             yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid memory expression"));
   1164             if (e1) yasm_expr_destroy(e1);
   1165             yasm_expr_destroy(e2);
   1166             return NULL;
   1167         }
   1168         get_next_token(); /* ',' */
   1169 
   1170         if (curtok == ')')
   1171             goto done;
   1172 
   1173         /* index register */
   1174         if (curtok == REG) {
   1175             reg = REG_val;
   1176             havereg = 1;
   1177             get_next_token(); /* REG */
   1178             if (curtok != ',') {
   1179                 scale = yasm_intnum_create_uint(1);
   1180                 goto done;
   1181             }
   1182             get_next_token(); /* ',' */
   1183         }
   1184 
   1185         /* scale */
   1186         if (!expect(INTNUM)) {
   1187             yasm_error_set(YASM_ERROR_SYNTAX, N_("non-integer scale"));
   1188             if (e1) yasm_expr_destroy(e1);
   1189             yasm_expr_destroy(e2);
   1190             return NULL;
   1191         }
   1192         scale = INTNUM_val;
   1193         get_next_token(); /* INTNUM */
   1194 
   1195 done:
   1196         if (!expect(')')) {
   1197             yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid memory expression"));
   1198             if (scale) yasm_intnum_destroy(scale);
   1199             if (e1) yasm_expr_destroy(e1);
   1200             yasm_expr_destroy(e2);
   1201             return NULL;
   1202         }
   1203         get_next_token(); /* ')' */
   1204 
   1205         if (scale) {
   1206             if (!havereg) {
   1207                 if (yasm_intnum_get_uint(scale) != 1)
   1208                     yasm_warn_set(YASM_WARN_GENERAL,
   1209                         N_("scale factor of %u without an index register"),
   1210                         yasm_intnum_get_uint(scale));
   1211                 yasm_intnum_destroy(scale);
   1212             } else
   1213                 e2 = p_expr_new(yasm_expr_expr(e2), YASM_EXPR_ADD,
   1214                     yasm_expr_expr(p_expr_new(yasm_expr_reg(reg), YASM_EXPR_MUL,
   1215                                               yasm_expr_int(scale))));
   1216         }
   1217 
   1218         if (e1) {
   1219             /* Ordering is critical here to correctly detecting presence of
   1220              * RIP in RIP-relative expressions.
   1221              */
   1222             e1 = p_expr_new_tree(e2, YASM_EXPR_ADD, e1);
   1223         } else
   1224             e1 = e2;
   1225         strong = 1;
   1226     }
   1227 
   1228     if (!e1)
   1229         return NULL;
   1230     ea = yasm_arch_ea_create(p_object->arch, e1);
   1231     if (strong)
   1232         ea->strong = 1;
   1233     return ea;
   1234 }
   1235 
   1236 static yasm_insn_operand *
   1237 parse_operand(yasm_parser_gas *parser_gas)
   1238 {
   1239     yasm_effaddr *ea;
   1240     yasm_insn_operand *op;
   1241     uintptr_t reg;
   1242 
   1243     switch (curtok) {
   1244         case REG:
   1245             reg = REG_val;
   1246             get_next_token(); /* REG */
   1247             return yasm_operand_create_reg(reg);
   1248         case SEGREG:
   1249             /* need to see if it's really a memory address */
   1250             get_peek_token(parser_gas);
   1251             if (parser_gas->peek_token == ':') {
   1252                 ea = parse_memaddr(parser_gas);
   1253                 if (!ea)
   1254                     return NULL;
   1255                 return yasm_operand_create_mem(ea);
   1256             }
   1257             reg = SEGREG_val;
   1258             get_next_token(); /* SEGREG */
   1259             return yasm_operand_create_segreg(reg);
   1260         case REGGROUP:
   1261         {
   1262             unsigned long regindex;
   1263             reg = REGGROUP_val;
   1264             get_next_token(); /* REGGROUP */
   1265             if (curtok != '(')
   1266                 return yasm_operand_create_reg(reg);
   1267             get_next_token(); /* '(' */
   1268             if (!expect(INTNUM)) {
   1269                 yasm_error_set(YASM_ERROR_SYNTAX,
   1270                                N_("integer register index expected"));
   1271                 return NULL;
   1272             }
   1273             regindex = yasm_intnum_get_uint(INTNUM_val);
   1274             get_next_token(); /* INTNUM */
   1275             if (!expect(')')) {
   1276                 yasm_error_set(YASM_ERROR_SYNTAX,
   1277                     N_("missing closing parenthesis for register index"));
   1278                 return NULL;
   1279             }
   1280             get_next_token(); /* ')' */
   1281             reg = yasm_arch_reggroup_get_reg(p_object->arch, reg, regindex);
   1282             if (reg == 0) {
   1283                 yasm_error_set(YASM_ERROR_SYNTAX, N_("bad register index `%u'"),
   1284                                regindex);
   1285                 return NULL;
   1286             }
   1287             return yasm_operand_create_reg(reg);
   1288         }
   1289         case '$':
   1290         {
   1291             yasm_expr *e;
   1292             get_next_token(); /* '$' */
   1293             e = parse_expr(parser_gas);
   1294             if (!e) {
   1295                 yasm_error_set(YASM_ERROR_SYNTAX,
   1296                                N_("expression missing after `%s'"), "$");
   1297                 return NULL;
   1298             }
   1299             return yasm_operand_create_imm(e);
   1300         }
   1301         case '*':
   1302             get_next_token(); /* '*' */
   1303             if (curtok == REG) {
   1304                 op = yasm_operand_create_reg(REG_val);
   1305                 get_next_token(); /* REG */
   1306             } else {
   1307                 ea = parse_memaddr(parser_gas);
   1308                 if (!ea) {
   1309                     yasm_error_set(YASM_ERROR_SYNTAX,
   1310                                    N_("expression missing after `%s'"), "*");
   1311                     return NULL;
   1312                 }
   1313                 op = yasm_operand_create_mem(ea);
   1314             }
   1315             op->deref = 1;
   1316             return op;
   1317         default:
   1318             ea = parse_memaddr(parser_gas);
   1319             if (!ea)
   1320                 return NULL;
   1321             return yasm_operand_create_mem(ea);
   1322     }
   1323 }
   1324 
   1325 /* Expression grammar parsed is:
   1326  *
   1327  * expr  : expr0 [ {+,-} expr0...]
   1328  * expr0 : expr1 [ {|,^,&,!} expr1...]
   1329  * expr1 : expr2 [ {*,/,%,<<,>>} expr2...]
   1330  * expr2 : { ~,+,- } expr2
   1331  *       | (expr)
   1332  *       | symbol
   1333  *       | number
   1334  */
   1335 
   1336 static yasm_expr *
   1337 parse_expr(yasm_parser_gas *parser_gas)
   1338 {
   1339     yasm_expr *e, *f;
   1340     e = parse_expr0(parser_gas);
   1341     if (!e)
   1342         return NULL;
   1343 
   1344     while (curtok == '+' || curtok == '-') {
   1345         int op = curtok;
   1346         get_next_token();
   1347         f = parse_expr0(parser_gas);
   1348         if (!f) {
   1349             yasm_expr_destroy(e);
   1350             return NULL;
   1351         }
   1352 
   1353         switch (op) {
   1354             case '+': e = p_expr_new_tree(e, YASM_EXPR_ADD, f); break;
   1355             case '-': e = p_expr_new_tree(e, YASM_EXPR_SUB, f); break;
   1356         }
   1357     }
   1358     return e;
   1359 }
   1360 
   1361 static yasm_expr *
   1362 parse_expr0(yasm_parser_gas *parser_gas)
   1363 {
   1364     yasm_expr *e, *f;
   1365     e = parse_expr1(parser_gas);
   1366     if (!e)
   1367         return NULL;
   1368 
   1369     while (curtok == '|' || curtok == '^' || curtok == '&' || curtok == '!') {
   1370         int op = curtok;
   1371         get_next_token();
   1372         f = parse_expr1(parser_gas);
   1373         if (!f) {
   1374             yasm_expr_destroy(e);
   1375             return NULL;
   1376         }
   1377 
   1378         switch (op) {
   1379             case '|': e = p_expr_new_tree(e, YASM_EXPR_OR, f); break;
   1380             case '^': e = p_expr_new_tree(e, YASM_EXPR_XOR, f); break;
   1381             case '&': e = p_expr_new_tree(e, YASM_EXPR_AND, f); break;
   1382             case '!': e = p_expr_new_tree(e, YASM_EXPR_NOR, f); break;
   1383         }
   1384     }
   1385     return e;
   1386 }
   1387 
   1388 static yasm_expr *
   1389 parse_expr1(yasm_parser_gas *parser_gas)
   1390 {
   1391     yasm_expr *e, *f;
   1392     e = parse_expr2(parser_gas);
   1393     if (!e)
   1394         return NULL;
   1395 
   1396     while (curtok == '*' || curtok == '/' || curtok == '%' || curtok == LEFT_OP
   1397            || curtok == RIGHT_OP) {
   1398         int op = curtok;
   1399         get_next_token();
   1400         f = parse_expr2(parser_gas);
   1401         if (!f) {
   1402             yasm_expr_destroy(e);
   1403             return NULL;
   1404         }
   1405 
   1406         switch (op) {
   1407             case '*': e = p_expr_new_tree(e, YASM_EXPR_MUL, f); break;
   1408             case '/': e = p_expr_new_tree(e, YASM_EXPR_DIV, f); break;
   1409             case '%': e = p_expr_new_tree(e, YASM_EXPR_MOD, f); break;
   1410             case LEFT_OP: e = p_expr_new_tree(e, YASM_EXPR_SHL, f); break;
   1411             case RIGHT_OP: e = p_expr_new_tree(e, YASM_EXPR_SHR, f); break;
   1412         }
   1413     }
   1414     return e;
   1415 }
   1416 
   1417 static yasm_expr *
   1418 parse_expr2(yasm_parser_gas *parser_gas)
   1419 {
   1420     yasm_expr *e;
   1421     yasm_symrec *sym;
   1422 
   1423     switch (curtok) {
   1424         case '+':
   1425             get_next_token();
   1426             return parse_expr2(parser_gas);
   1427         case '-':
   1428             get_next_token();
   1429             e = parse_expr2(parser_gas);
   1430             if (!e)
   1431                 return NULL;
   1432             return p_expr_new_branch(YASM_EXPR_NEG, e);
   1433         case '~':
   1434             get_next_token();
   1435             e = parse_expr2(parser_gas);
   1436             if (!e)
   1437                 return NULL;
   1438             return p_expr_new_branch(YASM_EXPR_NOT, e);
   1439         case '(':
   1440             get_next_token();
   1441             e = parse_expr(parser_gas);
   1442             if (!e)
   1443                 return NULL;
   1444             if (!expect(')')) {
   1445                 yasm_error_set(YASM_ERROR_SYNTAX, N_("missing parenthesis"));
   1446                 return NULL;
   1447             }
   1448             get_next_token();
   1449             return e;
   1450         case INTNUM:
   1451             e = p_expr_new_ident(yasm_expr_int(INTNUM_val));
   1452             get_next_token();
   1453             return e;
   1454         case FLTNUM:
   1455             e = p_expr_new_ident(yasm_expr_float(FLTNUM_val));
   1456             get_next_token();
   1457             return e;
   1458         case ID:
   1459         {
   1460             char *name = ID_val;
   1461             get_next_token(); /* ID */
   1462 
   1463             /* "." references the current assembly position */
   1464             if (name[1] == '\0' && name[0] == '.')
   1465                 sym = yasm_symtab_define_curpos(p_symtab, ".",
   1466                                                 parser_gas->prev_bc, cur_line);
   1467             else
   1468                 sym = yasm_symtab_use(p_symtab, name, cur_line);
   1469             yasm_xfree(name);
   1470 
   1471             if (curtok == '@') {
   1472                 yasm_symrec *wrt;
   1473                 /* TODO: this is needed for shared objects, e.g. sym@PLT */
   1474                 get_next_token(); /* '@' */
   1475                 if (!expect(ID)) {
   1476                     yasm_error_set(YASM_ERROR_SYNTAX,
   1477                                    N_("expected identifier after `@'"));
   1478                     return NULL;
   1479                 }
   1480                 wrt = yasm_objfmt_get_special_sym(p_object, ID_val, "gas");
   1481                 yasm_xfree(ID_val);
   1482                 get_next_token(); /* ID */
   1483                 if (!wrt) {
   1484                     yasm_warn_set(YASM_WARN_GENERAL,
   1485                                   N_("unrecognized identifier after `@'"));
   1486                     return p_expr_new_ident(yasm_expr_sym(sym));
   1487                 }
   1488                 return p_expr_new(yasm_expr_sym(sym), YASM_EXPR_WRT,
   1489                                   yasm_expr_sym(wrt));
   1490             }
   1491 
   1492             return p_expr_new_ident(yasm_expr_sym(sym));
   1493         }
   1494         default:
   1495             return NULL;
   1496     }
   1497 }
   1498 
   1499 static void
   1500 define_label(yasm_parser_gas *parser_gas, char *name, int local)
   1501 {
   1502     if (!local) {
   1503         if (parser_gas->locallabel_base)
   1504             yasm_xfree(parser_gas->locallabel_base);
   1505         parser_gas->locallabel_base_len = strlen(name);
   1506         parser_gas->locallabel_base =
   1507             yasm_xmalloc(parser_gas->locallabel_base_len+1);
   1508         strcpy(parser_gas->locallabel_base, name);
   1509     }
   1510 
   1511     yasm_symtab_define_label(p_symtab, name, parser_gas->prev_bc, 1,
   1512                              cur_line);
   1513     yasm_xfree(name);
   1514 }
   1515 
   1516 static void
   1517 define_lcomm(yasm_parser_gas *parser_gas, /*@only@*/ char *name,
   1518              yasm_expr *size, /*@null@*/ yasm_expr *align)
   1519 {
   1520     /* Put into .bss section. */
   1521     /*@dependent@*/ yasm_section *bss =
   1522         gas_get_section(parser_gas, yasm__xstrdup(".bss"), NULL, NULL, NULL, 1);
   1523 
   1524     if (align) {
   1525         /* XXX: assume alignment is in bytes, not power-of-two */
   1526         yasm_section_bcs_append(bss, gas_parser_align(parser_gas, bss, align,
   1527                                 NULL, NULL, 0));
   1528     }
   1529 
   1530     yasm_symtab_define_label(p_symtab, name, yasm_section_bcs_last(bss), 1,
   1531                              cur_line);
   1532     yasm_section_bcs_append(bss, yasm_bc_create_reserve(size, 1, cur_line));
   1533     yasm_xfree(name);
   1534 }
   1535 
   1536 static yasm_section *
   1537 gas_get_section(yasm_parser_gas *parser_gas, char *name,
   1538                 /*@null@*/ char *flags, /*@null@*/ char *type,
   1539                 /*@null@*/ yasm_valparamhead *objext_valparams,
   1540                 int builtin)
   1541 {
   1542     yasm_valparamhead vps;
   1543     yasm_valparam *vp;
   1544     char *gasflags;
   1545     yasm_section *new_section;
   1546 
   1547     yasm_vps_initialize(&vps);
   1548     vp = yasm_vp_create_id(NULL, name, '\0');
   1549     yasm_vps_append(&vps, vp);
   1550 
   1551     if (!builtin) {
   1552         if (flags)
   1553             gasflags = yasm__xstrdup(flags);
   1554         else
   1555             gasflags = yasm__xstrdup("");
   1556         vp = yasm_vp_create_string(yasm__xstrdup("gasflags"), gasflags);
   1557         yasm_vps_append(&vps, vp);
   1558         if (type) {
   1559             vp = yasm_vp_create_id(NULL, type, '\0');
   1560             yasm_vps_append(&vps, vp);
   1561         }
   1562     }
   1563 
   1564     new_section = yasm_objfmt_section_switch(p_object, &vps, objext_valparams,
   1565                                              cur_line);
   1566 
   1567     yasm_vps_delete(&vps);
   1568     return new_section;
   1569 }
   1570 
   1571 static void
   1572 gas_switch_section(yasm_parser_gas *parser_gas, const char *name,
   1573                    /*@null@*/ char *flags, /*@null@*/ char *type,
   1574                    /*@null@*/ yasm_valparamhead *objext_valparams,
   1575                    int builtin)
   1576 {
   1577     yasm_section *new_section;
   1578 
   1579     new_section = gas_get_section(parser_gas, yasm__xstrdup(name), flags, type,
   1580                                   objext_valparams, builtin);
   1581     if (new_section) {
   1582         cursect = new_section;
   1583         parser_gas->prev_bc = yasm_section_bcs_last(new_section);
   1584     } else
   1585         yasm_error_set(YASM_ERROR_GENERAL, N_("invalid section name `%s'"),
   1586                        name);
   1587 
   1588     if (objext_valparams)
   1589         yasm_vps_delete(objext_valparams);
   1590 }
   1591 
   1592 static yasm_bytecode *
   1593 gas_parser_align(yasm_parser_gas *parser_gas, yasm_section *sect,
   1594                  yasm_expr *boundval, /*@null@*/ yasm_expr *fillval,
   1595                  /*@null@*/ yasm_expr *maxskipval, int power2)
   1596 {
   1597     yasm_intnum *boundintn;
   1598 
   1599     /* Convert power of two to number of bytes if necessary */
   1600     if (power2)
   1601         boundval = yasm_expr_create(YASM_EXPR_SHL,
   1602                                     yasm_expr_int(yasm_intnum_create_uint(1)),
   1603                                     yasm_expr_expr(boundval), cur_line);
   1604 
   1605     /* Largest .align in the section specifies section alignment. */
   1606     boundintn = yasm_expr_get_intnum(&boundval, 0);
   1607     if (boundintn) {
   1608         unsigned long boundint = yasm_intnum_get_uint(boundintn);
   1609 
   1610         /* Alignments must be a power of two. */
   1611         if (is_exp2(boundint)) {
   1612             if (boundint > yasm_section_get_align(sect))
   1613                 yasm_section_set_align(sect, boundint, cur_line);
   1614         }
   1615     }
   1616 
   1617     return yasm_bc_create_align(boundval, fillval, maxskipval,
   1618                                 yasm_section_is_code(sect) ?
   1619                                     yasm_arch_get_fill(p_object->arch) : NULL,
   1620                                 cur_line);
   1621 }
   1622 
   1623 static yasm_bytecode *
   1624 gas_parser_dir_fill(yasm_parser_gas *parser_gas, /*@only@*/ yasm_expr *repeat,
   1625                     /*@only@*/ /*@null@*/ yasm_expr *size,
   1626                     /*@only@*/ /*@null@*/ yasm_expr *value)
   1627 {
   1628     yasm_datavalhead dvs;
   1629     yasm_bytecode *bc;
   1630     unsigned int ssize;
   1631 
   1632     if (size) {
   1633         /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
   1634         intn = yasm_expr_get_intnum(&size, 0);
   1635         if (!intn) {
   1636             yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
   1637                            N_("size must be an absolute expression"));
   1638             yasm_expr_destroy(repeat);
   1639             yasm_expr_destroy(size);
   1640             if (value)
   1641                 yasm_expr_destroy(value);
   1642             return NULL;
   1643         }
   1644         ssize = yasm_intnum_get_uint(intn);
   1645     } else
   1646         ssize = 1;
   1647 
   1648     if (!value)
   1649         value = yasm_expr_create_ident(
   1650             yasm_expr_int(yasm_intnum_create_uint(0)), cur_line);
   1651 
   1652     yasm_dvs_initialize(&dvs);
   1653     yasm_dvs_append(&dvs, yasm_dv_create_expr(value));
   1654     bc = yasm_bc_create_data(&dvs, ssize, 0, p_object->arch, cur_line);
   1655 
   1656     yasm_bc_set_multiple(bc, repeat);
   1657 
   1658     return bc;
   1659 }
   1660 
   1661 static dir_lookup dirs_static[] = {
   1662     /* FIXME: Whether this is power-of-two or not depends on arch and objfmt. */
   1663     {".align",      dir_align,  0,  INITIAL},
   1664     {".p2align",    dir_align,  1,  INITIAL},
   1665     {".balign",     dir_align,  0,  INITIAL},
   1666     {".org",        dir_org,    0,  INITIAL},
   1667     /* data visibility directives */
   1668     {".local",      dir_local,  0,  INITIAL},
   1669     {".comm",       dir_comm,   0,  INITIAL},
   1670     {".lcomm",      dir_comm,   1,  INITIAL},
   1671     /* integer data declaration directives */
   1672     {".byte",       dir_data,   1,  INITIAL},
   1673     {".2byte",      dir_data,   2,  INITIAL},
   1674     {".4byte",      dir_data,   4,  INITIAL},
   1675     {".8byte",      dir_data,   8,  INITIAL},
   1676     {".16byte",     dir_data,   16, INITIAL},
   1677     /* TODO: These should depend on arch */
   1678     {".short",      dir_data,   2,  INITIAL},
   1679     {".int",        dir_data,   4,  INITIAL},
   1680     {".long",       dir_data,   4,  INITIAL},
   1681     {".hword",      dir_data,   2,  INITIAL},
   1682     {".quad",       dir_data,   8,  INITIAL},
   1683     {".octa",       dir_data,   16, INITIAL},
   1684     /* XXX: At least on x86, this is 2 bytes */
   1685     {".value",      dir_data,   2,  INITIAL},
   1686     /* ASCII data declaration directives */
   1687     {".ascii",      dir_ascii,  0,  INITIAL},   /* no terminating zero */
   1688     {".asciz",      dir_ascii,  1,  INITIAL},   /* add terminating zero */
   1689     {".string",     dir_ascii,  1,  INITIAL},   /* add terminating zero */
   1690     /* LEB128 integer data declaration directives */
   1691     {".sleb128",    dir_leb128, 1,  INITIAL},   /* signed */
   1692     {".uleb128",    dir_leb128, 0,  INITIAL},   /* unsigned */
   1693     /* floating point data declaration directives */
   1694     {".float",      dir_data,   4,  INITIAL},
   1695     {".single",     dir_data,   4,  INITIAL},
   1696     {".double",     dir_data,   8,  INITIAL},
   1697     {".tfloat",     dir_data,   10, INITIAL},
   1698     /* section directives */
   1699     {".bss",        dir_bss_section,    0,  INITIAL},
   1700     {".data",       dir_data_section,   0,  INITIAL},
   1701     {".text",       dir_text_section,   0,  INITIAL},
   1702     {".section",    dir_section,        0, SECTION_DIRECTIVE},
   1703     /* empty space/fill directives */
   1704     {".skip",       dir_skip,   0,  INITIAL},
   1705     {".space",      dir_skip,   0,  INITIAL},
   1706     {".fill",       dir_fill,   0,  INITIAL},
   1707     {".zero",       dir_zero,   0,  INITIAL},
   1708     /* syntax directives */
   1709     {".intel_syntax", dir_intel_syntax, 0, INITIAL},
   1710     {".att_syntax",   dir_att_syntax,   0, INITIAL},
   1711     /* other directives */
   1712     {".equ",        dir_equ,    0,  INITIAL},
   1713     {".file",       dir_file,   0,  INITIAL},
   1714     {".line",       dir_line,   0,  INITIAL},
   1715     {".set",        dir_equ,    0,  INITIAL}
   1716 };
   1717 
   1718 static void
   1719 no_delete(void *data)
   1720 {
   1721 }
   1722 
   1723 void
   1724 gas_parser_parse(yasm_parser_gas *parser_gas)
   1725 {
   1726     dir_lookup word;
   1727     unsigned int i;
   1728     int replace = 1;
   1729 
   1730     word.name = ".word";
   1731     word.handler = dir_data;
   1732     word.param = yasm_arch_wordsize(p_object->arch)/8;
   1733     word.newstate = INITIAL;
   1734 
   1735     /* Create directive lookup */
   1736     parser_gas->dirs = HAMT_create(1, yasm_internal_error_);
   1737     HAMT_insert(parser_gas->dirs, word.name, &word, &replace, no_delete);
   1738     for (i=0; i<NELEMS(dirs_static); i++) {
   1739         replace = 1;
   1740         HAMT_insert(parser_gas->dirs, dirs_static[i].name,
   1741                     &dirs_static[i], &replace, no_delete);
   1742     }
   1743 
   1744     while (get_next_token() != 0) {
   1745         yasm_bytecode *bc = NULL, *temp_bc;
   1746 
   1747         if (!is_eol()) {
   1748             bc = parse_line(parser_gas);
   1749             demand_eol();
   1750         }
   1751 
   1752         yasm_errwarn_propagate(parser_gas->errwarns, cur_line);
   1753 
   1754         temp_bc = yasm_section_bcs_append(cursect, bc);
   1755         if (temp_bc)
   1756             parser_gas->prev_bc = temp_bc;
   1757         if (curtok == ';')
   1758             continue;       /* don't advance line number until \n */
   1759         if (parser_gas->save_input)
   1760             yasm_linemap_add_source(parser_gas->linemap,
   1761                 temp_bc,
   1762                 (char *)parser_gas->save_line[parser_gas->save_last ^ 1]);
   1763         yasm_linemap_goto_next(parser_gas->linemap);
   1764         parser_gas->dir_line++; /* keep track for .line followed by .file */
   1765     }
   1766 
   1767     HAMT_destroy(parser_gas->dirs, no_delete);
   1768 }
   1769