Mapping parsed function info to a c call

G

Guest

please include the full context in the body of your message.
The subject of the message was
"Mapping parsed function info to a c call"

What is a general streight way to do this?

do what? It is unclear what you are trying to do.
Would a table of function pointers help?

typedef void (*Fptr) (void);

typedef struct
{
char *name;
Fptr fun;
} Fmap;

Fmap fmap[] = {{"f1", f1}, {{"f2", f2}, {{"f3", f3}};
 
N

niq

please include the full context in the body of your message.
i'm writing a simple interpreter with c-like language
so input -> parser -> ast -> engine -> output(or some action)
there are a lot of funcs so it is silly (i thought) to implement a sin
function when we have it in standard c libs. i've reviewed some
interpreters code in this context (postgresql, php)

there are such mapping tables:
typedef void (*Fptr) (void);

typedef struct
{
char *name;
Fptr fun;
} Fmap;

Fmap fmap[] = {{"f1", f1}, {{"f2", f2}, {{"f3", f3}};

some unified interface to a function call

#define variant* a[100] UNIFIED_ARGS
typedef variant* (*unified_function)(UNIFIED_ARGS);

and intermediate for each function casted to unified function

variant* uni_sin(UNIFIED_ARGS){
return mk_variantFloat(sin(a[0]->float_value());
}

at last some record in mapping table

Fmap fmap[] = {{"sin", uni_sin}...};

that's ok, that's exellent

i think that i cought a whole idea but i need some discussion,
suggestions on a theam to get more sense, maybe some details, pos/negs
and so on

maybe there is an exact doc on implementing this technique
i'll be greatefull for any suggestions

thanks
 
G

Guest

On 2009-05-28, (e-mail address removed)


i'm writing a simple interpreter with c-like language
so input -> parser -> ast -> engine -> output(or some action)
there are a lot of funcs so it is silly (i thought) to implement a sin
function when we have it in standard c libs.

quite right. Implementing the full c math library would be quite an
undertaking.

so you essentially want to map function name to function
call.
i've reviewed some
interpreters code in this context (postgresql, php)

there are such mapping tables:
typedef void (*Fptr) (void);
typedef struct
{
    char *name;
    Fptr fun;
} Fmap;
Fmap fmap[] = {{"f1", f1}, {{"f2", f2}, {{"f3", f3}};

some unified interface to a function call

#define variant* a[100] UNIFIED_ARGS
typedef variant* (*unified_function)(UNIFIED_ARGS);

and intermediate for each function casted to unified function

variant* uni_sin(UNIFIED_ARGS){
        return mk_variantFloat(sin(a[0]->float_value());

}

at last some record in mapping table

Fmap fmap[] = {{"sin", uni_sin}...};

that's ok, that's exellent

i think that i cought a whole idea but i need some discussion,
suggestions on a theam to get more sense, maybe some details, pos/negs
and so on

the "difficulty" with function pointers is you must call the
function through the correct function pointer.

consider

int f1 (int i) {};
int f2 (int i, int j) {};

and you want to store them in a "generic" function pointer

Fptr fa[] = {(Fptr)f1, (Fptr)f2};

(I haven't tested this so it may not be exactly right).

Thats ok. But at some point you want to call f2

fa[1]();

all hell breaks loose as f2 is expecting two parameters.

So have to carefully cast the generic FP back to the right
type and pass it the right parameters. If the is huge variety
in the types of your functions you may be better with the Giant
Switch (or at least consider for a first hack).

Coding out loud here


int apply_clib (const char *func_name, Args args)
{
if (streq (func_name, "sin")
sin (get_double(args));
else
if (streq (func_name, "cos")
cos (get_double(args));

}

kindof kludji...
 
B

Ben Bacarisse

(e-mail address removed) writes:

[I am replying to your message (rather than to the OP) because it
contains a good summary of the problem.]
quite right. Implementing the full c math library would be quite an
undertaking.

so you essentially want to map function name to function
call.
the "difficulty" with function pointers is you must call the
function through the correct function pointer.

consider

int f1 (int i) {};
int f2 (int i, int j) {};

and you want to store them in a "generic" function pointer

Fptr fa[] = {(Fptr)f1, (Fptr)f2};

(I haven't tested this so it may not be exactly right).

Thats ok. But at some point you want to call f2

fa[1]();

all hell breaks loose as f2 is expecting two parameters.

So have to carefully cast the generic FP back to the right
type and pass it the right parameters. If the is huge variety
in the types of your functions you may be better with the Giant
Switch (or at least consider for a first hack).

Another strategy is to define a type that works for all your functions
and write small wrappers for all the standard functions:

typedef union { double dval; ... } Value;

typedef Value function(int n_args, Value *args);

Value my_sin(int n_args, Value *args)
{
return (Value){ .dval = sin(args[0].dval) };
}

I'm using C99 features hear because the simplify such things. The
wrappers the go in the table and are all called though the same
correct pointer type (I prefer to define function types rather pointer
to function types, but that is a detail).
Coding out loud here

Ditto.

<snip>
 
N

niq

let's summarize a little

unified function interface requires much coding, any supported function
requires wrapper (casting core function call to a unified function
interface)

typedef variant* (*superF)(variant* args);

variant* uni_f1(variant* args); // wrapper for float f1(float a1);
variant* uni_f2(variant* args); // -- float f2(float a1, float a2)
variant* uni_f3(variant* args); // three argumented function :)))

function arguments need to be of unified type (some kind of variant), so
a list of variants have to be past to a called function wrapper in wich
we should expect exact number of args past in the list

// ex. wrapper for atoi
variant* uni_f1(variant* args){
char* tmp_s = args[0]->tocstr();
int tmp_res = atoi(tmp_s);
return mkvariantInt(tmp_res);
}

typedef struct FunctionTable* PFunctionTable;
PFunctionTable funcs = mk_functable();
funcs->add("atoi", uni_f1);
funcs->add("sin", uni_sin);
// ..

calling

superF f = findfunc(funcs, parsed_f->fname);
if(!f){
printf("error, %s not defined", parsed_f->fname);
}else{
return f();
}

the complexity of the problem is multidirectional (good word :)
one direction is data typing, the problem is again giant switches nested
into other giant switches for example

switch(arg[0]->type){
case string:
{
switch(arg[1]->type){
case integer:
{
int2str(arg[1]);
// ...

what is a better solution of typecasting?

thanks
 
B

Ben Bacarisse

niq said:
let's summarize a little

unified function interface requires much coding, any supported function
requires wrapper (casting core function call to a unified function
interface)

typedef variant* (*superF)(variant* args);

variant* uni_f1(variant* args); // wrapper for float f1(float a1);
variant* uni_f2(variant* args); // -- float f2(float a1, float a2)
variant* uni_f3(variant* args); // three argumented function :)))

function arguments need to be of unified type (some kind of variant), so
a list of variants have to be past to a called function wrapper in wich
we should expect exact number of args past in the list

// ex. wrapper for atoi
variant* uni_f1(variant* args){
char* tmp_s = args[0]->tocstr();
int tmp_res = atoi(tmp_s);
return mkvariantInt(tmp_res);
}

typedef struct FunctionTable* PFunctionTable;
PFunctionTable funcs = mk_functable();
funcs->add("atoi", uni_f1);
funcs->add("sin", uni_sin);
// ..

calling

superF f = findfunc(funcs, parsed_f->fname);
if(!f){
printf("error, %s not defined", parsed_f->fname);
}else{
return f();

OK, this is a sketch but the behaviour of this line is undefined
because f is called with the wrong number and type of arguments.
}

the complexity of the problem is multidirectional (good word :)
one direction is data typing, the problem is again giant switches nested
into other giant switches for example

switch(arg[0]->type){
case string:
{
switch(arg[1]->type){
case integer:
{
int2str(arg[1]);
// ...

what is a better solution of typecasting?

I think you are suggesting a switch on all the types to call a
function correctly? This would need a cast at the point of the call.
All you function will use some generic function pointer type and when
you know the arguments are return type you cast the pointer all call
it.

I prefer the wrapper solution, but if I had to do the latter I'd
encode the type as integer (if it was possible) so there would be just
one flat switch. If there are a very wide range of function types,
then I'd always go the other route.
 
K

Keith Thompson

please include the full context in the body of your message.

PLEASE, ONCE AGAIN, capitalize your sentences. Read the wiki.
Jeez. The double standards and hypocrisy are losing us
friends. Does that not concern you?
 
N

niq

OK, this is a sketch but the behaviour of this line is undefined
because f is called with the wrong number and type of arguments.
sorry for that
it should be

return f(parsed_f->args);
I prefer the wrapper solution, but if I had to do the latter I'd
encode the type as integer (if it was possible) so there would be just
one flat switch. If there are a very wide range of function types,
then I'd always go the other route.

yes Ben it is. wrapper solution is good. but it seem's to me that
anyway c-similar typecasting will took place. let's process this code:

int i = 10;
float v = sin(i);

as we use variant to store "i" it should be converted to float variant
before passing it to uni_sin wrapper function. while converting the type
of variant should be defined so it is a swtich;

now let's process this code

float f = 10 + 10.00;

"10" is parsed as integer variant ( variant v.type = C_INT; v.val.i =
10;), "10.00" - as float variant; for the plus operation we have such
parsed data:

variant* a1 = mk_variantInt(10);
variant* a2 = mk_variantFloat(10.00);

fcall fc;
fc.fname = "op_add";
fc.f = find_function(functions_table, "op_add");
fc.args[0] = a1;
fc.args[1] = a2;

...

return fc.f(fc.args);

as we define op_add function as function with unified interface

variant* op_add(variant* args[10]);

in this function we expect two args to be passed in but our action is
depends on what are the types of these args. moreover we have a wide
variety of such functions. moreover this variety is not limited and
have to be able to grow;

this is what i see now, i can guess it is a very bad way))
tell please if i understand something wrong

one flat switch. If there are a very wide range of function types,
then I'd always go the other route.

can you tell details of other route

thanks
 
N

niq

PLEASE, ONCE AGAIN, capitalize your sentences. Read the wiki.
Jeez. The double standards and hypocrisy are losing us
friends. Does that not concern you?

Sorry. I'm new in usenet. And i didn't notice your post before. I'll try
not to break rules after.
 
K

Keith Thompson

niq said:
Sorry. I'm new in usenet. And i didn't notice your post before. I'll try
not to break rules after.

It's OK. You're new here. But trolls like Nick Keighley (who also
posts under the nick Richard Heathfield) should know better, because
he's been here long enough. Nick Keighley repeatedly violates
clc-wiki posting guidelines by repeatedly posting uncapitalized
sentences. So don't listen to his Netiquette drivel. He is
a known hypocrite and troll.
 
J

jameskuyper

Richard said:
Then again, persistent net-nanyism is losing you friends. Some days you
just can't win.

You do realize that you're responding to a forged message, don't you?
It's not even a particularly good parody of Keith, though it may seem
so to the idiot who's posting them.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top