Next: , Previous: , Up: Top   [Contents][Index]

7 Emulation examples

7.1 Introduction

The emulation examples are examples of defining a macro language in m0. It shows the different possibilities and solutions possible with m0.


Next: , Up: Emulation examples   [Contents][Index]

7.2 M4 emulation example

7.2.1 Introduction

The m4 emulation is an example of defining a macro language in m0.

It is (at least now) not a goal to be 100% compatible with m4 or to be complete.

Since m0 will also detect macros with invalid characters of m4 macros, it will probably be very difficult to be 100% compatible for cases where certain characteristics of m4 are used.

Also functions for regular expressions in m0 seem not necessary as this functionality can also be accomplished with patterns.

7.2.2 Emulation

The following text of the emulation is generated from a source file for both text and code. From this source file different versions of m4 are generated. These versions are:

v7

The original version of m4, see The M4 Macro Processor, Brian W. Kernighan and Dennis M. Ritchie, Bell Laboratories, July 1, 1977.

posix

A version with only the macros defined by posix, see e.g. m4.

gnu

Version with the macros defined in GNU m4, see GNU M4 manual.

bsd

Version with the macros defined in m4 of BSD, see e.g. FreeBSD m4 manual page.

Macros or code for all versions is indicated with all.

7.2.3 Main design

The emulation of m4 is using three macro sets:

  1. The default macro set 0 is used to define all basic macros that are necessary to be able to define the m4 macros. It is also used to hold some m4 macros that are build using the basic macros. The emulation starts in this macro set and is switched to the m4exec macro set to start emulation of the m4 input.
  2. The m4 macros are defined and executed in the macro set m4exec.
  3. The m4builtin macro set is used as a collection of builtin m4 macros that can be called from the builtin macro.

A big number of the builtin m4 macros are directly linked to the functions in m0. Several patterns are used to implement the syntax of m4. Difficult is a new definition of builtin macros using the defn macro. The use of defn requires that its use is detected by a define and the define is a copy or a define depending on this.

Some builtin m4 macros are emulated using a collection of macros in the default macro set 0.

Quoting and comments are implemented as macros as there exists no built in functionality for this in m0.

Although it it not necessary to use three macro sets, it allows a relatively easy separation of the underlying macro code and the emulated macros. Another solution can be a proper naming of underlying macros such that these are unlikely accidentally called.

7.2.4 At the start

Applicable for: all

At the start the macros used to define the macros for m4 are defined. This is all straightforward linking of macro names to builtin functions.

0_define:0_pattern:;;pattern;nr01;0
0_define:0_append_pattern:;;append_p;nr01;0
0_define:0_undefine:;;undefine;nr01;0
0_define:0_clr_pattern:;;clr_pat;nr01;0
0_define:0_copy_pattern:;;copy_pat;nr01;0
0_define:0_set_var:;;set_var;nr01;0
0_define:0_get_var:;;get_var;nr01;0
0_define:0_ifmacro:;;ifmacro?;rr01;0
0_define:0_argoptions:;;get_var;rr01;0;; stack_a pop_to_1 -7
0_define:0_chars_pattern:;;charpat;nr01;0
0_define:0_chars_args:;;chararg;nr01;0
0_define:0_specialchar:;;specialc;nr01;0
0_define:0_def_mcall:;;defmcall;nr01;0
0_define:0_atlast:;;at_last;nr01;0
0_define:0_mset:;;macroset;nr01;0
0_define:0_info:;;info;nr01;0
0_define:0_infofield:;$9;info;nr01;0
0_define:0_setinfo:;;set_info;nr01;0
0_define:0_copy:;;copy;nr01;0

Setting the defaults. This is also the default of m0.

0_chars_pattern:[]-\@+*?~

7.2.5 Large argument numbers

Applicable for: gnu bsd

Numbers can be larger than 0 – 9 (up to 9999) to select the arguments.

The second line defines the special characters for the arguments. This is missing the fifth character. It is thus not possible to select arguments from other stacks than the first stack.

0_chars_args:4$*@#;101;102;103;m4exec
0_chars_args:4$*@#;101;102;103;m4builtin

7.2.6 Argument with single number

Applicable for: v7 posix

Numbers can only be 0 – 9 to select the arguments.

0_chars_args:1$*@#;101;102;103;m4exec
0_chars_args:1$*@#;101;102;103;m4builtin

0_chars_args:1$*@#$;111;112;103

7.2.7 Quoting in default macro set

Applicable for: all

In the next part a macro with a pattern is used to have quoting in the macros in the default macro set 0 operational. The quoting is thus not a builtin function in m0.

0_set_var:111;+-+
0_set_var:112;-+-
0_pattern:0string;[@00-@ff]~;stack_b 1 stack_a begin-1
0_pattern:0string;+-+;stack_b 1 +
0_pattern:0string;-+-;stack_b 1 - dup =0 if stack_a end stop endif
0_define:+-+;$1;;nn00 ;0string

7.2.8 Collecting arguments of macros

Applicable for: all

The collecting of arguments in m4 macros is executed with a pattern named m4 containing small programs.

