mirror of https://github.com/yasm/yasm.git
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.
790 lines
21 KiB
790 lines
21 KiB
/* |
|
* NASM-compatible bison parser |
|
* |
|
* Copyright (C) 2001 Peter Johnson, Michael Urman |
|
* |
|
* This file is part of YASM. |
|
* |
|
* YASM is free software; you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License as published by |
|
* the Free Software Foundation; either version 2 of the License, or |
|
* (at your option) any later version. |
|
* |
|
* YASM is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with this program; if not, write to the Free Software |
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
*/ |
|
%{ |
|
#include "util.h" |
|
RCSID("$IdPath$"); |
|
|
|
#ifdef STDC_HEADERS |
|
# include <math.h> |
|
#endif |
|
|
|
#include "bitvect.h" |
|
|
|
#include "globals.h" |
|
#include "errwarn.h" |
|
#include "intnum.h" |
|
#include "floatnum.h" |
|
#include "expr.h" |
|
#include "symrec.h" |
|
|
|
#include "bytecode.h" |
|
#include "section.h" |
|
#include "objfmt.h" |
|
|
|
#include "arch.h" |
|
|
|
#include "src/parsers/nasm/nasm-defs.h" |
|
|
|
void init_table(void); |
|
extern int nasm_parser_lex(void); |
|
void nasm_parser_error(const char *); |
|
static void nasm_parser_directive(const char *name, |
|
valparamhead *valparams, |
|
/*@null@*/ valparamhead *objext_valparams); |
|
|
|
extern objfmt *nasm_parser_objfmt; |
|
extern sectionhead nasm_parser_sections; |
|
extern section *nasm_parser_cur_section; |
|
extern char *nasm_parser_locallabel_base; |
|
|
|
static /*@null@*/ bytecode *nasm_parser_prev_bc = (bytecode *)NULL; |
|
static bytecode *nasm_parser_temp_bc; |
|
|
|
/* additional data declarations (dynamically generated) */ |
|
/* @DATADECLS@ */ |
|
|
|
/*@-usedef -nullassign -memtrans -usereleased -compdef -mustfree@*/ |
|
%} |
|
|
|
%union { |
|
unsigned int int_info; |
|
char *str_val; |
|
intnum *intn; |
|
floatnum *flt; |
|
symrec *sym; |
|
unsigned char groupdata[4]; |
|
effaddr *ea; |
|
expr *exp; |
|
immval *im_val; |
|
x86_targetval tgt_val; |
|
datavalhead datahead; |
|
dataval *data; |
|
bytecode *bc; |
|
valparamhead dir_valparams; |
|
valparam *dir_valparam; |
|
} |
|
|
|
%token <intn> INTNUM |
|
%token <flt> FLTNUM |
|
%token <str_val> DIRECTIVE_NAME STRING FILENAME |
|
%token <int_info> BYTE WORD DWORD QWORD TWORD DQWORD |
|
%token <int_info> DECLARE_DATA |
|
%token <int_info> RESERVE_SPACE |
|
%token INCBIN EQU TIMES |
|
%token SEG WRT NEAR SHORT FAR NOSPLIT ORG |
|
%token TO |
|
%token LOCK REPNZ REP REPZ |
|
%token <int_info> OPERSIZE ADDRSIZE |
|
%token <int_info> CR4 CRREG_NOTCR4 DRREG TRREG ST0 FPUREG_NOTST0 MMXREG XMMREG |
|
%token <int_info> REG_EAX REG_ECX REG_EDX REG_EBX |
|
%token <int_info> REG_ESP REG_EBP REG_ESI REG_EDI |
|
%token <int_info> REG_AX REG_CX REG_DX REG_BX REG_SP REG_BP REG_SI REG_DI |
|
%token <int_info> REG_AL REG_CL REG_DL REG_BL REG_AH REG_CH REG_DH REG_BH |
|
%token <int_info> REG_ES REG_CS REG_SS REG_DS REG_FS REG_GS |
|
%token LEFT_OP RIGHT_OP SIGNDIV SIGNMOD START_SECTION_ID |
|
%token <str_val> ID LOCAL_ID SPECIAL_ID |
|
%token LINE |
|
|
|
/* instruction tokens (dynamically generated) */ |
|
/* @TOKENS@ */ |
|
|
|
/* @TYPES@ */ |
|
|
|
%type <bc> line lineexp exp instr instrbase |
|
|
|
%type <int_info> reg_eax reg_ecx |
|
%type <int_info> reg_ax reg_cx reg_dx |
|
%type <int_info> reg_al reg_cl |
|
%type <int_info> reg_es reg_cs reg_ss reg_ds reg_fs reg_gs |
|
%type <int_info> fpureg rawreg32 reg32 rawreg16 reg16 reg8 segreg |
|
%type <ea> mem memaddr memfar |
|
%type <ea> mem8x mem16x mem32x mem64x mem80x mem128x |
|
%type <ea> mem8 mem16 mem32 mem64 mem80 mem128 mem1632 |
|
%type <ea> rm8x rm16x rm32x /*rm64x rm128x*/ |
|
%type <ea> rm8 rm16 rm32 rm64 rm128 |
|
%type <im_val> imm imm8x imm16x imm32x imm8 imm16 imm32 |
|
%type <exp> expr expr_no_string memexpr direxpr |
|
%type <sym> explabel |
|
%type <str_val> label_id |
|
%type <tgt_val> target |
|
%type <data> dataval |
|
%type <datahead> datavals |
|
%type <dir_valparams> directive_valparams |
|
%type <dir_valparam> directive_valparam |
|
|
|
%left '|' |
|
%left '^' |
|
%left '&' |
|
%left LEFT_OP RIGHT_OP |
|
%left '-' '+' |
|
%left '*' '/' SIGNDIV '%' SIGNMOD |
|
%nonassoc UNARYOP |
|
|
|
%% |
|
input: /* empty */ |
|
| input line { |
|
nasm_parser_temp_bc = bcs_append(section_get_bytecodes(nasm_parser_cur_section), |
|
$2); |
|
if (nasm_parser_temp_bc) |
|
nasm_parser_prev_bc = nasm_parser_temp_bc; |
|
line_index++; |
|
} |
|
; |
|
|
|
line: '\n' { $$ = (bytecode *)NULL; } |
|
| lineexp '\n' |
|
| LINE INTNUM '+' INTNUM FILENAME '\n' { |
|
/* %line indicates the line number of the *next* line, so subtract out |
|
* the increment when setting the line number. |
|
*/ |
|
line_set($5, intnum_get_uint($2)-intnum_get_uint($4), |
|
intnum_get_uint($4)); |
|
intnum_delete($2); |
|
intnum_delete($4); |
|
xfree($5); |
|
$$ = (bytecode *)NULL; |
|
} |
|
| directive '\n' { $$ = (bytecode *)NULL; } |
|
| error '\n' { |
|
Error(_("label or instruction expected at start of line")); |
|
$$ = (bytecode *)NULL; |
|
yyerrok; |
|
} |
|
; |
|
|
|
lineexp: exp |
|
| TIMES expr exp { $$ = $3; bc_set_multiple($$, $2); } |
|
| label { $$ = (bytecode *)NULL; } |
|
| label exp { $$ = $2; } |
|
| label TIMES expr exp { $$ = $4; bc_set_multiple($$, $3); } |
|
| label_id EQU expr { |
|
symrec_define_equ($1, $3); |
|
xfree($1); |
|
$$ = (bytecode *)NULL; |
|
} |
|
; |
|
|
|
exp: instr |
|
| DECLARE_DATA datavals { $$ = bc_new_data(&$2, $1); } |
|
| RESERVE_SPACE expr { $$ = bc_new_reserve($2, $1); } |
|
| INCBIN STRING { $$ = bc_new_incbin($2, NULL, NULL); } |
|
| INCBIN STRING ',' expr { $$ = bc_new_incbin($2, $4, NULL); } |
|
| INCBIN STRING ',' expr ',' expr { $$ = bc_new_incbin($2, $4, $6); } |
|
; |
|
|
|
datavals: dataval { dvs_initialize(&$$); dvs_append(&$$, $1); } |
|
| datavals ',' dataval { dvs_append(&$1, $3); $$ = $1; } |
|
; |
|
|
|
dataval: expr_no_string { $$ = dv_new_expr($1); } |
|
| STRING { $$ = dv_new_string($1); } |
|
| error { |
|
Error(_("expression syntax error")); |
|
$$ = (dataval *)NULL; |
|
} |
|
; |
|
|
|
label: label_id { |
|
symrec_define_label($1, nasm_parser_cur_section, nasm_parser_prev_bc, |
|
1); |
|
xfree($1); |
|
} |
|
| label_id ':' { |
|
symrec_define_label($1, nasm_parser_cur_section, nasm_parser_prev_bc, |
|
1); |
|
xfree($1); |
|
} |
|
; |
|
|
|
label_id: ID { |
|
$$ = $1; |
|
if (nasm_parser_locallabel_base) |
|
xfree(nasm_parser_locallabel_base); |
|
nasm_parser_locallabel_base = xstrdup($1); |
|
} |
|
| SPECIAL_ID |
|
| LOCAL_ID |
|
; |
|
|
|
/* directives */ |
|
directive: '[' DIRECTIVE_NAME directive_val ']' { |
|
xfree($2); |
|
} |
|
| '[' DIRECTIVE_NAME error ']' { |
|
Error(_("invalid arguments to [%s]"), $2); |
|
xfree($2); |
|
} |
|
; |
|
|
|
/* $<str_val>0 is the DIRECTIVE_NAME */ |
|
/* After : is (optional) object-format specific extension */ |
|
directive_val: directive_valparams { |
|
nasm_parser_directive($<str_val>0, &$1, NULL); |
|
} |
|
| directive_valparams ':' directive_valparams { |
|
nasm_parser_directive($<str_val>0, &$1, &$3); |
|
} |
|
; |
|
|
|
directive_valparams: directive_valparam { |
|
vps_initialize(&$$); |
|
vps_append(&$$, $1); |
|
} |
|
| directive_valparams directive_valparam { |
|
vps_append(&$1, $2); |
|
$$ = $1; |
|
} |
|
; |
|
|
|
directive_valparam: direxpr { |
|
/* If direxpr is just an ID, put it in val and delete the expr */ |
|
const /*@null@*/ symrec *vp_symrec; |
|
if ((vp_symrec = expr_get_symrec(&$1, 0))) { |
|
vp_new($$, xstrdup(symrec_get_name(vp_symrec)), NULL); |
|
expr_delete($1); |
|
} else |
|
vp_new($$, NULL, $1); |
|
} |
|
| ID '=' direxpr { vp_new($$, $1, $3); } |
|
; |
|
|
|
/* register groupings */ |
|
fpureg: ST0 |
|
| FPUREG_NOTST0 |
|
; |
|
|
|
reg_eax: REG_EAX |
|
| DWORD reg_eax { $$ = $2; } |
|
; |
|
|
|
reg_ecx: REG_ECX |
|
| DWORD reg_ecx { $$ = $2; } |
|
; |
|
|
|
rawreg32: REG_EAX |
|
| REG_ECX |
|
| REG_EDX |
|
| REG_EBX |
|
| REG_ESP |
|
| REG_EBP |
|
| REG_ESI |
|
| REG_EDI |
|
; |
|
|
|
reg32: rawreg32 |
|
| DWORD reg32 { $$ = $2; } |
|
; |
|
|
|
reg_ax: REG_AX |
|
| WORD reg_ax { $$ = $2; } |
|
; |
|
|
|
reg_cx: REG_CX |
|
| WORD reg_cx { $$ = $2; } |
|
; |
|
|
|
reg_dx: REG_DX |
|
| WORD reg_dx { $$ = $2; } |
|
; |
|
|
|
rawreg16: REG_AX |
|
| REG_CX |
|
| REG_DX |
|
| REG_BX |
|
| REG_SP |
|
| REG_BP |
|
| REG_SI |
|
| REG_DI |
|
; |
|
|
|
reg16: rawreg16 |
|
| WORD reg16 { $$ = $2; } |
|
; |
|
|
|
reg_al: REG_AL |
|
| BYTE reg_al { $$ = $2; } |
|
; |
|
|
|
reg_cl: REG_CL |
|
| BYTE reg_cl { $$ = $2; } |
|
; |
|
|
|
reg8: REG_AL |
|
| REG_CL |
|
| REG_DL |
|
| REG_BL |
|
| REG_AH |
|
| REG_CH |
|
| REG_DH |
|
| REG_BH |
|
| BYTE reg8 { $$ = $2; } |
|
; |
|
|
|
reg_es: REG_ES |
|
| WORD reg_es { $$ = $2; } |
|
; |
|
|
|
reg_ss: REG_SS |
|
| WORD reg_ss { $$ = $2; } |
|
; |
|
|
|
reg_ds: REG_DS |
|
| WORD reg_ds { $$ = $2; } |
|
; |
|
|
|
reg_fs: REG_FS |
|
| WORD reg_fs { $$ = $2; } |
|
; |
|
|
|
reg_gs: REG_GS |
|
| WORD reg_gs { $$ = $2; } |
|
; |
|
|
|
reg_cs: REG_CS |
|
| WORD reg_cs { $$ = $2; } |
|
; |
|
|
|
segreg: REG_ES |
|
| REG_SS |
|
| REG_DS |
|
| REG_FS |
|
| REG_GS |
|
| REG_CS |
|
| WORD segreg { $$ = $2; } |
|
; |
|
|
|
/* memory addresses */ |
|
/* FIXME: Is there any way this redundancy can be eliminated? This is almost |
|
* identical to expr: the only difference is that FLTNUM is replaced by |
|
* rawreg16 and rawreg32. |
|
* |
|
* Note that the two can't be just combined because of conflicts caused by imm |
|
* vs. reg. I don't see a simple solution right now to this. |
|
* |
|
* We don't attempt to check memory expressions for validity here. |
|
*/ |
|
memexpr: INTNUM { $$ = expr_new_ident(ExprInt($1)); } |
|
| rawreg16 { $$ = expr_new_ident(ExprReg($1, 16)); } |
|
| rawreg32 { $$ = expr_new_ident(ExprReg($1, 32)); } |
|
| explabel { $$ = expr_new_ident(ExprSym($1)); } |
|
/*| memexpr '||' memexpr { $$ = expr_new_tree($1, EXPR_LOR, $3); }*/ |
|
| memexpr '|' memexpr { $$ = expr_new_tree($1, EXPR_OR, $3); } |
|
| memexpr '^' memexpr { $$ = expr_new_tree($1, EXPR_XOR, $3); } |
|
/*| expr '&&' memexpr { $$ = expr_new_tree($1, EXPR_LAND, $3); }*/ |
|
| memexpr '&' memexpr { $$ = expr_new_tree($1, EXPR_AND, $3); } |
|
/*| memexpr '==' memexpr { $$ = expr_new_tree($1, EXPR_EQUALS, $3); }*/ |
|
/*| memexpr '>' memexpr { $$ = expr_new_tree($1, EXPR_GT, $3); }*/ |
|
/*| memexpr '<' memexpr { $$ = expr_new_tree($1, EXPR_GT, $3); }*/ |
|
/*| memexpr '>=' memexpr { $$ = expr_new_tree($1, EXPR_GE, $3); }*/ |
|
/*| memexpr '<=' memexpr { $$ = expr_new_tree($1, EXPR_GE, $3); }*/ |
|
/*| memexpr '!=' memexpr { $$ = expr_new_tree($1, EXPR_NE, $3); }*/ |
|
| memexpr LEFT_OP memexpr { $$ = expr_new_tree($1, EXPR_SHL, $3); } |
|
| memexpr RIGHT_OP memexpr { $$ = expr_new_tree($1, EXPR_SHR, $3); } |
|
| memexpr '+' memexpr { $$ = expr_new_tree($1, EXPR_ADD, $3); } |
|
| memexpr '-' memexpr { $$ = expr_new_tree($1, EXPR_SUB, $3); } |
|
| memexpr '*' memexpr { $$ = expr_new_tree($1, EXPR_MUL, $3); } |
|
| memexpr '/' memexpr { $$ = expr_new_tree($1, EXPR_DIV, $3); } |
|
| memexpr SIGNDIV memexpr { $$ = expr_new_tree($1, EXPR_SIGNDIV, $3); } |
|
| memexpr '%' memexpr { $$ = expr_new_tree($1, EXPR_MOD, $3); } |
|
| memexpr SIGNMOD memexpr { $$ = expr_new_tree($1, EXPR_SIGNMOD, $3); } |
|
| '+' memexpr %prec UNARYOP { $$ = $2; } |
|
| '-' memexpr %prec UNARYOP { $$ = expr_new_branch(EXPR_NEG, $2); } |
|
/*| '!' memexpr { $$ = expr_new_branch(EXPR_LNOT, $2); }*/ |
|
| '~' memexpr %prec UNARYOP { $$ = expr_new_branch(EXPR_NOT, $2); } |
|
| '(' memexpr ')' { $$ = $2; } |
|
| STRING { |
|
$$ = expr_new_ident(ExprInt(intnum_new_charconst_nasm($1))); |
|
xfree($1); |
|
} |
|
| error { Error(_("invalid effective address")); } |
|
; |
|
|
|
memaddr: memexpr { |
|
$$ = x86_ea_new_expr($1); |
|
x86_ea_set_segment($$, 0); |
|
} |
|
| REG_CS ':' memaddr { $$ = $3; x86_ea_set_segment($$, 0x2E); } |
|
| REG_SS ':' memaddr { $$ = $3; x86_ea_set_segment($$, 0x36); } |
|
| REG_DS ':' memaddr { $$ = $3; x86_ea_set_segment($$, 0x3E); } |
|
| REG_ES ':' memaddr { $$ = $3; x86_ea_set_segment($$, 0x26); } |
|
| REG_FS ':' memaddr { $$ = $3; x86_ea_set_segment($$, 0x64); } |
|
| REG_GS ':' memaddr { $$ = $3; x86_ea_set_segment($$, 0x65); } |
|
| BYTE memaddr { $$ = $2; ea_set_len($$, 1); } |
|
| WORD memaddr { $$ = $2; ea_set_len($$, 2); } |
|
| DWORD memaddr { $$ = $2; ea_set_len($$, 4); } |
|
| NOSPLIT memaddr { $$ = $2; ea_set_nosplit($$, 1); } |
|
; |
|
|
|
mem: '[' memaddr ']' { $$ = $2; } |
|
; |
|
|
|
/* explicit memory */ |
|
mem8x: BYTE mem { $$ = $2; } |
|
| BYTE mem8x { $$ = $2; } |
|
; |
|
mem16x: WORD mem { $$ = $2; } |
|
| WORD mem16x { $$ = $2; } |
|
; |
|
mem32x: DWORD mem { $$ = $2; } |
|
| DWORD mem32x { $$ = $2; } |
|
; |
|
mem64x: QWORD mem { $$ = $2; } |
|
| QWORD mem64x { $$ = $2; } |
|
; |
|
mem80x: TWORD mem { $$ = $2; } |
|
| TWORD mem80x { $$ = $2; } |
|
; |
|
mem128x: DQWORD mem { $$ = $2; } |
|
| DQWORD mem128x { $$ = $2; } |
|
; |
|
|
|
/* FAR memory, for jmp and call */ |
|
memfar: FAR mem { $$ = $2; } |
|
| FAR memfar { $$ = $2; } |
|
; |
|
|
|
/* implicit memory */ |
|
mem8: mem |
|
| mem8x |
|
; |
|
mem16: mem |
|
| mem16x |
|
; |
|
mem32: mem |
|
| mem32x |
|
; |
|
mem64: mem |
|
| mem64x |
|
; |
|
mem80: mem |
|
| mem80x |
|
; |
|
mem128: mem |
|
| mem128x |
|
; |
|
|
|
/* both 16 and 32 bit memory */ |
|
mem1632: mem |
|
| mem16x |
|
| mem32x |
|
; |
|
|
|
/* explicit register or memory */ |
|
rm8x: reg8 { $$ = x86_ea_new_reg($1); } |
|
| mem8x |
|
; |
|
rm16x: reg16 { $$ = x86_ea_new_reg($1); } |
|
| mem16x |
|
; |
|
rm32x: reg32 { $$ = x86_ea_new_reg($1); } |
|
| mem32x |
|
; |
|
/* not needed: |
|
rm64x: MMXREG { $$ = x86_ea_new_reg($1); } |
|
| mem64x |
|
; |
|
rm128x: XMMREG { $$ = x86_ea_new_reg($1); } |
|
| mem128x |
|
; |
|
*/ |
|
|
|
/* implicit register or memory */ |
|
rm8: reg8 { $$ = x86_ea_new_reg($1); } |
|
| mem8 |
|
; |
|
rm16: reg16 { $$ = x86_ea_new_reg($1); } |
|
| mem16 |
|
; |
|
rm32: reg32 { $$ = x86_ea_new_reg($1); } |
|
| mem32 |
|
; |
|
rm64: MMXREG { $$ = x86_ea_new_reg($1); } |
|
| mem64 |
|
; |
|
rm128: XMMREG { $$ = x86_ea_new_reg($1); } |
|
| mem128 |
|
; |
|
|
|
/* immediate values */ |
|
imm: expr { $$ = imm_new_expr($1); } |
|
; |
|
|
|
/* explicit immediates */ |
|
imm8x: BYTE imm { $$ = $2; } |
|
; |
|
imm16x: WORD imm { $$ = $2; } |
|
; |
|
imm32x: DWORD imm { $$ = $2; } |
|
; |
|
|
|
/* implicit immediates */ |
|
imm8: imm |
|
| imm8x |
|
; |
|
imm16: imm |
|
| imm16x |
|
; |
|
imm32: imm |
|
| imm32x |
|
; |
|
|
|
/* jump targets */ |
|
target: expr { |
|
$$.val = $1; |
|
x86_set_jmprel_opcode_sel(&$$.op_sel, JR_NONE); |
|
} |
|
| SHORT target { |
|
$$ = $2; |
|
x86_set_jmprel_opcode_sel(&$$.op_sel, JR_SHORT_FORCED); |
|
} |
|
| NEAR target { |
|
$$ = $2; |
|
x86_set_jmprel_opcode_sel(&$$.op_sel, JR_NEAR_FORCED); |
|
} |
|
; |
|
|
|
/* expression trees */ |
|
|
|
/* expr w/o FLTNUM and unary + and -, for use in directives */ |
|
direxpr: INTNUM { $$ = expr_new_ident(ExprInt($1)); } |
|
| ID { |
|
$$ = expr_new_ident(ExprSym(symrec_define_label($1, NULL, NULL, 0))); |
|
xfree($1); |
|
} |
|
| direxpr '|' direxpr { $$ = expr_new_tree($1, EXPR_OR, $3); } |
|
| direxpr '^' direxpr { $$ = expr_new_tree($1, EXPR_XOR, $3); } |
|
| direxpr '&' direxpr { $$ = expr_new_tree($1, EXPR_AND, $3); } |
|
| direxpr LEFT_OP direxpr { $$ = expr_new_tree($1, EXPR_SHL, $3); } |
|
| direxpr RIGHT_OP direxpr { $$ = expr_new_tree($1, EXPR_SHR, $3); } |
|
| direxpr '+' direxpr { $$ = expr_new_tree($1, EXPR_ADD, $3); } |
|
| direxpr '-' direxpr { $$ = expr_new_tree($1, EXPR_SUB, $3); } |
|
| direxpr '*' direxpr { $$ = expr_new_tree($1, EXPR_MUL, $3); } |
|
| direxpr '/' direxpr { $$ = expr_new_tree($1, EXPR_DIV, $3); } |
|
| direxpr SIGNDIV direxpr { $$ = expr_new_tree($1, EXPR_SIGNDIV, $3); } |
|
| direxpr '%' direxpr { $$ = expr_new_tree($1, EXPR_MOD, $3); } |
|
| direxpr SIGNMOD direxpr { $$ = expr_new_tree($1, EXPR_SIGNMOD, $3); } |
|
/*| '!' expr { $$ = expr_new_branch(EXPR_LNOT, $2); }*/ |
|
| '~' direxpr %prec UNARYOP { $$ = expr_new_branch(EXPR_NOT, $2); } |
|
| '(' direxpr ')' { $$ = $2; } |
|
; |
|
|
|
expr_no_string: INTNUM { $$ = expr_new_ident(ExprInt($1)); } |
|
| FLTNUM { $$ = expr_new_ident(ExprFloat($1)); } |
|
| explabel { $$ = expr_new_ident(ExprSym($1)); } |
|
/*| expr '||' expr { $$ = expr_new_tree($1, EXPR_LOR, $3); }*/ |
|
| expr '|' expr { $$ = expr_new_tree($1, EXPR_OR, $3); } |
|
| expr '^' expr { $$ = expr_new_tree($1, EXPR_XOR, $3); } |
|
/*| expr '&&' expr { $$ = expr_new_tree($1, EXPR_LAND, $3); }*/ |
|
| expr '&' expr { $$ = expr_new_tree($1, EXPR_AND, $3); } |
|
/*| expr '==' expr { $$ = expr_new_tree($1, EXPR_EQUALS, $3); }*/ |
|
/*| expr '>' expr { $$ = expr_new_tree($1, EXPR_GT, $3); }*/ |
|
/*| expr '<' expr { $$ = expr_new_tree($1, EXPR_GT, $3); }*/ |
|
/*| expr '>=' expr { $$ = expr_new_tree($1, EXPR_GE, $3); }*/ |
|
/*| expr '<=' expr { $$ = expr_new_tree($1, EXPR_GE, $3); }*/ |
|
/*| expr '!=' expr { $$ = expr_new_tree($1, EXPR_NE, $3); }*/ |
|
| expr LEFT_OP expr { $$ = expr_new_tree($1, EXPR_SHL, $3); } |
|
| expr RIGHT_OP expr { $$ = expr_new_tree($1, EXPR_SHR, $3); } |
|
| expr '+' expr { $$ = expr_new_tree($1, EXPR_ADD, $3); } |
|
| expr '-' expr { $$ = expr_new_tree($1, EXPR_SUB, $3); } |
|
| expr '*' expr { $$ = expr_new_tree($1, EXPR_MUL, $3); } |
|
| expr '/' expr { $$ = expr_new_tree($1, EXPR_DIV, $3); } |
|
| expr SIGNDIV expr { $$ = expr_new_tree($1, EXPR_SIGNDIV, $3); } |
|
| expr '%' expr { $$ = expr_new_tree($1, EXPR_MOD, $3); } |
|
| expr SIGNMOD expr { $$ = expr_new_tree($1, EXPR_SIGNMOD, $3); } |
|
| '+' expr %prec UNARYOP { $$ = $2; } |
|
| '-' expr %prec UNARYOP { $$ = expr_new_branch(EXPR_NEG, $2); } |
|
/*| '!' expr { $$ = expr_new_branch(EXPR_LNOT, $2); }*/ |
|
| '~' expr %prec UNARYOP { $$ = expr_new_branch(EXPR_NOT, $2); } |
|
| '(' expr ')' { $$ = $2; } |
|
; |
|
|
|
expr: expr_no_string |
|
| STRING { |
|
$$ = expr_new_ident(ExprInt(intnum_new_charconst_nasm($1))); |
|
xfree($1); |
|
} |
|
; |
|
|
|
explabel: ID { |
|
$$ = symrec_use($1); |
|
xfree($1); |
|
} |
|
| SPECIAL_ID { |
|
$$ = symrec_use($1); |
|
xfree($1); |
|
} |
|
| LOCAL_ID { |
|
$$ = symrec_use($1); |
|
xfree($1); |
|
} |
|
| '$' { |
|
$$ = symrec_define_label("$", nasm_parser_cur_section, |
|
nasm_parser_prev_bc, 0); |
|
} |
|
| START_SECTION_ID { |
|
if (section_is_absolute(nasm_parser_cur_section)) { |
|
Error(_("`$$' is not valid within an ABSOLUTE section")); |
|
YYERROR; |
|
} else { |
|
const char *ss_name = section_get_name(nasm_parser_cur_section); |
|
assert(ss_name != NULL); |
|
$$ = symrec_use(ss_name); |
|
} |
|
} |
|
; |
|
|
|
instr: /* empty */ { |
|
idata.opersize=0; idata.op_len=0; idata.ea=NULL; idata.imm=NULL; |
|
$$ = x86_bc_new_insn(&idata); |
|
} |
|
| instrbase |
|
| OPERSIZE instr { $$ = $2; x86_bc_insn_opersize_override($$, $1); } |
|
| ADDRSIZE instr { $$ = $2; x86_bc_insn_addrsize_override($$, $1); } |
|
| REG_CS instr { |
|
$$ = $2; |
|
x86_ea_set_segment(x86_bc_insn_get_ea($$), 0x2E); |
|
} |
|
| REG_SS instr { |
|
$$ = $2; |
|
x86_ea_set_segment(x86_bc_insn_get_ea($$), 0x36); |
|
} |
|
| REG_DS instr { |
|
$$ = $2; |
|
x86_ea_set_segment(x86_bc_insn_get_ea($$), 0x3E); |
|
} |
|
| REG_ES instr { |
|
$$ = $2; |
|
x86_ea_set_segment(x86_bc_insn_get_ea($$), 0x26); |
|
} |
|
| REG_FS instr { |
|
$$ = $2; |
|
x86_ea_set_segment(x86_bc_insn_get_ea($$), 0x64); |
|
} |
|
| REG_GS instr { |
|
$$ = $2; |
|
x86_ea_set_segment(x86_bc_insn_get_ea($$), 0x65); |
|
} |
|
| LOCK instr { $$ = $2; x86_bc_insn_set_lockrep_prefix($$, 0xF0); } |
|
| REPNZ instr { $$ = $2; x86_bc_insn_set_lockrep_prefix($$, 0xF2); } |
|
| REP instr { $$ = $2; x86_bc_insn_set_lockrep_prefix($$, 0xF3); } |
|
| REPZ instr { $$ = $2; x86_bc_insn_set_lockrep_prefix($$, 0xF4); } |
|
; |
|
|
|
/* instruction grammars (dynamically generated) */ |
|
/* @INSTRUCTIONS@ */ |
|
|
|
%% |
|
/*@=usedef =nullassign =memtrans =usereleased =compdef =mustfree@*/ |
|
|
|
static void |
|
nasm_parser_directive(const char *name, valparamhead *valparams, |
|
valparamhead *objext_valparams) |
|
{ |
|
valparam *vp, *vp2; |
|
const intnum *intn; |
|
long lval; |
|
|
|
assert(cur_objfmt != NULL); |
|
|
|
/* Handle (mostly) output-format independent directives here */ |
|
if (strcasecmp(name, "extern") == 0) { |
|
vp = vps_first(valparams); |
|
if (vp->val) |
|
symrec_declare(vp->val, SYM_EXTERN, |
|
cur_objfmt->extern_data_new(vp->val, |
|
objext_valparams)); |
|
else |
|
Error(_("invalid argument to [%s]"), "EXTERN"); |
|
} else if (strcasecmp(name, "global") == 0) { |
|
vp = vps_first(valparams); |
|
if (vp->val) |
|
symrec_declare(vp->val, SYM_GLOBAL, |
|
cur_objfmt->global_data_new(vp->val, |
|
objext_valparams)); |
|
else |
|
Error(_("invalid argument to [%s]"), "GLOBAL"); |
|
} else if (strcasecmp(name, "common") == 0) { |
|
vp = vps_first(valparams); |
|
if (vp->val) { |
|
vp2 = vps_next(vp); |
|
if (!vp2 || (!vp2->val && !vp2->param)) |
|
Error(_("no size specified in %s declaration"), "COMMON"); |
|
else { |
|
if (vp2->val) |
|
symrec_declare(vp->val, SYM_COMMON, |
|
cur_objfmt->common_data_new(vp->val, |
|
expr_new_ident(ExprSym(symrec_use(vp2->val))), |
|
objext_valparams)); |
|
else if (vp2->param) { |
|
symrec_declare(vp->val, SYM_COMMON, |
|
cur_objfmt->common_data_new(vp->val, vp2->param, |
|
objext_valparams)); |
|
vp2->param = NULL; |
|
} |
|
} |
|
} else |
|
Error(_("invalid argument to [%s]"), "COMMON"); |
|
} else if (strcasecmp(name, "section") == 0 || |
|
strcasecmp(name, "segment") == 0) { |
|
section *new_section = |
|
cur_objfmt->sections_switch(&nasm_parser_sections, valparams, |
|
objext_valparams); |
|
if (new_section) { |
|
nasm_parser_cur_section = new_section; |
|
nasm_parser_prev_bc = (bytecode *)NULL; |
|
} else |
|
Error(_("invalid argument to [%s]"), "SECTION"); |
|
} else if (strcasecmp(name, "absolute") == 0) { |
|
/* it can be just an ID or a complete expression, so handle both. */ |
|
vp = vps_first(valparams); |
|
if (vp->val) |
|
nasm_parser_cur_section = |
|
sections_switch_absolute(&nasm_parser_sections, |
|
expr_new_ident(ExprSym(symrec_use(vp->val)))); |
|
else if (vp->param) { |
|
nasm_parser_cur_section = |
|
sections_switch_absolute(&nasm_parser_sections, vp->param); |
|
vp->param = NULL; |
|
} |
|
nasm_parser_prev_bc = (bytecode *)NULL; |
|
} else if (strcasecmp(name, "bits") == 0) { |
|
if ((vp = vps_first(valparams)) && !vp->val && vp->param != NULL && |
|
(intn = expr_get_intnum(&vp->param)) != NULL && |
|
(lval = intnum_get_int(intn)) && (lval == 16 || lval == 32)) |
|
x86_mode_bits = (unsigned char)lval; |
|
else |
|
Error(_("invalid argument to [%s]"), "BITS"); |
|
} else if (cur_objfmt->directive(name, valparams, objext_valparams)) { |
|
Error(_("unrecognized directive [%s]"), name); |
|
} |
|
|
|
vps_delete(valparams); |
|
if (objext_valparams) |
|
vps_delete(objext_valparams); |
|
} |
|
|
|
void |
|
nasm_parser_error(const char *s) |
|
{ |
|
ParserError(s); |
|
} |
|
|
|
|