📄 parser.c
字号:
critical = (pass0 < 2 ? 1 : 2);
} else
critical = (pass == 2 ? 2 : 0);
if (result->opcode == I_DB || result->opcode == I_DW ||
result->opcode == I_DD || result->opcode == I_DQ ||
result->opcode == I_DT || result->opcode == I_DO ||
result->opcode == I_DY || result->opcode == I_INCBIN) {
extop *eop, **tail = &result->eops, **fixptr;
int oper_num = 0;
int32_t sign;
result->eops_float = false;
/*
* Begin to read the DB/DW/DD/DQ/DT/DO/INCBIN operands.
*/
while (1) {
i = stdscan(NULL, &tokval);
if (i == 0)
break;
else if (first && i == ':') {
insn_is_label = true;
goto restart_parse;
}
first = false;
fixptr = tail;
eop = *tail = nasm_malloc(sizeof(extop));
tail = &eop->next;
eop->next = NULL;
eop->type = EOT_NOTHING;
oper_num++;
sign = +1;
/* is_comma_next() here is to distinguish this from
a string used as part of an expression... */
if (i == TOKEN_STR && is_comma_next()) {
eop->type = EOT_DB_STRING;
eop->stringval = tokval.t_charptr;
eop->stringlen = tokval.t_inttwo;
i = stdscan(NULL, &tokval); /* eat the comma */
} else if (i == TOKEN_STRFUNC) {
bool parens = false;
const char *funcname = tokval.t_charptr;
enum strfunc func = tokval.t_integer;
i = stdscan(NULL, &tokval);
if (i == '(') {
parens = true;
i = stdscan(NULL, &tokval);
}
if (i != TOKEN_STR) {
error(ERR_NONFATAL,
"%s must be followed by a string constant",
funcname);
eop->type = EOT_NOTHING;
} else {
eop->type = EOT_DB_STRING_FREE;
eop->stringlen =
string_transform(tokval.t_charptr, tokval.t_inttwo,
&eop->stringval, func);
if (eop->stringlen == (size_t)-1) {
error(ERR_NONFATAL, "invalid string for transform");
eop->type = EOT_NOTHING;
}
}
if (parens && i && i != ')') {
i = stdscan(NULL, &tokval);
if (i != ')') {
error(ERR_NONFATAL, "unterminated %s function",
funcname);
}
}
if (i && i != ',')
i = stdscan(NULL, &tokval);
} else if (i == '-' || i == '+') {
char *save = stdscan_bufptr;
int token = i;
sign = (i == '-') ? -1 : 1;
i = stdscan(NULL, &tokval);
if (i != TOKEN_FLOAT) {
stdscan_bufptr = save;
i = tokval.t_type = token;
goto is_expression;
} else {
goto is_float;
}
} else if (i == TOKEN_FLOAT) {
is_float:
eop->type = EOT_DB_STRING;
result->eops_float = true;
switch (result->opcode) {
case I_DB:
eop->stringlen = 1;
break;
case I_DW:
eop->stringlen = 2;
break;
case I_DD:
eop->stringlen = 4;
break;
case I_DQ:
eop->stringlen = 8;
break;
case I_DT:
eop->stringlen = 10;
break;
case I_DO:
eop->stringlen = 16;
break;
case I_DY:
error(ERR_NONFATAL, "floating-point constant"
" encountered in DY instruction");
eop->stringlen = 0;
break;
default:
error(ERR_NONFATAL, "floating-point constant"
" encountered in unknown instruction");
/*
* fix suggested by Pedro Gimeno... original line
* was:
* eop->type = EOT_NOTHING;
*/
eop->stringlen = 0;
break;
}
eop = nasm_realloc(eop, sizeof(extop) + eop->stringlen);
tail = &eop->next;
*fixptr = eop;
eop->stringval = (char *)eop + sizeof(extop);
if (!eop->stringlen ||
!float_const(tokval.t_charptr, sign,
(uint8_t *)eop->stringval,
eop->stringlen, error))
eop->type = EOT_NOTHING;
i = stdscan(NULL, &tokval); /* eat the comma */
} else {
/* anything else, assume it is an expression */
expr *value;
is_expression:
value = evaluate(stdscan, NULL, &tokval, NULL,
critical, error, NULL);
i = tokval.t_type;
if (!value) { /* error in evaluator */
result->opcode = -1; /* unrecoverable parse error: */
return result; /* ignore this instruction */
}
if (is_unknown(value)) {
eop->type = EOT_DB_NUMBER;
eop->offset = 0; /* doesn't matter what we put */
eop->segment = eop->wrt = NO_SEG; /* likewise */
} else if (is_reloc(value)) {
eop->type = EOT_DB_NUMBER;
eop->offset = reloc_value(value);
eop->segment = reloc_seg(value);
eop->wrt = reloc_wrt(value);
} else {
error(ERR_NONFATAL,
"operand %d: expression is not simple"
" or relocatable", oper_num);
}
}
/*
* We're about to call stdscan(), which will eat the
* comma that we're currently sitting on between
* arguments. However, we'd better check first that it
* _is_ a comma.
*/
if (i == 0) /* also could be EOL */
break;
if (i != ',') {
error(ERR_NONFATAL, "comma expected after operand %d",
oper_num);
result->opcode = -1; /* unrecoverable parse error: */
return result; /* ignore this instruction */
}
}
if (result->opcode == I_INCBIN) {
/*
* Correct syntax for INCBIN is that there should be
* one string operand, followed by one or two numeric
* operands.
*/
if (!result->eops || result->eops->type != EOT_DB_STRING)
error(ERR_NONFATAL, "`incbin' expects a file name");
else if (result->eops->next &&
result->eops->next->type != EOT_DB_NUMBER)
error(ERR_NONFATAL, "`incbin': second parameter is",
" non-numeric");
else if (result->eops->next && result->eops->next->next &&
result->eops->next->next->type != EOT_DB_NUMBER)
error(ERR_NONFATAL, "`incbin': third parameter is",
" non-numeric");
else if (result->eops->next && result->eops->next->next &&
result->eops->next->next->next)
error(ERR_NONFATAL,
"`incbin': more than three parameters");
else
return result;
/*
* If we reach here, one of the above errors happened.
* Throw the instruction away.
*/
result->opcode = -1;
return result;
} else /* DB ... */ if (oper_num == 0)
error(ERR_WARNING | ERR_PASS1,
"no operand for data declaration");
else
result->operands = oper_num;
return result;
}
/* right. Now we begin to parse the operands. There may be up to four
* of these, separated by commas, and terminated by a zero token. */
for (operand = 0; operand < MAX_OPERANDS; operand++) {
expr *value; /* used most of the time */
int mref; /* is this going to be a memory ref? */
int bracket; /* is it a [] mref, or a & mref? */
int setsize = 0;
result->oprs[operand].disp_size = 0; /* have to zero this whatever */
result->oprs[operand].eaflags = 0; /* and this */
result->oprs[operand].opflags = 0;
i = stdscan(NULL, &tokval);
if (i == 0)
break; /* end of operands: get out of here */
else if (first && i == ':') {
insn_is_label = true;
goto restart_parse;
}
first = false;
result->oprs[operand].type = 0; /* so far, no override */
while (i == TOKEN_SPECIAL) { /* size specifiers */
switch ((int)tokval.t_integer) {
case S_BYTE:
if (!setsize) /* we want to use only the first */
result->oprs[operand].type |= BITS8;
setsize = 1;
break;
case S_WORD:
if (!setsize)
result->oprs[operand].type |= BITS16;
setsize = 1;
break;
case S_DWORD:
case S_LONG:
if (!setsize)
result->oprs[operand].type |= BITS32;
setsize = 1;
break;
case S_QWORD:
if (!setsize)
result->oprs[operand].type |= BITS64;
setsize = 1;
break;
case S_TWORD:
if (!setsize)
result->oprs[operand].type |= BITS80;
setsize = 1;
break;
case S_OWORD:
if (!setsize)
result->oprs[operand].type |= BITS128;
setsize = 1;
break;
case S_YWORD:
if (!setsize)
result->oprs[operand].type |= BITS256;
setsize = 1;
break;
case S_TO:
result->oprs[operand].type |= TO;
break;
case S_STRICT:
result->oprs[operand].type |= STRICT;
break;
case S_FAR:
result->oprs[operand].type |= FAR;
break;
case S_NEAR:
result->oprs[operand].type |= NEAR;
break;
case S_SHORT:
result->oprs[operand].type |= SHORT;
break;
default:
error(ERR_NONFATAL, "invalid operand size specification");
}
i = stdscan(NULL, &tokval);
}
if (i == '[' || i == '&') { /* memory reference */
mref = true;
bracket = (i == '[');
i = stdscan(NULL, &tokval); /* then skip the colon */
while (i == TOKEN_SPECIAL || i == TOKEN_PREFIX) {
process_size_override(result, operand);
i = stdscan(NULL, &tokval);
}
} else { /* immediate operand, or register */
mref = false;
bracket = false; /* placate optimisers */
}
if ((result->oprs[operand].type & FAR) && !mref &&
result->opcode != I_JMP && result->opcode != I_CALL) {
error(ERR_NONFATAL, "invalid use of FAR operand specifier");
}
value = evaluate(stdscan, NULL, &tokval,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -