Yasm Assembler mainline development tree (ffmpeg 依赖)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

884 lines
25 KiB

/*
* GAS-compatible bison parser
*
* Copyright (C) 2005 Peter Johnson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of other contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
%{
#include <util.h>
RCSID("$Id$");
#define YASM_LIB_INTERNAL
#define YASM_EXPR_INTERNAL
#include <libyasm.h>
#ifdef STDC_HEADERS
# include <math.h>
#endif
#include "modules/parsers/gas/gas-parser.h"
#include "modules/parsers/gas/gas-defs.h"
static void define_label(yasm_parser_gas *parser_gas, char *name, int local);
static yasm_section *gas_get_section
(yasm_parser_gas *parser_gas, char *name, /*@null@*/ char *flags,
/*@null@*/ char *type, /*@null@*/ yasm_valparamhead *objext_valparams,
int builtin);
static void gas_switch_section(yasm_parser_gas *parser_gas, char *name,
/*@null@*/ char *flags, /*@null@*/ char *type,
/*@null@*/ yasm_valparamhead *objext_valparams,
int builtin);
static yasm_bytecode *gas_parser_align(yasm_parser_gas *parser_gas,
yasm_valparamhead *valparams,
int power2);
static void gas_parser_directive
(yasm_parser_gas *parser_gas, const char *name,
yasm_valparamhead *valparams,
/*@null@*/ yasm_valparamhead *objext_valparams);
#define gas_parser_error(s) yasm__parser_error(cur_line, s)
#define YYPARSE_PARAM parser_gas_arg
#define YYLEX_PARAM parser_gas_arg
#define parser_gas ((yasm_parser_gas *)parser_gas_arg)
#define gas_parser_debug (parser_gas->debug)
/*@-usedef -nullassign -memtrans -usereleased -compdef -mustfree@*/
%}
%pure_parser
%union {
unsigned int int_info;
char *str_val;
yasm_intnum *intn;
yasm_floatnum *flt;
yasm_symrec *sym;
unsigned long arch_data[4];
yasm_effaddr *ea;
yasm_expr *exp;
yasm_bytecode *bc;
yasm_valparamhead valparams;
yasm_datavalhead datavals;
yasm_dataval *dv;
struct {
yasm_insn_operands operands;
int num_operands;
} insn_operands;
yasm_insn_operand *insn_operand;
struct {
char *contents;
size_t len;
} str;
}
%token <intn> INTNUM
%token <flt> FLTNUM
%token <str> STRING
%token <int_info> SIZE_OVERRIDE
%token <int_info> DECLARE_DATA
%token <int_info> RESERVE_SPACE
%token <arch_data> INSN PREFIX REG REGGROUP SEGREG TARGETMOD
%token LEFT_OP RIGHT_OP
%token <str_val> ID DIR_ID LABEL
%token LINE
%token DIR_2BYTE DIR_4BYTE DIR_ALIGN DIR_ASCII DIR_ASCIZ DIR_BALIGN
%token DIR_BSS DIR_BYTE DIR_COMM DIR_DATA DIR_DOUBLE DIR_ENDR DIR_EXTERN
%token DIR_EQU DIR_FILE DIR_FLOAT DIR_GLOBAL DIR_IDENT DIR_INT DIR_LINE
%token DIR_LOC DIR_LCOMM DIR_OCTA DIR_ORG DIR_P2ALIGN DIR_REPT DIR_SECTION
%token DIR_SHORT DIR_SIZE DIR_SKIP DIR_SLEB128 DIR_STRING DIR_TEXT
%token DIR_TFLOAT DIR_TYPE DIR_QUAD DIR_ULEB128 DIR_VALUE DIR_WEAK DIR_WORD
%token DIR_ZERO
%type <bc> lineexp instr
%type <str_val> expr_id label_id
%type <ea> memaddr
%type <exp> expr regmemexpr
%type <sym> explabel
%type <valparams> dirvals dirvals2
%type <datavals> strvals datavals strvals2 datavals2
%type <insn_operands> operands
%type <insn_operand> operand
%left '-' '+'
%left '|' '&' '^' '!'
%left '*' '/' '%' LEFT_OP RIGHT_OP
%nonassoc UNARYOP
%%
input: /* empty */
| input line {
if (parser_gas->save_input)
yasm_linemap_add_source(parser_gas->linemap,
parser_gas->prev_bc,
parser_gas->save_line[parser_gas->save_last ^ 1]);
yasm_linemap_goto_next(parser_gas->linemap);
}
;
line: '\n'
| linebcs '\n'
| error '\n' {
yasm__error(cur_line,
N_("label or instruction expected at start of line"));
yyerrok;
}
;
linebcs: linebc
| linebc ';' linebcs
;
linebc: lineexp {
parser_gas->temp_bc =
yasm_section_bcs_append(parser_gas->cur_section, $1);
if (parser_gas->temp_bc)
parser_gas->prev_bc = parser_gas->temp_bc;
}
;
lineexp: instr
| label_id ':' {
$$ = (yasm_bytecode *)NULL;
define_label(parser_gas, $1, 0);
}
| label_id ':' instr {
$$ = $3;
define_label(parser_gas, $1, 0);
}
| LABEL {
$$ = (yasm_bytecode *)NULL;
define_label(parser_gas, $1, 0);
}
| LABEL instr {
$$ = $2;
define_label(parser_gas, $1, 0);
}
/* Line directive */
| DIR_LINE INTNUM {
$$ = (yasm_bytecode *)NULL;
if (yasm_intnum_sign($2) < 0)
yasm__error(cur_line, N_("line number is negative"));
else
yasm_linemap_set(parser_gas->linemap, NULL,
yasm_intnum_get_uint($2), 1);
}
/* Macro directives */
| DIR_REPT expr {
yasm_intnum *intn = yasm_expr_get_intnum(&$2, NULL);
$$ = (yasm_bytecode *)NULL;
if (!intn) {
yasm__error(cur_line, N_("rept expression not absolute"));
} else if (yasm_intnum_sign(intn) < 0) {
yasm__error(cur_line, N_("rept expression is negative"));
} else {
gas_rept *rept = yasm_xmalloc(sizeof(gas_rept));
STAILQ_INIT(&rept->lines);
rept->startline = cur_line;
rept->numrept = yasm_intnum_get_uint(intn);
rept->numdone = 0;
rept->line = NULL;
rept->linepos = 0;
rept->ended = 0;
rept->oldbuf = NULL;
rept->oldbuflen = 0;
rept->oldbufpos = 0;
parser_gas->rept = rept;
}
}
| DIR_ENDR {
$$ = (yasm_bytecode *)NULL;
/* Shouldn't ever get here unless we didn't get a DIR_REPT first */
yasm__error(cur_line, N_("endr without matching rept"));
}
/* Alignment directives */
| DIR_ALIGN dirvals2 {
/* FIXME: Whether this is power-of-two or not depends on arch and
* objfmt.
*/
$$ = gas_parser_align(parser_gas, &$2, 0);
}
| DIR_P2ALIGN dirvals2 {
$$ = gas_parser_align(parser_gas, &$2, 1);
}
| DIR_BALIGN dirvals2 {
$$ = gas_parser_align(parser_gas, &$2, 0);
}
| DIR_ORG INTNUM {
/* TODO: support expr instead of intnum */
$$ = yasm_bc_create_org(yasm_intnum_get_uint($2), cur_line);
}
/* Data visibility directives */
| DIR_GLOBAL label_id {
yasm_objfmt_global_declare(parser_gas->objfmt, $2, NULL, cur_line);
yasm_xfree($2);
$$ = NULL;
}
| DIR_COMM label_id ',' expr {
yasm_objfmt_common_declare(parser_gas->objfmt, $2, $4, NULL, cur_line);
yasm_xfree($2);
$$ = NULL;
}
| DIR_COMM label_id ',' expr ',' expr {
/* Give third parameter as objext valparam for use as alignment */
yasm_valparamhead vps;
yasm_valparam *vp;
yasm_vps_initialize(&vps);
vp = yasm_vp_create(NULL, $6);
yasm_vps_append(&vps, vp);
yasm_objfmt_common_declare(parser_gas->objfmt, $2, $4, &vps, cur_line);
yasm_vps_delete(&vps);
yasm_xfree($2);
$$ = NULL;
}
| DIR_EXTERN label_id {
/* Go ahead and do it, even though all undef become extern */
yasm_objfmt_extern_declare(parser_gas->objfmt, $2, NULL, cur_line);
yasm_xfree($2);
$$ = NULL;
}
| DIR_WEAK label_id {
yasm_valparamhead vps;
yasm_valparam *vp;
yasm_vps_initialize(&vps);
vp = yasm_vp_create($2, NULL);
yasm_vps_append(&vps, vp);
yasm_objfmt_directive(parser_gas->objfmt, "weak", &vps, NULL,
cur_line);
yasm_vps_delete(&vps);
$$ = NULL;
}
| DIR_LCOMM label_id ',' expr {
/* Put into .bss section. */
/*@dependent@*/ yasm_section *bss =
gas_get_section(parser_gas, yasm__xstrdup(".bss"), NULL, NULL,
NULL, 1);
/* TODO: default alignment */
yasm_symtab_define_label(p_symtab, $2, yasm_section_bcs_last(bss), 1,
cur_line);
yasm_section_bcs_append(bss, yasm_bc_create_reserve($4, 1, cur_line));
yasm_xfree($2);
$$ = NULL;
}
| DIR_LCOMM label_id ',' expr ',' expr {
/* Put into .bss section. */
/*@dependent@*/ yasm_section *bss =
gas_get_section(parser_gas, yasm__xstrdup(".bss"), NULL, NULL,
NULL, 1);
/* TODO: force alignment */
yasm_symtab_define_label(p_symtab, $2, yasm_section_bcs_last(bss), 1,
cur_line);
yasm_section_bcs_append(bss, yasm_bc_create_reserve($4, 1, cur_line));
yasm_xfree($2);
$$ = NULL;
}
/* Integer data definition directives */
| DIR_ASCII strvals {
$$ = yasm_bc_create_data(&$2, 1, 0, cur_line);
}
| DIR_ASCIZ strvals {
$$ = yasm_bc_create_data(&$2, 1, 1, cur_line);
}
| DIR_BYTE datavals {
$$ = yasm_bc_create_data(&$2, 1, 0, cur_line);
}
| DIR_SHORT datavals {
/* TODO: This should depend on arch */
$$ = yasm_bc_create_data(&$2, 2, 0, cur_line);
}
| DIR_WORD datavals {
$$ = yasm_bc_create_data(&$2, yasm_arch_wordsize(parser_gas->arch), 0,
cur_line);
}
| DIR_INT datavals {
/* TODO: This should depend on arch */
$$ = yasm_bc_create_data(&$2, 4, 0, cur_line);
}
| DIR_VALUE datavals {
/* XXX: At least on x86, this is two bytes */
$$ = yasm_bc_create_data(&$2, 2, 0, cur_line);
}
| DIR_2BYTE datavals {
$$ = yasm_bc_create_data(&$2, 2, 0, cur_line);
}
| DIR_4BYTE datavals {
$$ = yasm_bc_create_data(&$2, 4, 0, cur_line);
}
| DIR_QUAD datavals {
$$ = yasm_bc_create_data(&$2, 8, 0, cur_line);
}
| DIR_OCTA datavals {
$$ = yasm_bc_create_data(&$2, 16, 0, cur_line);
}
| DIR_ZERO expr {
yasm_datavalhead dvs;
yasm_dvs_initialize(&dvs);
yasm_dvs_append(&dvs, yasm_dv_create_expr(
p_expr_new_ident(yasm_expr_int(yasm_intnum_create_uint(0)))));
$$ = yasm_bc_create_data(&dvs, 1, 0, cur_line);
yasm_bc_set_multiple($$, $2);
}
| DIR_SLEB128 datavals {
$$ = yasm_bc_create_leb128(&$2, 1, cur_line);
}
| DIR_ULEB128 datavals {
$$ = yasm_bc_create_leb128(&$2, 0, cur_line);
}
/* Floating point data definition directives */
| DIR_FLOAT datavals {
$$ = yasm_bc_create_data(&$2, 4, 0, cur_line);
}
| DIR_DOUBLE datavals {
$$ = yasm_bc_create_data(&$2, 8, 0, cur_line);
}
| DIR_TFLOAT datavals {
$$ = yasm_bc_create_data(&$2, 10, 0, cur_line);
}
/* Empty space / fill data definition directives */
| DIR_SKIP expr {
$$ = yasm_bc_create_reserve($2, 1, cur_line);
}
| DIR_SKIP expr ',' expr {
yasm_datavalhead dvs;
yasm_dvs_initialize(&dvs);
yasm_dvs_append(&dvs, yasm_dv_create_expr($4));
$$ = yasm_bc_create_data(&dvs, 1, 0, cur_line);
yasm_bc_set_multiple($$, $2);
}
/* Section directives */
| DIR_TEXT {
gas_switch_section(parser_gas, yasm__xstrdup(".text"), NULL, NULL,
NULL, 1);
$$ = NULL;
}
| DIR_DATA {
gas_switch_section(parser_gas, yasm__xstrdup(".data"), NULL, NULL,
NULL, 1);
$$ = NULL;
}
| DIR_BSS {
gas_switch_section(parser_gas, yasm__xstrdup(".bss"), NULL, NULL, NULL,
1);
$$ = NULL;
}
| DIR_SECTION label_id {
gas_switch_section(parser_gas, $2, NULL, NULL, NULL, 0);
$$ = NULL;
}
| DIR_SECTION label_id ',' STRING {
gas_switch_section(parser_gas, $2, $4.contents, NULL, NULL, 0);
$$ = NULL;
}
| DIR_SECTION label_id ',' STRING ',' '@' label_id {
gas_switch_section(parser_gas, $2, $4.contents, $7, NULL, 0);
$$ = NULL;
}
| DIR_SECTION label_id ',' STRING ',' '@' label_id ',' dirvals {
gas_switch_section(parser_gas, $2, $4.contents, $7, &$9, 0);
$$ = NULL;
}
/* Other directives */
| DIR_IDENT strvals {
/* Put text into .comment section. */
/*@dependent@*/ yasm_section *comment =
gas_get_section(parser_gas, yasm__xstrdup(".comment"), NULL, NULL,
NULL, 1);
/* To match GAS output, if the comment section is empty, put an
* initial 0 byte in the section.
*/
if (yasm_section_bcs_first(comment) == yasm_section_bcs_last(comment)) {
yasm_datavalhead dvs;
yasm_dvs_initialize(&dvs);
yasm_dvs_append(&dvs, yasm_dv_create_expr(
p_expr_new_ident(yasm_expr_int(yasm_intnum_create_uint(0)))));
yasm_section_bcs_append(comment,
yasm_bc_create_data(&dvs, 1, 0, cur_line));
}
yasm_section_bcs_append(comment,
yasm_bc_create_data(&$2, 1, 1, cur_line));
$$ = NULL;
}
| DIR_FILE INTNUM STRING {
/* TODO */
$$ = NULL;
}
| DIR_FILE STRING {
/* TODO */
$$ = NULL;
}
| DIR_LOC INTNUM INTNUM INTNUM {
/* TODO */
$$ = NULL;
}
| DIR_TYPE label_id ',' '@' label_id {
yasm_valparamhead vps;
yasm_valparam *vp;
yasm_vps_initialize(&vps);
vp = yasm_vp_create($2, NULL);
yasm_vps_append(&vps, vp);
vp = yasm_vp_create($5, NULL);
yasm_vps_append(&vps, vp);
yasm_objfmt_directive(parser_gas->objfmt, "type", &vps, NULL,
cur_line);
yasm_vps_delete(&vps);
$$ = NULL;
}
| DIR_SIZE label_id ',' expr {
yasm_valparamhead vps;
yasm_valparam *vp;
yasm_vps_initialize(&vps);
vp = yasm_vp_create($2, NULL);
yasm_vps_append(&vps, vp);
vp = yasm_vp_create(NULL, $4);
yasm_vps_append(&vps, vp);
yasm_objfmt_directive(parser_gas->objfmt, "size", &vps, NULL,
cur_line);
yasm_vps_delete(&vps);
$$ = NULL;
}
| DIR_ID dirvals {
yasm__warning(YASM_WARN_GENERAL, cur_line,
N_("directive `%s' not recognized"), $1);
$$ = (yasm_bytecode *)NULL;
yasm_xfree($1);
yasm_vps_delete(&$2);
}
| DIR_ID error {
yasm__warning(YASM_WARN_GENERAL, cur_line,
N_("directive `%s' not recognized"), $1);
$$ = (yasm_bytecode *)NULL;
yasm_xfree($1);
}
| label_id '=' expr {
$$ = (yasm_bytecode *)NULL;
yasm_symtab_define_equ(p_symtab, $1, $3, cur_line);
yasm_xfree($1);
}
;
instr: INSN {
$$ = yasm_bc_create_insn(parser_gas->arch, $1, 0, NULL, cur_line);
}
| INSN operands {
$$ = yasm_bc_create_insn(parser_gas->arch, $1, $2.num_operands,
&$2.operands, cur_line);
}
| INSN error {
yasm__error(cur_line, N_("expression syntax error"));
$$ = NULL;
}
| PREFIX instr {
$$ = $2;
yasm_bc_insn_add_prefix($$, $1);
}
| SEGREG instr {
$$ = $2;
yasm_bc_insn_add_seg_prefix($$, $1[0]);
}
| PREFIX {
$$ = yasm_bc_create_empty_insn(parser_gas->arch, cur_line);
yasm_bc_insn_add_prefix($$, $1);
}
| SEGREG {
$$ = yasm_bc_create_empty_insn(parser_gas->arch, cur_line);
yasm_bc_insn_add_seg_prefix($$, $1[0]);
}
| ID {
yasm__error(cur_line, N_("instruction not recognized: `%s'"), $1);
$$ = NULL;
}
| ID operands {
yasm__error(cur_line, N_("instruction not recognized: `%s'"), $1);
$$ = NULL;
}
| ID error {
yasm__error(cur_line, N_("instruction not recognized: `%s'"), $1);
$$ = NULL;
}
;
dirvals: /* empty */ { yasm_vps_initialize(&$$); }
| dirvals2
;
dirvals2: expr {
yasm_valparam *vp = yasm_vp_create(NULL, $1);
yasm_vps_initialize(&$$);
yasm_vps_append(&$$, vp);
}
| dirvals2 ',' expr {
yasm_valparam *vp = yasm_vp_create(NULL, $3);
yasm_vps_append(&$1, vp);
$$ = $1;
}
| dirvals2 ',' ',' expr {
yasm_valparam *vp = yasm_vp_create(NULL, NULL);
yasm_vps_append(&$1, vp);
vp = yasm_vp_create(NULL, $4);
yasm_vps_append(&$1, vp);
$$ = $1;
}
;
strvals: /* empty */ { yasm_dvs_initialize(&$$); }
| strvals2
;
strvals2: STRING {
yasm_dataval *dv = yasm_dv_create_string($1.contents, $1.len);
yasm_dvs_initialize(&$$);
yasm_dvs_append(&$$, dv);
}
| strvals2 ',' STRING {
yasm_dataval *dv = yasm_dv_create_string($3.contents, $3.len);
yasm_dvs_append(&$1, dv);
$$ = $1;
}
;
datavals: /* empty */ { yasm_dvs_initialize(&$$); }
| datavals2
;
datavals2: expr {
yasm_dataval *dv = yasm_dv_create_expr($1);
yasm_dvs_initialize(&$$);
yasm_dvs_append(&$$, dv);
}
| datavals2 ',' expr {
yasm_dataval *dv = yasm_dv_create_expr($3);
yasm_dvs_append(&$1, dv);
$$ = $1;
}
;
/* instruction operands */
operands: operand {
yasm_ops_initialize(&$$.operands);
yasm_ops_append(&$$.operands, $1);
$$.num_operands = 1;
}
| operands ',' operand {
yasm_ops_append(&$1.operands, $3);
$$.operands = $1.operands;
$$.num_operands = $1.num_operands+1;
}
;
regmemexpr: '(' REG ')' {
$$ = p_expr_new_ident(yasm_expr_reg($2[0]));
}
| '(' ',' REG ')' {
$$ = p_expr_new(yasm_expr_reg($3[0]), YASM_EXPR_MUL,
yasm_expr_int(yasm_intnum_create_uint(1)));
}
| '(' ',' INTNUM ')' {
if (yasm_intnum_get_uint($3) != 1)
yasm__warning(YASM_WARN_GENERAL, cur_line,
N_("scale factor of %u without an index register"),
yasm_intnum_get_uint($3));
$$ = p_expr_new(yasm_expr_int(yasm_intnum_create_uint(0)),
YASM_EXPR_MUL, yasm_expr_int($3));
}
| '(' REG ',' REG ')' {
$$ = p_expr_new(yasm_expr_reg($2[0]), YASM_EXPR_ADD,
yasm_expr_expr(p_expr_new(yasm_expr_reg($4[0]), YASM_EXPR_MUL,
yasm_expr_int(yasm_intnum_create_uint(1)))));
}
| '(' ',' REG ',' INTNUM ')' {
$$ = p_expr_new(yasm_expr_reg($3[0]), YASM_EXPR_MUL,
yasm_expr_int($5));
}
| '(' REG ',' REG ',' INTNUM ')' {
$$ = p_expr_new(yasm_expr_reg($2[0]), YASM_EXPR_ADD,
yasm_expr_expr(p_expr_new(yasm_expr_reg($4[0]), YASM_EXPR_MUL,
yasm_expr_int($6))));
}
;
/* memory addresses */
memaddr: expr {
$$ = yasm_arch_ea_create(parser_gas->arch, $1);
}
| regmemexpr {
$$ = yasm_arch_ea_create(parser_gas->arch, $1);
yasm_ea_set_strong($$, 1);
}
| expr regmemexpr {
$$ = yasm_arch_ea_create(parser_gas->arch,
p_expr_new_tree($2, YASM_EXPR_ADD, $1));
yasm_ea_set_strong($$, 1);
}
| SEGREG ':' memaddr {
$$ = $3;
yasm_ea_set_segreg($$, $1[0], cur_line);
}
;
operand: memaddr { $$ = yasm_operand_create_mem($1); }
| REG { $$ = yasm_operand_create_reg($1[0]); }
| REGGROUP { $$ = yasm_operand_create_reg($1[0]); }
| REGGROUP '(' INTNUM ')' {
unsigned long reg =
yasm_arch_reggroup_get_reg(parser_gas->arch, $1[0],
yasm_intnum_get_uint($3));
if (reg == 0) {
yasm__error(cur_line, N_("bad register index `%u'"),
yasm_intnum_get_uint($3));
$$ = yasm_operand_create_reg($1[0]);
} else
$$ = yasm_operand_create_reg(reg);
yasm_intnum_destroy($3);
}
| '$' expr { $$ = yasm_operand_create_imm($2); }
| '*' REG {
$$ = yasm_operand_create_reg($2[0]);
$$->deref = 1;
}
| '*' memaddr {
$$ = yasm_operand_create_mem($2);
$$->deref = 1;
}
;
/* Expressions */
expr: INTNUM { $$ = p_expr_new_ident(yasm_expr_int($1)); }
| FLTNUM { $$ = p_expr_new_ident(yasm_expr_float($1)); }
| explabel { $$ = p_expr_new_ident(yasm_expr_sym($1)); }
| expr '|' expr { $$ = p_expr_new_tree($1, YASM_EXPR_OR, $3); }
| expr '^' expr { $$ = p_expr_new_tree($1, YASM_EXPR_XOR, $3); }
| expr '&' expr { $$ = p_expr_new_tree($1, YASM_EXPR_AND, $3); }
| expr '!' expr { $$ = p_expr_new_tree($1, YASM_EXPR_NOR, $3); }
| expr LEFT_OP expr { $$ = p_expr_new_tree($1, YASM_EXPR_SHL, $3); }
| expr RIGHT_OP expr { $$ = p_expr_new_tree($1, YASM_EXPR_SHR, $3); }
| expr '+' expr { $$ = p_expr_new_tree($1, YASM_EXPR_ADD, $3); }
| expr '-' expr { $$ = p_expr_new_tree($1, YASM_EXPR_SUB, $3); }
| expr '*' expr { $$ = p_expr_new_tree($1, YASM_EXPR_MUL, $3); }
| expr '/' expr { $$ = p_expr_new_tree($1, YASM_EXPR_DIV, $3); }
| expr '%' expr { $$ = p_expr_new_tree($1, YASM_EXPR_MOD, $3); }
| '+' expr %prec UNARYOP { $$ = $2; }
| '-' expr %prec UNARYOP { $$ = p_expr_new_branch(YASM_EXPR_NEG, $2); }
| '~' expr %prec UNARYOP { $$ = p_expr_new_branch(YASM_EXPR_NOT, $2); }
| '(' expr ')' { $$ = $2; }
;
explabel: expr_id {
/* "." references the current assembly position */
if ($1[1] == '\0' && $1[0] == '.')
$$ = yasm_symtab_define_label(p_symtab, ".", parser_gas->prev_bc,
0, cur_line);
else
$$ = yasm_symtab_use(p_symtab, $1, cur_line);
yasm_xfree($1);
}
| expr_id '@' label_id {
/* TODO: this is needed for shared objects, e.g. sym@PLT */
$$ = yasm_symtab_use(p_symtab, $1, cur_line);
yasm_xfree($1);
yasm_xfree($3);
}
;
expr_id: label_id
| DIR_DATA { $$ = yasm__xstrdup(".data"); }
| DIR_TEXT { $$ = yasm__xstrdup(".text"); }
| DIR_BSS { $$ = yasm__xstrdup(".bss"); }
;
label_id: ID | DIR_ID;
%%
/*@=usedef =nullassign =memtrans =usereleased =compdef =mustfree@*/
#undef parser_gas
static void
define_label(yasm_parser_gas *parser_gas, char *name, int local)
{
if (!local) {
if (parser_gas->locallabel_base)
yasm_xfree(parser_gas->locallabel_base);
parser_gas->locallabel_base_len = strlen(name);
parser_gas->locallabel_base =
yasm_xmalloc(parser_gas->locallabel_base_len+1);
strcpy(parser_gas->locallabel_base, name);
}
yasm_symtab_define_label(p_symtab, name, parser_gas->prev_bc, 1,
cur_line);
yasm_xfree(name);
}
static yasm_section *
gas_get_section(yasm_parser_gas *parser_gas, char *name,
/*@null@*/ char *flags, /*@null@*/ char *type,
/*@null@*/ yasm_valparamhead *objext_valparams,
int builtin)
{
yasm_valparamhead vps;
yasm_valparam *vp;
char *gasflags;
yasm_section *new_section;
yasm_vps_initialize(&vps);
vp = yasm_vp_create(yasm__xstrdup(name), NULL);
yasm_vps_append(&vps, vp);
if (!builtin) {
if (flags) {
gasflags = yasm_xmalloc(5+strlen(flags));
strcpy(gasflags, "gas_");
strcat(gasflags, flags);
} else
gasflags = yasm__xstrdup("gas_");
vp = yasm_vp_create(gasflags, NULL);
yasm_vps_append(&vps, vp);
if (type) {
vp = yasm_vp_create(type, NULL);
yasm_vps_append(&vps, vp);
}
}
new_section = yasm_objfmt_section_switch(parser_gas->objfmt, &vps,
objext_valparams, cur_line);
yasm_vps_delete(&vps);
return new_section;
}
static void
gas_switch_section(yasm_parser_gas *parser_gas, char *name,
/*@null@*/ char *flags, /*@null@*/ char *type,
/*@null@*/ yasm_valparamhead *objext_valparams,
int builtin)
{
yasm_section *new_section;
new_section = gas_get_section(parser_gas, name, flags, type,
objext_valparams, builtin);
if (new_section) {
parser_gas->cur_section = new_section;
parser_gas->prev_bc = yasm_section_bcs_last(new_section);
} else
yasm__error(cur_line, N_("invalid section name `%s'"), name);
}
static yasm_bytecode *
gas_parser_align(yasm_parser_gas *parser_gas, yasm_valparamhead *valparams,
int power2)
{
/*@dependent@*/ yasm_valparam *bound, *fill = NULL, *maxskip = NULL;
yasm_expr *boundval, *fillval = NULL, *maxskipval = NULL;
yasm_intnum *boundintn;
bound = yasm_vps_first(valparams);
boundval = bound->param;
bound->param = NULL;
if (bound && boundval) {
fill = yasm_vps_next(bound);
} else {
yasm__error(cur_line, N_("align directive must specify alignment"));
return NULL;
}
if (fill) {
fillval = fill->param;
fill->param = NULL;
maxskip = yasm_vps_next(fill);
}
if (maxskip) {
maxskipval = maxskip->param;
maxskip->param = NULL;
}
yasm_vps_delete(valparams);
/* Convert power of two to number of bytes if necessary */
if (power2)
boundval = yasm_expr_create(YASM_EXPR_SHL,
yasm_expr_int(yasm_intnum_create_uint(1)),
yasm_expr_expr(boundval), cur_line);
/* If .align is the first bytecode in the section, it's really specifying
* section alignment.
*/
boundintn = yasm_expr_get_intnum(&boundval, NULL);
if (boundintn) {
unsigned long boundint = yasm_intnum_get_uint(boundintn);
/* Alignments must be a power of two. */
if ((boundint & (boundint - 1)) == 0) {
if (boundint > yasm_section_get_align(parser_gas->cur_section))
yasm_section_set_align(parser_gas->cur_section, boundint,
cur_line);
}
}
return yasm_bc_create_align(boundval, fillval, maxskipval,
yasm_section_is_code(parser_gas->cur_section) ?
yasm_arch_get_fill(parser_gas->arch) : NULL,
cur_line);
}
static void
gas_parser_directive(yasm_parser_gas *parser_gas, const char *name,
yasm_valparamhead *valparams,
yasm_valparamhead *objext_valparams)
{
unsigned long line = cur_line;
/* Handle (mostly) output-format independent directives here */
if (!yasm_arch_parse_directive(parser_gas->arch, name, valparams,
objext_valparams, parser_gas->object, line)) {
;
} else if (yasm_objfmt_directive(parser_gas->objfmt, name, valparams,
objext_valparams, line)) {
yasm__error(line, N_("unrecognized directive [%s]"), name);
}
yasm_vps_delete(valparams);
if (objext_valparams)
yasm_vps_delete(objext_valparams);
}