386 lines
11 KiB
C
386 lines
11 KiB
C
/*
|
|
* Value/Parameter type functions
|
|
*
|
|
* Copyright (C) 2001-2007 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.
|
|
*
|
|
* 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"
|
|
|
|
#include "libyasm-stdint.h"
|
|
#include "coretype.h"
|
|
#include "valparam.h"
|
|
|
|
#include "errwarn.h"
|
|
#include "intnum.h"
|
|
#include "expr.h"
|
|
#include "symrec.h"
|
|
|
|
#include "section.h"
|
|
|
|
void
|
|
yasm_call_directive(const yasm_directive *directive, yasm_object *object,
|
|
yasm_valparamhead *valparams,
|
|
yasm_valparamhead *objext_valparams, unsigned long line)
|
|
{
|
|
yasm_valparam *vp;
|
|
|
|
if ((directive->flags & (YASM_DIR_ARG_REQUIRED|YASM_DIR_ID_REQUIRED)) &&
|
|
(!valparams || !yasm_vps_first(valparams))) {
|
|
yasm_error_set(YASM_ERROR_SYNTAX,
|
|
N_("directive `%s' requires an argument"),
|
|
directive->name);
|
|
return;
|
|
}
|
|
if (valparams) {
|
|
vp = yasm_vps_first(valparams);
|
|
if ((directive->flags & YASM_DIR_ID_REQUIRED) &&
|
|
vp->type != YASM_PARAM_ID) {
|
|
yasm_error_set(YASM_ERROR_SYNTAX,
|
|
N_("directive `%s' requires an identifier parameter"),
|
|
directive->name);
|
|
return;
|
|
}
|
|
}
|
|
directive->handler(object, valparams, objext_valparams, line);
|
|
}
|
|
|
|
yasm_valparam *
|
|
yasm_vp_create_id(/*@keep@*/ char *v, /*@keep@*/ char *p, int id_prefix)
|
|
{
|
|
yasm_valparam *r = yasm_xmalloc(sizeof(yasm_valparam));
|
|
r->val = v;
|
|
r->type = YASM_PARAM_ID;
|
|
r->param.id = p;
|
|
r->id_prefix = (char)id_prefix;
|
|
return r;
|
|
}
|
|
|
|
yasm_valparam *
|
|
yasm_vp_create_string(/*@keep@*/ char *v, /*@keep@*/ char *p)
|
|
{
|
|
yasm_valparam *r = yasm_xmalloc(sizeof(yasm_valparam));
|
|
r->val = v;
|
|
r->type = YASM_PARAM_STRING;
|
|
r->param.str = p;
|
|
r->id_prefix = '\0';
|
|
return r;
|
|
}
|
|
|
|
yasm_valparam *
|
|
yasm_vp_create_expr(/*@keep@*/ char *v, /*@keep@*/ yasm_expr *p)
|
|
{
|
|
yasm_valparam *r = yasm_xmalloc(sizeof(yasm_valparam));
|
|
r->val = v;
|
|
r->type = YASM_PARAM_EXPR;
|
|
r->param.e = p;
|
|
r->id_prefix = '\0';
|
|
return r;
|
|
}
|
|
|
|
/*@null@*/ /*@only@*/ yasm_expr *
|
|
yasm_vp_expr(const yasm_valparam *vp, yasm_symtab *symtab, unsigned long line)
|
|
{
|
|
if (!vp)
|
|
return NULL;
|
|
switch (vp->type) {
|
|
case YASM_PARAM_ID:
|
|
return yasm_expr_create_ident(yasm_expr_sym(
|
|
yasm_symtab_use(symtab, yasm_vp_id(vp), line)), line);
|
|
case YASM_PARAM_EXPR:
|
|
return yasm_expr_copy(vp->param.e);
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/*@null@*/ /*@dependent@*/ const char *
|
|
yasm_vp_string(const yasm_valparam *vp)
|
|
{
|
|
if (!vp)
|
|
return NULL;
|
|
switch (vp->type) {
|
|
case YASM_PARAM_ID:
|
|
return vp->param.id;
|
|
case YASM_PARAM_STRING:
|
|
return vp->param.str;
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/*@null@*/ /*@dependent@*/ const char *
|
|
yasm_vp_id(const yasm_valparam *vp)
|
|
{
|
|
if (!vp)
|
|
return NULL;
|
|
if (vp->type == YASM_PARAM_ID) {
|
|
if (vp->param.id[0] == vp->id_prefix)
|
|
return &vp->param.id[1];
|
|
else
|
|
return vp->param.id;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
yasm_vps_delete(yasm_valparamhead *headp)
|
|
{
|
|
yasm_valparam *cur, *next;
|
|
|
|
cur = STAILQ_FIRST(headp);
|
|
while (cur) {
|
|
next = STAILQ_NEXT(cur, link);
|
|
if (cur->val)
|
|
yasm_xfree(cur->val);
|
|
switch (cur->type) {
|
|
case YASM_PARAM_ID:
|
|
yasm_xfree(cur->param.id);
|
|
break;
|
|
case YASM_PARAM_STRING:
|
|
yasm_xfree(cur->param.str);
|
|
break;
|
|
case YASM_PARAM_EXPR:
|
|
yasm_expr_destroy(cur->param.e);
|
|
break;
|
|
}
|
|
yasm_xfree(cur);
|
|
cur = next;
|
|
}
|
|
STAILQ_INIT(headp);
|
|
}
|
|
|
|
void
|
|
yasm_vps_print(const yasm_valparamhead *headp, FILE *f)
|
|
{
|
|
const yasm_valparam *vp;
|
|
|
|
if(!headp) {
|
|
fprintf(f, "(none)");
|
|
return;
|
|
}
|
|
|
|
yasm_vps_foreach(vp, headp) {
|
|
if (vp->val)
|
|
fprintf(f, "(\"%s\",", vp->val);
|
|
else
|
|
fprintf(f, "((nil),");
|
|
switch (vp->type) {
|
|
case YASM_PARAM_ID:
|
|
fprintf(f, "%s", vp->param.id);
|
|
break;
|
|
case YASM_PARAM_STRING:
|
|
fprintf(f, "\"%s\"", vp->param.str);
|
|
break;
|
|
case YASM_PARAM_EXPR:
|
|
yasm_expr_print(vp->param.e, f);
|
|
break;
|
|
}
|
|
fprintf(f, ")");
|
|
if (yasm_vps_next(vp))
|
|
fprintf(f, ",");
|
|
}
|
|
}
|
|
|
|
yasm_valparamhead *
|
|
yasm_vps_create(void)
|
|
{
|
|
yasm_valparamhead *headp = yasm_xmalloc(sizeof(yasm_valparamhead));
|
|
yasm_vps_initialize(headp);
|
|
return headp;
|
|
}
|
|
|
|
void
|
|
yasm_vps_destroy(yasm_valparamhead *headp)
|
|
{
|
|
yasm_vps_delete(headp);
|
|
yasm_xfree(headp);
|
|
}
|
|
|
|
int
|
|
yasm_dir_helper(void *obj, yasm_valparam *vp_first, unsigned long line,
|
|
const yasm_dir_help *help, size_t nhelp, void *data,
|
|
int (*helper_valparam) (void *obj, yasm_valparam *vp,
|
|
unsigned long line, void *data))
|
|
{
|
|
yasm_valparam *vp = vp_first;
|
|
int anymatched = 0;
|
|
int matched;
|
|
|
|
if (!vp)
|
|
return 0;
|
|
|
|
do {
|
|
const char *s;
|
|
size_t i;
|
|
|
|
matched = 0;
|
|
if (!vp->val && (s = yasm_vp_id(vp))) {
|
|
for (i=0; i<nhelp; i++) {
|
|
if (help[i].needsparam == 0 &&
|
|
yasm__strcasecmp(s, help[i].name) == 0) {
|
|
if (help[i].helper(obj, vp, line,
|
|
((char *)data)+help[i].off,
|
|
help[i].arg) != 0)
|
|
return -1;
|
|
matched = 1;
|
|
anymatched = 1;
|
|
break;
|
|
}
|
|
}
|
|
} else if (vp->val) {
|
|
for (i=0; i<nhelp; i++) {
|
|
if (help[i].needsparam == 1 &&
|
|
yasm__strcasecmp(vp->val, help[i].name) == 0) {
|
|
if (help[i].helper(obj, vp, line,
|
|
((char *)data)+help[i].off,
|
|
help[i].arg) != 0)
|
|
return -1;
|
|
matched = 1;
|
|
anymatched = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!matched) {
|
|
int final = helper_valparam(obj, vp, line, data);
|
|
if (final < 0)
|
|
return -1;
|
|
if (final > 0)
|
|
anymatched = 1;
|
|
}
|
|
} while((vp = yasm_vps_next(vp)));
|
|
|
|
return anymatched;
|
|
}
|
|
|
|
int
|
|
yasm_dir_helper_flag_or(void *obj, yasm_valparam *vp, unsigned long line,
|
|
void *d, uintptr_t flag)
|
|
{
|
|
unsigned long *flags = (unsigned long *)d;
|
|
*flags |= flag;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
yasm_dir_helper_flag_and(void *obj, yasm_valparam *vp, unsigned long line,
|
|
void *d, uintptr_t flag)
|
|
{
|
|
unsigned long *flags = (unsigned long *)d;
|
|
*flags &= ~flag;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
yasm_dir_helper_flag_set(void *obj, yasm_valparam *vp, unsigned long line,
|
|
void *d, uintptr_t flag)
|
|
{
|
|
unsigned long *flags = (unsigned long *)d;
|
|
*flags = flag;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
yasm_dir_helper_expr(void *obj, yasm_valparam *vp, unsigned long line,
|
|
void *data, uintptr_t arg)
|
|
{
|
|
yasm_object *object = (yasm_object *)obj;
|
|
yasm_expr **expr = (yasm_expr **)data;
|
|
|
|
if (*expr)
|
|
yasm_expr_destroy(*expr);
|
|
if (!(*expr = yasm_vp_expr(vp, object->symtab, line))) {
|
|
yasm_error_set(YASM_ERROR_VALUE, N_("argument to `%s' is not an expression"),
|
|
vp->val);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
yasm_dir_helper_intn(void *obj, yasm_valparam *vp, unsigned long line,
|
|
void *data, uintptr_t arg)
|
|
{
|
|
yasm_object *object = (yasm_object *)obj;
|
|
/*@only@*/ /*@null@*/ yasm_expr *e;
|
|
/*@dependent@*/ /*@null@*/ yasm_intnum *local;
|
|
yasm_intnum **intn = (yasm_intnum **)data;
|
|
|
|
if (*intn)
|
|
yasm_intnum_destroy(*intn);
|
|
if (!(e = yasm_vp_expr(vp, object->symtab, line)) ||
|
|
!(local = yasm_expr_get_intnum(&e, 0))) {
|
|
yasm_error_set(YASM_ERROR_NOT_CONSTANT,
|
|
N_("argument to `%s' is not an integer"),
|
|
vp->val);
|
|
if (e)
|
|
yasm_expr_destroy(e);
|
|
return -1;
|
|
}
|
|
*intn = yasm_intnum_copy(local);
|
|
yasm_expr_destroy(e);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
yasm_dir_helper_string(void *obj, yasm_valparam *vp, unsigned long line,
|
|
void *data, uintptr_t arg)
|
|
{
|
|
/*@dependent@*/ /*@null@*/ const char *local;
|
|
char **s = (char **)data;
|
|
|
|
if (*s)
|
|
yasm_xfree(*s);
|
|
if (!(local = yasm_vp_string(vp))) {
|
|
yasm_error_set(YASM_ERROR_VALUE,
|
|
N_("argument to `%s' is not a string or identifier"),
|
|
vp->val);
|
|
return -1;
|
|
}
|
|
*s = yasm__xstrdup(local);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
yasm_dir_helper_valparam_warn(void *obj, yasm_valparam *vp,
|
|
unsigned long line, void *data)
|
|
{
|
|
const char *s;
|
|
|
|
if (vp->val) {
|
|
yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized qualifier `%s'"),
|
|
vp->val);
|
|
return 0;
|
|
}
|
|
|
|
if ((s = yasm_vp_id(vp)))
|
|
yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized qualifier `%s'"), s);
|
|
else if (vp->type == YASM_PARAM_STRING)
|
|
yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized string qualifier"));
|
|
else
|
|
yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized numeric qualifier"));
|
|
|
|
return 0;
|
|
}
|