JHines: you can use defn() to access the
body/content of a macro definition, and
defn() allows you to access macros with
names fitting an arbitrary regexp pattern
that won't typically be expanded. So you
can create a macro, and if that macro fits
a unique pattern then it will be treated
a certain way. This way  you can
implement a sort of pseudo-type.

For example, lets create a boolean type
in m4.  In terms of how m4 understands
macros, the canonical description of a
boolean type is already implicit. What
I mean by that is ifelse($1,1,1,0) will
actually look at the byte value contained
at $1 and compare it with the value of 1
(returning 1 if true, and 0 if false).
Other m4 macros achieve macro
comparisons like regexp() and eval().

So, we can say that the closest thing
to a 'false' value in m4 is an empty
string, and the closest thing to 'true'
in m4 is a non-empty string.

CODE:
define(getboolVal,`pushdef(_boolVal,defn($))_boolVal($1)popdef(`_boolVal')')
define($,`ifelse'($`'1,`true',0,$`'1,`false',`'))
getboolVal(true)

On Mon, Aug 8, 2011 at 5:51 AM, Johnicholas Hines <
[email protected]> wrote:

> I'd be interested in an interactive shell also - but rather than a
> code generator, I was imagining implementing another language IN m4,
> just as you can write a lisp interpreter in C.
>
> Here's a snippet - I made it as small and simple as possible, possibly
> too small and simple, but extending it to have variables that are
> looked up in the environment, more control flow, should be
> straightforward.
>
> divert(-1)
> # a global counter used for making things unique
> define(`_gensym',`0')
> define(`gensym',`_gensym`'define(`_gensym',incr(_gensym))')
> # exp ::= Num( int )
> define(`_num',`define(`eat_Num'$1,`$'`1_num($2,shift($'`@))')Num$1')
> define(`num',`_num(gensym,$1)')
> # exp ::= Plus( exp , exp )
> define(`_plus',`define(`eat_Plus'$1,`$'`1_plus($2,$3,shift($'`@))')Plus$1')
> define(`plus',`_plus(gensym,$1,$2)')
> # define print_exp by cases
> #   print_exp(Num(int)) => int
> define(`_print_exp_num',`$1')
> #   print_exp(Plus(exp1,exp2)) => print_exp(exp1)+print_exp(exp2)
> define(`_print_exp_plus',`print_exp($1)+print_exp($2)')
> # actually dispatch
> define(`print_exp',`eat_$1(_print_exp)')
> # define my_eval by cases
> #   my_eval(Num(int)) => int
> define(`_my_eval_num',`$1')
> #   my_eval(Plus(exp1,exp2)) => eval(my_eval(exp1)+my_eval(exp2))
> define(`_my_eval_plus',`eval(my_eval($1)+my_eval($2))')
> # actually dispatch
> define(`my_eval',`eat_$1(_my_eval)')
> divert`'dnl
> # Now we can use the new "little language"
> print_exp(plus(plus(num(1),num(2)),num(3)))
> my_eval(plus(num(4),plus(num(5),num(6))))
>
> Is this sort of definition-by-cases a standard m4 idiom?
> What would the idiomatic way to create a new abstract datatype be?
>
> Johnicholas
>
>

Reply via email to