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
40typedef 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
47static void cpp_line_marker(yasm_parser_gas *parser_gas);
48static void nasm_line_marker(yasm_parser_gas *parser_gas);
49static yasm_bytecode *parse_instr(yasm_parser_gas *parser_gas);
50static int parse_dirvals(yasm_parser_gas *parser_gas, yasm_valparamhead *vps);
51static int parse_datavals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs);
52static int parse_strvals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs);
53static yasm_effaddr *parse_memaddr(yasm_parser_gas *parser_gas);
54static yasm_insn_operand *parse_operand(yasm_parser_gas *parser_gas);
55static yasm_expr *parse_expr(yasm_parser_gas *parser_gas);
56static yasm_expr *parse_expr0(yasm_parser_gas *parser_gas);
57static yasm_expr *parse_expr1(yasm_parser_gas *parser_gas);
58static yasm_expr *parse_expr2(yasm_parser_gas *parser_gas);
59
60static void define_label(yasm_parser_gas *parser_gas, char *name, int local);
61static void define_lcomm(yasm_parser_gas *parser_gas, /*@only@*/ char *name,
62                         yasm_expr *size, /*@null@*/ yasm_expr *align);
63static 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);
67static 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);
71static 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);
75static 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
85static void
86get_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
97static void
98destroy_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 */
124static void
125demand_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
141static int
142expect_(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
173static yasm_bytecode *
174parse_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*/
272static void
273cpp_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*/
370static void
371nasm_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 */
457static yasm_bytecode *
458dir_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
490static yasm_bytecode *
491dir_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
515static yasm_bytecode *
516dir_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
546static yasm_bytecode *
547dir_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
556static yasm_bytecode *
557dir_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
611static yasm_bytecode *
612dir_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
621static yasm_bytecode *
622dir_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
630static yasm_bytecode *
631dir_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
641static yasm_bytecode *
642dir_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
661static yasm_bytecode *
662dir_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 */
687static yasm_bytecode *
688dir_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
710static yasm_bytecode *
711dir_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
717static yasm_bytecode *
718dir_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
724static yasm_bytecode *
725dir_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
731static yasm_bytecode *
732dir_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
787static yasm_bytecode *
788dir_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
812static yasm_bytecode *
813dir_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
884static yasm_bytecode *
885dir_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
896static yasm_bytecode *
897dir_att_syntax(yasm_parser_gas *parser_gas, unsigned int param)
898{
899    parser_gas->intel_syntax = 0;
900    return NULL;
901}
902
903static yasm_bytecode *
904parse_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
1007static int
1008parse_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
1062static int
1063parse_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
1088static int
1089parse_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 */
1115static yasm_effaddr *
1116parse_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
1195done:
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
1236static yasm_insn_operand *
1237parse_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
1336static yasm_expr *
1337parse_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
1361static yasm_expr *
1362parse_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
1388static yasm_expr *
1389parse_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
1417static yasm_expr *
1418parse_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
1499static void
1500define_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
1516static void
1517define_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
1536static yasm_section *
1537gas_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
1571static void
1572gas_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
1592static yasm_bytecode *
1593gas_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
1623static yasm_bytecode *
1624gas_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
1661static 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
1718static void
1719no_delete(void *data)
1720{
1721}
1722
1723void
1724gas_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