m4-discuss
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: interpreters/compilers in m4?


From: daniel daniel
Subject: Re: interpreters/compilers in m4?
Date: Wed, 10 Aug 2011 14:38:57 -0700

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 <address@hidden> 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

[Prev in Thread] Current Thread [Next in Thread]