0_specialchar:(;[@00-@27@29-@ff]
0_pattern:m4;[\(]~;stack_b argpos =0 ifthen abort 
0_pattern:m4;[@00-@ff]~;stack_c 0
0_pattern:m4;(;stack_c 1 +
0_pattern:m4;);stack_c 1 - dup =0 if stack_a end stop endif
0_pattern:m4;[(,][@00- ]*[!-@ff];stack_a begin-1 ;1
0_pattern:m4;,;stack_c dup <=1 if stack_a end endif

7.2.9 define

Applicable for: all

First some special characters are defined to make the definition of macros easier.

The define of m4 can not be directly linked to the function define. In m4 a builtin macro can be named by using defn. These builtin macros should be handled differently from a user macro. Some code is necessary to handle the two cases.

Without the builtin definition, the define could be directly linked as:

0_define:\Bdefine(;;define;nr11 ;m4;;+-+stack_d "" putarg3
"rr11" putarg4 "m4" putarg5 "" putarg6 "" putarg7 "m4exec"
putarg8 "\B" getarg1 cat "\ " cat putarg1-+-;m4exec

In this example a program, executed in the macro, sets default values for the define function.

In this emulation the defn returns the name of the builtin macro and the word "builtin" to be used by this code to copy a builtin to a new name.

A macro to check for this and select the correct option is defined to handle this. The macro is actually a large program that:

The program uses the function calls, the macro is further empty because of this.

The builtin macro set is used to hold the information of the new builtin macro. This has as a side effect that this new macro can also be called using the m4 builtin, which is not possible in m4.

0_specialchar: ;[@00-@2f@3a-@40@5b-@5e@60@7b-@ff]
0_specialchar:B;[@00-@40@5b-@5e@60@7b-@ff]
0_def_mcall:\Bdefine(;4_define;0;nr11 ;m4;;m4exec
0_def_mcall:define;4_define;0;nn00;m4;;m4builtin
0_setinfo:define;(;m4builtin
0_define:4_define;;;nn00;0;;+-+ stack_e getarg1 stack_f getarg2 
stack_d getarg3 "builtin" strcmp
if
stack_g getarg4
stack_a pop_to_3 swap "m4builtin" "m4builtin" "copy" fun_call
pop_to_1 "\B" copyfr_f cat copyfr_g cat  "\B" copyfr_e cat
copyfr_g  cat "m4exec" "m4exec" "copy" fun_call 
else
stack_a pop_to_1 "\B" copyfr_e cat "\ " cat 
copyfr_f "" "rr11" "m4" "" "" "m4exec" "define" fun_call 
endif
-+-;0

7.2.10 pushdef

Applicable for: posix gnu bsd

Similar to the define. The only difference is the use of push instead of define.

0_def_mcall:\Bpushdef(;4_push;0;nr11 ;m4;;m4exec
0_def_mcall:pushdef;4_push;0;nn00;m4;;m4builtin
0_setinfo:pushdef;(;m4builtin
0_define:4_push;;;nn00;0;;+-+ stack_e getarg1 stack_f getarg2 
stack_d getarg3 "builtin" strcmp
if
stack_g getarg4
stack_a pop_to_3 swap "m4builtin" "m4builtin" "pushcopy" fun_call
pop_to_1 "\B" copyfr_f cat copyfr_g cat  "\B" copyfr_e cat
copyfr_g  cat "m4exec" "m4exec" "pushcopy" fun_call 
else
stack_a pop_to_1 "\B" copyfr_e cat "\ " cat 
copyfr_f "" "rr11" "m4" "" "" "m4exec" "push" fun_call 
endif
-+-;0

7.2.11 popdef

Applicable for: posix gnu bsd

0_define:\Bpopdef(;;pop;nr11 ;m4;;stack_d "m4exec" putarg2 "\B" getarg1 cat "\ " cat putarg1;m4exec
0_define:popdef;;pop;nn00;m4;;stack_d "m4exec" putarg2 "\B" getarg1 cat "\ " cat putarg1;m4builtin
0_setinfo:popdef;(;m4builtin

7.2.12 undefine

Applicable for: all

0_define:\Bundefine(;;undefine;nr11 ;m4;;stack_d "m4exec" putarg2 "\B" getarg1 cat "\ " cat putarg1;m4exec
0_define:undefine;;undefine;nn00;m4;;stack_d "m4exec" putarg2 "\B" getarg1 cat "\ " cat putarg1;m4builtin
0_setinfo:undefine;(;m4builtin

7.2.13 Quoting in m4

Applicable for: all

In the next part a macro with a pattern is used to have quoting operational in the m4 emulation.

0_set_var:101;`
0_set_var:102;'
0_set_var:103;,
0_set_var:100;$1
0_pattern:string;[@00-@ff]~;stack_b 1 stack_a begin-1 
0_pattern:string;0_get_var:101
;1 +
0_pattern:string;';stack_b 1 - dup =0 if stack_a end stop endif
0_define:0_get_var:101
;$1;;nn00 ;string;;;m4exec

7.2.14 changequote

Applicable for: all

The changequote calls the macro 0_changequote in macro set 0.

This enables the use of macros in the default macro set to perform the change of quotes.

0_def_mcall:\Bchangequote\ ;0_changequote;0;nn11 ;m4;;m4exec
0_def_mcall:changequote;0_changequote;0;nn00;m4;;m4builtin
0_setinfo:changequote;\ ;m4builtin
0_define:0_changequote;+-+0_undefine:0_get_var:101
;m4exec
0_set_var:101;$1
0_set_var:102;$2
0_clr_pattern:string
0_pattern:string;[@00-@ff]~;stack_b 1 stack_a begin-1
0_pattern:string;$1;stack_b 1 +
0_pattern:string;$2;stack_b 1 - dup =0 if stack_a end stop endif
0_define:0_get_var:101
;0_get_var:100
;;nn00 ;string;;;m4exec
-+-;;rn00;0;;+-+stack_d argnum <=1 if "`" putarg1 "'" putarg2 endif-+-

7.2.15 Comments

Applicable for: posix gnu bsd

Also a comment is built as a macro.

0_pattern:comment;[@00-@ff]~;begin-1
0_pattern:comment;+-+
-+-;end stop
0_define:#;+-+#$1
-+-;;nn00 ;comment;;;m4exec

7.2.16 changecom

Applicable for: posix gnu bsd

to do


7.2.17 builtin

Applicable for: gnu bsd

Defines a macro call to a macro stored in the first argument. The macro set m4builtin is used for calling the builtin macros of m4.

The macros defined in the macro set m4builtin are only called from this macro. Therefore these macros should not recurse their output, because this is done by the builtin macro. Since they are never called normally, the settings for argument collection are irrelevant.

For macros that have a different argument collection than the m4 of builtin this represents a difficulty.

The builtin macro itself is also defined in the macro set m4builtin.

0_def_mcall:\Bbuiltin(;;m4builtin;rr11 ;m4;;m4exec
0_def_mcall:builtin;;m4builtin;nn00;m4;;m4builtin
0_setinfo:builtin;(;m4builtin

7.2.18 include

Applicable for: all

0_define:\Binclude(;;include;rr11 ;m4;;;m4exec
0_define:include;;include;nn00;m4;;;m4builtin
0_setinfo:include;(;m4builtin

7.2.19 sinclude

Applicable for: all

0_define:\Bsinclude(;;sinclude;rr11 ;m4;;;m4exec
0_define:sinclude;;sinclude;nn00;m4;;;m4builtin
0_setinfo:sinclude;(;m4builtin

7.2.20 place

Applicable for: bsd

The place is like an include, but the contents of the file is not recurrently scanned for macros.

To have the builtin not to recurrently scan the output the setting thereof is overruled with the recur_n.

0_define:\Bplace(;;include;nr11 ;m4;;;m4exec
0_define:place;;include;nn00;m4;;recur_n;m4builtin
0_setinfo:place;(;m4builtin

7.2.21 splace

Applicable for: bsd

Similar to place just silent for file errors.

0_define:\Bsplace(;;sinclude;nr11 ;m4;;;m4exec
0_define:splace;;sinclude;nn00;m4;;recur_n;m4builtin
0_setinfo:splace;(;m4builtin

7.2.22 divert

Applicable for: all

0_define:\Bdivert\ ;;divert;nr11 ;m4;;;m4exec
0_define:divert;;divert;nn00;m4;;;m4builtin
0_setinfo:divert;\ ;m4builtin

7.2.23 undivert

Applicable for: all

0_define:\Bundivert\ ;;undivert;nr11 ;m4;;;m4exec
0_define:undivert;;undivert;nn00;m4;;;m4builtin
0_setinfo:undivert;\ ;m4builtin

7.2.24 divnum

Applicable for: all

0_define:\Bdivnum\ ;;get_var;nn11 ;m4;;stack_a pop_to_1 -1;m4exec
0_define:divnum;;get_var;nn00;m4;;stack_a pop_to_1 -1;m4builtin
0_setinfo:divnum;\ ;m4builtin

7.2.25 __line__

Applicable for: gnu bsd

0_define:\B__line__\ ;;get_var;nn11 ;m4;;stack_a pop_to_1 -4;m4exec
0_define:__line__;;get_var;nn00;m4;;stack_a pop_to_1 -4;m4builtin
0_setinfo:__line__;\ ;m4builtin

7.2.26 __file__

Applicable for: gnu bsd

0_define:\B__file__\ ;;get_var;nn11 ;m4;;stack_a pop_to_1 -5;m4exec
0_define:__file__;;get_var;nn00;m4;;stack_a pop_to_1 -5;m4builtin
0_setinfo:__file__;\ ;m4builtin

7.2.27 __program__

Applicable for: gnu

0_define:\B__program__\ ;;get_var;nn11 ;m4;;stack_a pop_to_1 -6;m4exec
0_define:__program__;;get_var;nn00;m4;;stack_a pop_to_1 -6;m4builtin
0_setinfo:__program__;\ ;m4builtin

7.2.28 __unix__

Applicable for: gnu

0_define:\B__0_get_var:-2
__\ ;;;nn11;m4;;;m4exec
0_define:__0_get_var:-2
__;;;nn00;m4;;;m4builtin
0_setinfo:__0_get_var:-2
__;\ ;m4builtin

7.2.29 unix

Applicable for: v7 bsd

0_define:\B0_get_var:-2
\ ;0_get_var:-2
;;nn11;m4;;;m4exec
0_define:0_get_var:-2
;0_get_var:-2
;;nn00;m4;;;m4builtin
0_setinfo:0_get_var:-2
;\ ;m4builtin

7.2.30 errprint

Applicable for: all

0_define:\Berrprint(;;errprint;nr11 ;m4;;;m4exec
0_define:errprint;;errprint;nn00;m4;;;m4builtin
0_setinfo:errprint;(;m4builtin

7.2.31 m4exit

Applicable for: posix gnu bsd

0_define:\Bm4exit(;;exit;nr11;m4;;;m4exec
0_define:m4exit;;exit;nn00;m4;;;m4builtin
0_setinfo:m4exit;(;m4builtin

7.2.32 index

Applicable for: all

0_define:\Bindex(;;strindex;rr11 ;m4;;;m4exec
0_define:index;;strindex;nn00;m4;;;m4builtin
0_setinfo:index;(;m4builtin

7.2.33 substr

Applicable for: all

0_define:\Bsubstr(;;substr;rr11 ;m4;;;m4exec
0_define:substr;;substr;nn00;m4;;;m4builtin
0_setinfo:substr;(;m4builtin

7.2.34 translit

Applicable for: all

0_define:\Btranslit(;;strtrans;rr11 ;m4;;;m4exec
0_define:translit;;strtrans;nn00;m4;;;m4builtin
0_setinfo:translit;(;m4builtin

7.2.35 m4wrap

Applicable for: posix gnu bsd

0_define:\Bm4wrap(;;at_last;nr11 ;m4;;;m4exec
0_define:m4wrap;;at_last;nn00;m4;;;m4builtin
0_setinfo:m4wrap;(;m4builtin

7.2.36 esyscmd

Applicable for: gnu bsd

The output is of the shell function is recursive. This is different from the m4 macro syscmd. See the rr11 settings string.

0_define:\Besyscmd(;;shell;rr11 ;m4;;;m4exec
0_define:esyscmd;;shell;nn00;m4;;;m4builtin
0_setinfo:esyscmd;(;m4builtin

7.2.37 syscmd

Applicable for: all

The output of syscmd is not recursive. See the n in the nr11 settings string.

0_define:\Bsyscmd(;;shell;nr11 ;m4;;;m4exec
0_define:syscmd;;shell;nn00;m4;;recur_n;m4builtin
0_setinfo:syscmd;(;m4builtin

7.2.38 sysval

Applicable for: all

0_define:\Bsysval\ ;;get_var;nn11 ;m4;;stack_a pop_to_1 -8;m4exec
0_define:sysval;;get_var;nn00;m4;;stack_a pop_to_1 -8 recur_n;m4builtin
0_setinfo:sysval;\ ;m4builtin

7.2.39 maketemp

Applicable for: posix gnu bsd

Making the "safe" temporary file instead of the "unsafe" file in the original m4.

0_define:\Bmaketemp(;;tempfile;rr11 ;m4;;;m4exec
0_define:maketemp;;tempfile;nn00;m4;;;m4builtin
0_setinfo:maketemp;(;m4builtin

7.2.40 mkstemp

Applicable for: posix gnu bsd

Same as maketemp, but the output is not recursive.

0_define:\Bmkstemp(;;tempfile;nr11 ;m4;;;m4exec
0_define:mkstemp;;tempfile;nn00;m4;;recur_n;m4builtin
0_setinfo:mkstemp;(;m4builtin

7.2.41 defn

Applicable for: posix gnu bsd

defn should return the definition of a macro or in case of a builtin something so that in a define a new macro can be defined for the builtin.

These two possibilities require a different handling and thus a special macro in the 0 macro set is called.

The information text of the macros in the m4builtin macro set is used to determine if a macro has optional arguments or not.

A builtin is returned quoted as name, builtin, info field of name,. If the macro defn is not called from within another macro, then the builtin is not output. This simulates (partly) the behaviour in m4.

0_def_mcall:\Bdefn(;4_defn;0;rr11 ;m4;;m4exec
0_def_mcall:defn;4_defn;0;nn00;m4;;m4builtin
0_setinfo:defn;(;m4builtin
0_define:4_defn;+-+0_ifmacro:+-+$1-+-;+-+4_level:+-+0_get_var:101
$1+-+-+-0_get_var:102
,0_get_var:101
builtin0_get_var:102
,0_get_var:101
4_inf_builtin:$1
0_get_var:102
,-+-
-+-;+-+4_inf_def:$1
-+-;m4builtin
-+-;;rn00;0
0_define:4_inf_builtin:;+-+0_infofield:$1;m4builtin
-+-;;rn01;0
0_define:4_inf_def:;+-+0_info:\B$1\ ;m4exec
-+-;;rn01;0
0_define:4_level:;$1;;rr01;0;;stack_a m_depth <=3 ifthen pop;0

7.2.42 dnl

Applicable for: all

The delete to newline as the m4 macro and a special 0_dnl (macro starts with a space!) used at the beginning and end of the input.

0_define:\Bdnl\ ;;;+-+nn11
-+-;comment;;;m4exec
0_define:dnl;;;+-+nn00
-+-;comment;;;m4builtin
0_setinfo:dnl;\ ;m4builtin
0_define: 0_dnl;;;+-+nn00
-+-;comment;;;m4exec

7.2.43 incr

Applicable for: all

0_define:\Bincr(;$1;;rr11 ;m4;;stack_d getarg1 1 + putarg1;m4exec
0_define:incr;$1;;nn00;m4;;stack_d getarg1 1 + putarg1;m4builtin
0_setinfo:incr;(;m4builtin

7.2.44 decr

Applicable for: posix gnu bsd

0_define:\Bdecr(;$1;;rr11 ;m4;;stack_d getarg1 1 - putarg1;m4exec
0_define:decr;$1;;nn00;m4;;stack_d getarg1 1 - putarg1;m4builtin
0_setinfo:decr;(;m4builtin

7.2.45 shift

Applicable for: posix gnu bsd

0_define:\Bshift(;$@;;rr11 ;m4;;base_=_1;m4exec
0_define:shift;$@;;nn00;m4;;base_=_1;m4builtin
0_setinfo:shift;(;m4builtin

7.2.46 indir

Applicable for: gnu bsd

0_define:\Bindir(;$1($@);;rr11 ;m4;;base_=_1;m4exec
0_define:indir;$1($@);;nn00;m4;;base_=_1;m4builtin
0_setinfo:indir;(;m4builtin

7.2.47 ifdef

Applicable for: all

The ifdef calls the macro 0_ifdef in macro set 0.

This enables the use of macros in the default macro set.

0_def_mcall:\Bifdef(;0_ifdef;0;rr11 ;m4;;m4exec
0_def_mcall:ifdef;0_ifdef;0;nn00;m4;;m4builtin
0_setinfo:ifdef;(;m4builtin
0_define:0_ifdef;+-+0_ifmacro:\B$1\ ;$2;+-+0_ifmacro:\B$1(;$2;$3;m4exec
-+-;m4exec
-+-;;rr00;0

7.2.48 len

Applicable for: all

0_define:\Blen(;$1;;rr11 ;m4;;stack_a pop_to_2 argnum >0 if strlen else 0 endif;m4exec
0_define:len;$1;;nn00;m4;;stack_a pop_to_2 argnum >0 if strlen else 0 endif;m4builtin
0_setinfo:len;(;m4builtin

7.2.49 ifelse

Applicable for: all

The ifelse macro is implemented with a pattern using the special ifcmpset instruction in the programs.

The ifelse macro does not use the m4 pattern and therefore the macro is cloned in the 0 macro set for use with the builtin macro. Using the intermediary macro 0_ifelse to output the arguments to the clone macro 4_ifelse so that the m4if pattern can be used.

0_pattern:m4if;[\(]~;stack_b argpos =0 ifthen abort
0_pattern:m4if;[@00-@ff]~;stack_c 0 stack_a "" 0
0_pattern:m4if;(;stack_c 1 +
0_pattern:m4if;);stack_c 1 - dup =0 if stack_a end ifcmpset stop endif
0_pattern:m4if;[(,][@00- ]*[!-@ff];stack_a begin-1 ;1
0_pattern:m4if;,;stack_c dup <=1 if stack_a end stack_d argnum 3 mod =0 if stack_a ifcmpset endif endif
0_define:\Bifelse(;$1;;rr11 ;m4if;; stack_a argnum =1 ifthen pop argnum =2 ifthen pop pop;m4exec
0_def_mcall:ifelse;0_ifelse;0;nn00;m4;;m4builtin
0_setinfo:ifelse;(;m4builtin
0_define:0_ifelse;4_ifelse($@);;rn00;m4;;;0
0_define:4_ifelse(;$1;;nr01;m4if;; stack_a argnum =1 ifthen pop argnum =2 ifthen pop pop;0

7.2.50 eval

Applicable for: all

Like in the builtin ifelse also here an intermediary macro is used for the builtin macro.

The 4_eval macro can not be called with the arguments quoted, because the quotes used (+-+ and -+-) interfere with the evaluation by the m4eval pattern.

0_pattern:m4eval;[\(]~;stack_b argpos =0 ifthen abort 
0_pattern:m4eval;[@00-@ff]~;stack_c 0 stack_d 1
0_specialchar:S;[@00-@2a@2b@2c@2d@2e@2f@3a-@41@43-@51@53-@57@59-@61@63-@71@73-@77@79-@ff]
0_specialchar:*;[@00-@29@2b-@ff]
0_specialchar:>;[@00-@3c@3f-@ff]
0_specialchar:<;[@00-@3b@3e-@ff]
0_specialchar:=;[@00-@20@22-@3b@3f-@ff]
0_specialchar:&;[@00-@25@27-@ff]
0_specialchar:|;[@00-@7b@7d-@ff]
0_specialchar:D;[@00-@2f@3a-@ff]
0_specialchar:R;[@00-@2f@3b-@40@5b-@60@7b-@ff]
0_pattern:m4eval;\S[0-9];stack_b begin+1
0_append_pattern:m4eval;[0-9a-zA-Z:]*\R;stack_b end-1 stack_d pop_to_0 0
0_pattern:m4eval;+[0-9];stack_d =0 if stack_b 19 opexif>= + else stack_b 0 30 opexif>= + endif 
0_pattern:m4eval;-[0-9];stack_d =0 if stack_b 19 opexif>= - else stack_b 0 30 opexif>= - endif 
0_pattern:m4eval;+\D;stack_b 19 opexif>= + stack_d 1 
0_pattern:m4eval;-\D;stack_b 19 opexif>= - stack_d 1
0_pattern:m4eval;\**\*;stack_b 20 opexif>= * stack_d 1
0_pattern:m4eval;**;stack_b 21 opexif> power stack_d 1
0_pattern:m4eval;/;stack_b 20 opexif>= / stack_d 1
0_pattern:m4eval;%;stack_b 20 opexif>= mod stack_d 1
0_pattern:m4eval;~;stack_b 29 opexif>= ~ stack_d 1
0_pattern:m4eval;!\=;stack_b 29 opexif>= ! stack_d 1
0_pattern:m4eval;<<;stack_b 18 opexif>= shift_l stack_d 1
0_pattern:m4eval;>>;stack_b 18 opexif>= shift_r stack_d 1
0_pattern:m4eval;\>>\>;stack_b 17 opexif>= > stack_d 1
0_pattern:m4eval;\<<\<;stack_b 17 opexif>= < stack_d 1
0_pattern:m4eval;>=;stack_b 17 opexif>= >= stack_d 1
0_pattern:m4eval;<=;stack_b 17 opexif>= <= stack_d 1
0_pattern:m4eval;==;stack_b 16 opexif>= = stack_d 1
0_pattern:m4eval;!=;stack_b 16 opexif>= != stack_d 1
0_pattern:m4eval;testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest;stack_d 
0_pattern:m4eval;\==\=;stack_b 16 opexif>= = stack_d 1
0_pattern:m4eval;\&&\&;stack_b 15 opexif>= bit_and stack_d 1
0_pattern:m4eval;^;stack_b 14 opexif>= bit_exor stack_d 1
0_pattern:m4eval;\||\|;stack_b 13 opexif>= bit_or stack_d 1
0_pattern:m4eval;&&;stack_b 12 opexif>= and stack_d 1
0_pattern:m4eval;||;stack_b 11 opexif>= or stack_d 1
0_pattern:m4eval;(;stack_c 1 + dup >=2 if stack_b 0 oppush nop endif
0_pattern:m4eval;);stack_c 1 - dup >=1 if stack_b opexto nop endif stack_c dup =0 if stack_a end argnum =1 if stack_b opexall putarg1 endif stop endif
0_pattern:m4eval;[(,][@00- ]*[!-@ff];stack_a begin-1 ;1
0_pattern:m4eval;,;stack_c dup <=1 if stack_a end argnum =1 if stack_b opexall putarg1 endif endif
0_define:\Beval(;;num2str;rr11 ;m4eval;;;m4exec
0_def_mcall:eval;0_eval;0;nn00;m4;;m4builtin
0_setinfo:eval;(;m4builtin
0_define:0_eval;4_eval($*);;rn00;m4;;;0
0_define:4_eval(;;num2str;nn01;m4eval;;;0

7.2.51 expr

Applicable for: bsd

Same as the eval macro of m4.

0_define:\Bexpr(;;num2str;rr11 ;m4eval;;;m4exec
0_def_mcall:expr;0_eval;0;nn00;m4;;m4builtin
0_setinfo:expr;(;m4builtin

7.2.52 format

Applicable for: gnu bsd

Like in the builtin ifelse also here an intermediary macro is used for the builtin macro.

0_pattern:m4format;[@00-@ff]~;stack_d 2
0_pattern:m4format;%[0-9];stack_e begin+0
0_append_pattern:m4format;[0-9]*\D;stack_e get_st+1
0_pattern:m4format;%[0-9]+s;stack_d copyto_e stack_e getarg copyto_d strlen - " " str* putoutst stack_d putout-0 1 +
0_pattern:m4format;%s;stack_d dup getarg putout 1 +
0_pattern:m4format;%[1-9][0-9]*d;stack_d copyto_e stack_e getarg 0 + copyto_d strlen - " " str* putoutst stack_d putout-0 1 +
0_pattern:m4format;%[0][0-9]+d;stack_e get_st+2 stack_d copyto_e stack_e getarg 0 + copyto_d strlen - "0" str* putoutst stack_d putout-0 1 +
0_pattern:m4format;%d;stack_d dup getarg 0 + putout 1 +
0_define:\Bformat(;;;rr11 ;m4;m4format;;m4exec
0_def_mcall:format;0_format;0;nn00;m4;;m4builtin
0_setinfo:format;(;m4builtin
0_define:0_format;4_format($@);;rn00;m4;;;0
0_define:4_format(;;;nr01;m4;m4format;;0

7.2.53 dumpdef

Applicable for: posix gnu bsd

to do


7.2.54 regexp

Applicable for: gnu bsd

to do


7.2.55 patsubst

Applicable for: gnu bsd

to do


7.2.56 traceon

Applicable for: posix gnu bsd

to do


7.2.57 traceoff

Applicable for: posix gnu bsd

to do


7.2.58 end of emulation file, start of m4 files

Applicable for: all

Finally switch to the m4exec macro set.

Extra input is inserted to be sure that all macros are recognised at the start and the end of the input file. These macros do not generate output.

0_atlast:+-+ 0_dnl
-+-
0_mset:m4exec
 0_dnl


Next: , Previous: , Up: Emulation examples   [Contents][Index]

7.3 M6 emulation example

7.3.1 Introduction

The m6 emulation is an example of defining a macro language in m0.

The m6 macro processor is a predecessor of m4. It does not seem to be used anymore, but as an example it seems to be still useful.

Since there is no working m6 for current systems, the testing of this emulation is limited.

7.3.2 Emulation

The following text of the emulation is generated from a source file for both text and code.

The original m6 was written in Fortran and a later version can be found in Unix v6 written in a pre K&R C (see https://minnie.tuhs.org/cgi-bin/utree.pl?file=V6/usr/source/m6).

However in this emulation only one version that is based on The M6 Macro Processor, Andrew D. Hall, Bell Laboratories, April 12, 1972 is made and indicated with all.

7.3.3 Main design

A similar approach as is used in the m4 emulation could be used for the m6 emulation. However, because the macros in m6 look a lot like S-expressions as known from Lisp, a different solution is chosen.

In the macro set for execution of m6 macros a main macro is defined that will trigger on all macros and will call the macro placed in the first argument. This gives some difficulties, because 3 macros (GO, GOBK and DNL) have a different behaviour for the collection of arguments. Thus the emulation design of m4 might be a better choice, but for demonstration the current design is also fine.

The main macro is defined in the m6exec macro set. The builtin and user macros are defined in the m6def macro set.

7.3.4 At the start

Applicable for: all

At the start the macros used to define the macros for m6 are defined. This is all straightforward linking of macro names to builtin functions.

0_define:0_pattern:;;pattern;nr01;0
0_define:0_set_var:;;set_var;nr01;0
0_define:0_get_var:;;get_var;nr01;0
0_define:0_chars_pattern:;;charpat;nr01;0
0_define:0_chars_args:;;chararg;nr01;0
0_define:0_specialchar:;;specialc;nr01;0
0_define:0_def_mcall:;;defmcall;nr01;0
0_define:0_atlast:;;at_last;nr01;0
0_define:0_mset:;;macroset;nr01;0

Setting the defaults. The first is also the default of m0. The second line defines the special characters for the arguments. This is missing the fifth character. It is thus not possible to select arguments from other stacks than the first stack.

0_chars_pattern:[]-\@+*?~
0_chars_args:1$*@#;101;102;103;m6exec
0_chars_args:1$*@#;101;102;103;m6def
0_chars_args:1$*@#$;111;112;103

7.3.5 Quoting in default macro set

Applicable for: all

In the next part a macro with a pattern is used to have quoting in the macros in the default macro set 0 operational. The quoting is thus not a builtin function in m0.

0_set_var:111;+-+
0_set_var:112;-+-
0_pattern:0string;[@00-@ff]~;stack_b 1 stack_a begin-1
0_pattern:0string;+-+;stack_b 1 +
0_pattern:0string;-+-;stack_b 1 - dup =0 if stack_a end stop endif
0_define:+-+;$1;;nn00 ;0string

7.3.6 Quoting

Applicable for: all

In the next part a macro with a pattern is used to have quoting in m6.

0_set_var:101;<
0_set_var:102;>
0_set_var:103;,
0_pattern:string;[@00-@ff]~;stack_b 1 stack_a begin-1
0_pattern:string;<;stack_b 1 +
0_pattern:string;>;stack_b 1 - dup =0 if stack_a end stop endif
0_define:<;$1;;nn00 ;string;;;m6exec

7.3.7 Collecting arguments of macros

Applicable for: all

The collecting of arguments in m6 macros is executed with a pattern named m6 containing small programs.

The macros GO or GOBK are special cases. Therefore the pattern will detect these and then all arguments after the second argument are eaten when the argument equals 1. If the argument does not equal 1, then the pattern stops, so that the text after these macros is output.

In this case also an undocumented implementation feature is used to let the collection of arguments continue until the end of the buffer. In the implementation of m0, the replacement text is put in a memory buffer that is used as input to the bitap algorithm. At the end of the buffer the collection of arguments (in this case only for these two macros) ends and the execution of the macro continues. This results in the effect as described in m6 for these two macros.

The DNL macro is also a special case and is also performed in this pattern. The argument collection is stopped when a "\n" is encountered.

In the normal case all arguments 9 and larger are also collected together into argument 9. This is so defined in m6.

0_pattern:m6;[@00-@ff]~;begin-1 stack_b 0 stack_c 0
0_pattern:m6;+-+GO[,:;]-+-;stack_b argnum <1 if 1 endif
0_pattern:m6;+-+GOBK[,:;]-+-;stack_b argnum <1 if 1 endif
0_pattern:m6;+-+DNL[,:;]-+-;stack_c argnum <1 if 1 endif
0_pattern:m6;,;argnum 9 < if  stack_a end begin endif 
0_pattern:m6;+-+;-+-; recur_n 
0_pattern:m6;+-+[:;]-+-;+-+stack_a end stack_b dup =0 if 
stack_c dup =0 ifthen stop  
else
dup =1 if
  getarg2 =1 if
    2
    no_macro
    else
    stop
    endif
  endif
endif -+-
0_pattern:m6;+-+
-+-;stack_c dup =1 if stack_a end stop endif

7.3.8 Main macro for executing all macros

Applicable for: all

The main macro will collect all arguments including the macro name and will make an mcall to the macro.

This is therefore a relatively simple macro.

0_def_mcall:#;;m6def;rr00 ;m6;;m6exec

7.3.9 GO, GOBK

Applicable for: all

These two macros are a bit different from normal macros. They will remove or keep the rest of a replacement text after the macro. They are similar to an if but their influence is outside of the macro.

Therefore the m6 pattern will do the check of the if of the argument for these macros. The called macros are nop except for setting the no recurrent in the GO macro.

0_define:GOBK;;;nn00;m6;;;m6def
0_define:GO;;;nn00;m6;;recur_n;m6def

7.3.10 DEF

Applicable for: all

The macros will be defined in the m6def macro set.

They will be called from the main macro. Therefore the argument collection has no significance.

0_define:DEF;;define;nn00;m6;;stack_a pop_to_3 "" "nn00" "" "" "" "m6def";m6def

7.3.11 COPY

Applicable for: all

0_define:COPY;;copy;nn00;m6;;stack_a pop_to_3 "m6def" "m6def";m6def

7.3.12 SEQ

Applicable for: all

0_define:SEQ;$1;;nn00;m6;;stack_a pop_to_3 strcmp;m6def

7.3.13 SNE

Applicable for: all

0_define:SNE;$1;;nn00;m6;;stack_a pop_to_3 strcmp !;m6def

7.3.14 GT

Applicable for: all

0_define:GT;$1;;nn00;m6;;stack_a pop_to_3 >;m6def

7.3.15 GE

Applicable for: all

0_define:GE;$1;;nn00;m6;;stack_a pop_to_3 >=;m6def

7.3.16 LT

Applicable for: all

0_define:LT;$1;;nn00;m6;;stack_a pop_to_3 <;m6def

7.3.17 LE

Applicable for: all

0_define:LE;$1;;nn00;m6;;stack_a pop_to_3 <=;m6def

7.3.18 EQ

Applicable for: all

0_define:EQ;$1;;nn00;m6;;stack_a pop_to_3 =;m6def

7.3.19 NE

Applicable for: all

0_define:NE;$1;;nn00;m6;;stack_a pop_to_3 !=;m6def

7.3.20 IF

Applicable for: all

The IF will call a macro in the 0 macro set to redo the arguments with the m6if pattern. This pattern will do the to do the comparisons and set the correct answer.

0_pattern:m6if;[@00-@ff]~;stack_a begin-1  
0_pattern:m6if;[,:];+-+stack_a end begin 
stack_b argnum 2 mod =0 if
argnum 1 - getarg =1 if 
argnum getarg 
endif endif-+-   
0_pattern:m6if;[:]; stop
0_def_mcall:IF;6_IF;0;nn00;m6;;m6def
0_define:6_IF;0_IF$@:;;rn00;m6;;;0
0_define:0_IF;$b0;;nr00;m6if;;;0

7.3.21 SIZE

Applicable for: all

0_define:SIZE;$1;;nn00;m6;;stack_a pop_to_2 strlen;m6def

7.3.22 SUBSTR

Applicable for: all

0_define:SUBSTR;;substr;nn00;m6;;;m6def

7.3.23 ADD

Applicable for: all

0_define:ADD;$1;;nn00;m6;;stack_a pop_to_3 +;m6def

7.3.24 SUB

Applicable for: all

0_define:SUB;$1;;nn00;m6;;stack_a pop_to_3 -;m6def

7.3.25 MPY

Applicable for: all

0_define:MPY;$1;;nn00;m6;;stack_a pop_to_3 *;m6def

7.3.26 DIV

Applicable for: all

0_define:DIV;$1;;nn00;m6;;+-+stack_b getarg2 =0 if
"" putarg1 else stack_a pop_to_3 / endif-+-;m6def

7.3.27 EXP

Applicable for: all

0_define:EXP;$1;;nn00;m6;;+-+stack_b getarg2 <0 if
"" putarg1 else stack_a pop_to_3 power endif-+-;m6def

7.3.28 DNL

Applicable for: all

The DNL does nothing. All the work is performed in the m6 pattern.

0_define:DNL;;;nn00;;;;m6def

7.3.29 Source, End, Trace

Applicable for: all

These macros are not implemented.

7.3.30 end of emulation file, start of m6 files

Applicable for: all

Finally switch to the m6exec macro set.

0_mset:m6exec


Previous: , Up: Emulation examples   [Contents][Index]

7.4 GPM emulation example

7.4.1 Introduction

The gpm emulation is an example of defining a macro language in m0.

The gpm macro processor is an early macro processor and is considered a very early predecessor of m4. It does not seem to be used anymore, but as an example it seems to be still useful.

Since there is no working gpm macro processor for current systems, the testing of this emulation is limited.

7.4.2 Emulation

The following text of the emulation is generated from a source file for both text and code.

In this emulation the version that is described in GPMX A portable general purpose macro processor adapted for preprocessing FORTRAN, Robert C. Gammill, The Rand Corporation, Santa Monica, California, 7 June 1976 is made and indicated with all.

7.4.3 Main design

A similar approach as is used in the m6 emulation is used for the gpm emulation.

In the macro set for execution of gpm macros a main macro is defined that will trigger on all macros and will call the macro placed in the first argument. The use of a macro call is necessary because it seems a practise that called macros are first defined during argument collection. Thus the called macro is not yet defined when called.

The main macro is defined in the gpmexec macro set. The builtin and user macros are defined in the gpmdef macro set.

GPM has only 6 macros builtin. It is thus small and the characteristics of gpm are used to add complexity.

7.4.4 At the start

Applicable for: all

At the start the macros used to define the macros for gpm are defined. This is all straightforward linking of macro names to builtin functions.

0_define:0_pattern:;;pattern;nr01;0
0_define:0_set_var:;;set_var;nr01;0
0_define:0_get_var:;;get_var;nr01;0
0_define:0_chars_pattern:;;charpat;nr01;0
0_define:0_chars_args:;;chararg;nr01;0
0_define:0_specialchar:;;specialc;nr01;0
0_define:0_def_mcall:;;defmcall;nr01;0
0_define:0_atlast:;;at_last;nr01;0
0_define:0_mset:;;macroset;nr01;0
0_define:0_char:;;num2chr;nr01;0
0_define:0_program:;;program;nr01;0

Setting the defaults. These are different from the defaults of m0. The second line defines the special characters for the arguments. This is missing the fifth character. It is thus not possible to select arguments from other stacks than the first stack.

0_chars_pattern:{}-\@+*?~
0_chars_args:1%*@#;101;102;103;gpmexec
0_chars_args:1%*@#;101;102;103;gpmdef
0_chars_args:1$*@#$;111;112;103

7.4.5 Quoting in default macro set

Applicable for: all

In the next part a macro with a pattern is used to have quoting in the macros in the default macro set 0 operational. The quoting is thus not a builtin function in m0.

0_set_var:111;+-+
0_set_var:112;-+-
0_pattern:0string;{@00-@ff}~;stack_b 1 stack_a begin-1
0_pattern:0string;+-+;stack_b 1 +
0_pattern:0string;-+-;stack_b 1 - dup =0 if stack_a end stop endif
0_define:+-+;$1;;nn00 ;0string

7.4.6 Quoting

Applicable for: all

In the next part a macro with a pattern is used to have quoting in gpm in a similar way as m6.

0_set_var:101;<
0_set_var:102;>
0_set_var:103;:
0_pattern:string;{@00-@ff}~;stack_b 1 stack_a begin-1
0_pattern:string;<;stack_b 1 +
0_pattern:string;>;stack_b 1 - dup =0 if stack_a end stop endif
0_define:<;%1;;nn00 ;string;;;gpmexec

7.4.7 Collecting arguments of macros

Applicable for: all

The collecting of arguments in gpm macros is executed with a pattern named gpm containing small programs.

This pattern will also recognise the arithmetic for the BAR macro. It will push the operators to the operator stack. The BAR macro can execute these operators.

0_pattern:gpm;{@00-@ff}~;stack_a begin-1 
0_pattern:gpm;:;stack_a end begin  
0_pattern:gpm;];stack_a end stop
0_pattern:gpm;:+:;stack_a 0 oppush +
0_pattern:gpm;:-:;stack_a 0 oppush -
0_pattern:gpm;:*:;stack_a 0 oppush *
0_pattern:gpm;:/:;stack_a 0 oppush /

7.4.8 Substitution of arguments

Applicable for: all

The emulation is not using the default argument substitution, because the local defined macros should be deleted at the end of a macro. The argument substitution is executed at the end of a macro and is therefore the correct place to delete local macros.

Stack h holds the names of macros defined. This stack is not freed at the end of a DEF.

A char with value 0 is used in macros to execute the deletion of the macros whereby the name of the macros are stored on stack h.

A char with value 3 is used in the DEF macro to execute the deletion of macros and to store the defined macro on stack h.

A char with value 2 is used in the VAL macro to output the second argument and delete the last char (the char with value 0).

0_define:0_zero;0_char:0
;;nn00;;;;0
0_define:0_three;0_char:3
;;nn00;;;;0
0_define:0_two;0_char:2
;;nn00;;;;0
0_pattern:arggpm;%{0-9};stack_b getlast1 getarg putout 
0_pattern:arggpm;0_zero;+-+ stack_a pop_to_2 "gpmdef"
stack_h while_st putarg1 "pop" fun_call pop endwhile
"" putout -+-
0_pattern:arggpm;0_three;+-+ stack_a pop_to_2 copyto_c "gpmdef"
stack_h while_st putarg1 "pop" fun_call pop endwhile
copyfr_c free_no "" putout -+-
0_pattern:arggpm;0_two;stack_b getarg2 putout "" putout

7.4.9 Main macro for executing all macros

Applicable for: all

The main macro will collect all arguments including the macro name and will make an mcall to the macro.

This is therefore a relatively simple macro.

0_def_mcall:[;;gpmdef;rr00;gpm;;gpmexec

7.4.10 DEF

Applicable for: all

The macros will be defined in the gpmdef macro set.

They will be called from the main macro. Therefore the argument collection has no significance.

The DEF uses the push function so that it can also be popped at the end of macros.

0_program:defargs;+-+ 
stack_a pop_to_3 "" "nn00" "gpm" "arggpm" "" "gpmdef"
stack_c getarg2 -+-"0_zero"+-+ cat putarg2-+-
0_define:DEF;0_three;push;nn00;gpm;arggpm; @defargs ;gpmdef

7.4.11 UPDATE

Applicable for: all

Is similar to DEF, but uses a define instead of a push.

0_define:UPDATE;0_zero;define;nn00;gpm;arggpm; @defargs ;gpmdef

7.4.12 BIN

Applicable for: all

This macro has nothing to do. In m0 integers and strings are automatically converted.

0_define:BIN;%10_zero;;nn00;gpm;arggpm;;gpmdef

7.4.13 DEC

Applicable for: all

Similar to BIN.

0_define:DEC;%10_zero;;nn00;gpm;arggpm;;gpmdef

7.4.14 VAL

Applicable for: all

Links to info, but needs to also output char with 0 to the output.

0_define:VAL;0_two0_zero;info;nn00;gpm;arggpm;recur_n;gpmdef

7.4.15 BAR

Applicable for: all

The operators are already stored by the gpm pattern. So operator needs only to be executed here.

0_define:BAR;%20_zero;;nn00;gpm;arggpm;stack_a opexall;gpmdef

7.4.16 end of emulation file, start of gpm files

Applicable for: all

Finally switch to the gpmexec macro set.

0_mset:gpmexec


Previous: , Up: Emulation examples   [Contents][Index]