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

9 Emulation examples

9.1 Introduction

In the previous Macro processing to Internal functioning of m0 the working of m0 has been explained. In this section the application thereof is demonstrated by the implementation of several examples of macro processor emulation. It shows the different possible solutions and the possibilities of m0.

Normally macro processors use words or atoms and a parser to proces these words. In m0 a start character set and a stop character set is used to emulate the use of words or atoms. The bitap algorithm allows to use this efficiently.

9.1.1 Peculiarities of the macro processor emulations

The different examples have their own peculiarities and solutions for the emulation. The M4, M6 and GPM examples are all general purpose macro processors. The M4 macro processor is the most extensive of these three, and in contrast GPM is very small.

The most interesting peculiarities in the emulations are:

9.1.2 Using emulation files

The emulation files are like any other file that contains sets of macros. Therefore they are placed as the first input file. The files to be processed follow hereafter. An example to use the M4 emulation in the versions of GNU, v7, BSD or posix that are placed in the emu directory:

m0 emu/m4gnu.m0 text.m4
m0 emu/m4v7.m0 text.m4
m0 emu/m4bsd.m0 text.m4
m0 emu/m4posix.m0 text.m4

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

9.2 M4 emulation example

9.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 (GNU) 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. The macros related to regular expressions in (GNU) m4 are therefore not implemented.

9.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.

9.2.3 Main design

The emulation of m4 is using four 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.
  4. The Args macro set is used for the m4 command line options.

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.

9.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_atfirst:;;at_first;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
0_define:0_char:;;num2chr;nr01;0
0_define:0_program:;;program;nr01;0
0_define:0_divert:;;divert;nr01;0
0_define:0_undivert:;;undivert;nr01;0
0_define:0_divnum:;;get_var;nr01;0;; stack_a pop_to_1 -1
0_define:0_inter_pat:;;inter_p;nr01;0
0_define:0_tag_pat:;;tag_p;nr01;0
0_define:0_link_pat:;;link_prt;nr01;0

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

0_chars_pattern:[]-\@+*?~
0_define:0_l1;0_char:1
;;nn00;;;;0
0_define:0_r1;0_char:2
;;nn00;;;;0
0_define:0_alt;0_char:3
;;nn00;;;;0
0_define:0_slash;0_char:4
;;nn00;;;;0

9.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

9.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

9.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

And defining a beginning pattern to be copied.

0_pattern:0start;[@00-@ff]~;stack_b 1 stack_a begin-1

9.2.8 Special characters

Applicable for: all

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

The "\ " is used at the end of a macro to mean all characters except characters valid for a name. This ends the detection of a macro name. It is used for all macros which have optional arguments. Macros which must be followed by arguments end with a "(".

The "\B" is used at the start of a macro to mean all characters except characters valid for a name. This is used to not start a macro inside a word.

0_specialchar: ;[@00-@2f@3a-@40@5b-@5e@60@7b-@ff]
0_specialchar:B;[@00-@40@5b-@5e@60@7b-@ff]

9.2.9 Command line options

Applicable for: all

The collecting of command line options is executed in a separate macro-set Args.

0_define:==Options;;get_var;rn00;;; stack_a pop_to_1 -8;Args
0_define:==Alloptions;;get_var;rn00;;; stack_a pop_to_1 -7;Args
0_define:==Mset:;;macroset;nr01;0;;;Args
0_pattern:args;[@00-@ff]~;stack_a begin-1  
0_pattern:args;=;stack_a end begin 
0_pattern:args;++-+
--+-;stack_a end stop

Setting the option of -P / --prefix-builtins to prefix all builtins with m4_.

This is accomplished by deleting the macro m4_. This macro is set as default to delete the m4_ part of the macro names. Deleting this macro will leave the m4_ part.

0_define:-P;;undefine;nn00;;;stack_a "m4_" "0";Args
0_define:--prefix-builtins;;undefine;nn00;;;stack_a "m4_" "0";Args
0_define:m4_;;;nn00
0_divert:-1
0_mset:Args
==Alloptions
==Mset:0
0_divert:0

The other command line options are executed at the start of a new file.

0_def_mcall:-D;define;m4builtin;nn00;args;;Args
0_def_mcall:--define=;define;m4builtin;nn00;args;;Args
0_def_mcall:-U;undefine;m4builtin;nn00;args;;Args
0_def_mcall:--undefine=;undefine;m4builtin;nn00;args;;Args

Setting options at the start of a file by an mcall to the ==Options macro in Args.

During this time diverting the output so that no output of options remain.

0_atfirst:m4_define(4_prev_div, divnum)m4_divert(-1)++-+
4_Set_Options
--+-m4_divert(4_prev_div)m4_dnl++-+
--+-
0_def_mcall:4_Set_Options;==Options;Args;++-+nn00
--+-;;;m4exec

9.2.10 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;[(,][@00- ]*[!-@ff];stack_a begin-1 ;1
0_pattern:m4;);stack_c 1 - dup =0 if stack_a end stop endif
0_pattern:m4;,;stack_c dup <=1 if stack_a end endif

9.2.11 define

Applicable for: all

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 information of the builtin macro on stack h. When a builtin is returned by the defn stack h holds:

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

0_program:define;++-+ 
stack_e argnum =0 ifthen stop
getarg1 dup "" strcmp ifthen stop
stack_f getarg2
stack_h if
stack_a pop_to_2 copyfr_h swap "m4builtin" "m4builtin" "copy" fun_call
pop_to_1 "\B" copyfr_h cat stack_h pop stack_a copyfr_h cat  "\B" copyfr_e cat
copyfr_h  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 --+-

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

The m4builtin 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_define:\Bm4_define(;;;nr11 ;m4;; @define ;m4exec
0_define:define;;;nn00;m4;; @define ;m4builtin
0_setinfo:define;(;m4builtin

9.2.12 pushdef

Applicable for: posix gnu bsd

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

0_program:push;++-+ 
stack_e argnum =0 ifthen stop
getarg1 dup "" strcmp ifthen stop
stack_f getarg2
stack_h if
stack_a pop_to_2 copyfr_h swap "m4builtin" "m4builtin" "pushcopy" fun_call
pop_to_1 "\B" copyfr_h cat stack_h pop stack_a copyfr_h cat  "\B" copyfr_e cat
copyfr_h  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_define:\Bm4_pushdef(;;;nr11 ;m4;; @push ;m4exec
0_define:pushdef;;;nn00;m4;; @push ;m4builtin
0_setinfo:pushdef;(;m4builtin

9.2.13 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 specific argument collection is defined that is similar to the m4 argument collection, but puts the arguments to stack b and calls a program to handle a builtin or a normal macro.

A builtin is returned on stack h to be used by a define.

Stack h is not freed and holds:

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

0_program:m4defnif;++-+ stack_b end dup "m4builtin" m?_num dup if
copyto_h stack_h m?_info copyfr_b  m?_name 1 free_no else
stack_b pop "\B" swap cat "\" cat "m4exec" m?_num 
dup if
stack_a copyfr_b m?_def cat endif
endif --+-
0_pattern:m4defn;[\(]~;stack_b argpos =0 ifthen abort  
0_pattern:m4defn;[@00-@ff]~;stack_c 0 stack_a ""
0_pattern:m4defn;(;stack_c 1 +
0_pattern:m4defn;[(,][@00- ]*[!-@ff];stack_b begin-1 ;1
0_pattern:m4defn;);stack_c 1 - dup =0 if @m4defnif stop endif
0_pattern:m4defn;,;stack_c dup <=1 if @m4defnif endif
0_define:\Bm4_defn(;$1;;nr11 ;m4defn;;;m4exec
0_define:defn;$1;;nn00;m4defn;;;m4builtin
0_setinfo:defn;(;m4builtin

9.2.14 popdef

Applicable for: posix gnu bsd

First a program is defined that selects between the two possible macros. It also sets the macro set.

0_program:undef;++-+ stack_d "\B" getarg1 cat 
dup "\ " cat "m4exec" m?_num if
"\ " cat putarg1 else
"(" cat putarg1 endif
"m4exec" putarg2 --+-

The popdef is a link to the pop function with the correct input set by the program.

0_define:\Bm4_popdef(;;pop;nr11 ;m4;; @undef ;m4exec
0_define:popdef;;pop;nn00;m4;; @undef ;m4builtin
0_setinfo:popdef;(;m4builtin

9.2.15 undefine

Applicable for: all

Similar to popdef, but with an undefine function.

0_define:\Bm4_undefine(;;undefine;nr11 ;m4;; @undef ;m4exec
0_define:undefine;;undefine;nn00;m4;; @undef ;m4builtin
0_setinfo:undefine;(;m4builtin

9.2.16 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;`;stack_b 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

9.2.17 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:\Bm4_changequote\ ;0_changequote;0;nr11 ;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_copy_pattern:0start;string
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--+-

9.2.18 Comments

Applicable for: posix gnu bsd

Also a comment is built as a macro.

0_set_var:104;#
0_pattern:comment;[@00-@ff]~;begin-1
0_pattern:comment;++-+
--+-;end stop
0_define:#;++-+$0$1
--+-;;nn00 ;comment;;stack_a argnum =0 ifthen end-1;m4exec

9.2.19 changecom

Applicable for: posix gnu bsd

Similar to changequote but with the specific argument amounts of changecom.

It uses the __ifelse macro defined further down like an m4 ifelse in the 0 macro set.

0_def_mcall:\Bm4_changecom\ ;0_changecom;0;nr11 ;m4;;m4exec
0_def_mcall:changecom;0_changecom;0;nr00;m4;;m4builtin
0_setinfo:changecom;\ ;m4builtin
0_define:0_changecom;++-+__ifelse(0_get_var:104
,,,++-+0_undefine:0_get_var:104
;m4exec
--+-)0_set_var:104;++-+$1--+-
0_copy_pattern:0start;comment
0_pattern:comment;++-+$2--+-;end stop
__ifelse(++-+$1--+-,,,++-+0_define:++-+$1--+-;++-+$--+-0$++-+1--+-++-+$2--+-;;nn00 ;comment;;stack_a argnum =0 ifthen end-1;m4exec
--+-)--+-;;rn00;0;;++-+stack_d argnum <=1 if "
" putarg2 endif--+-

9.2.20 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:\Bm4_builtin(;;m4builtin;rr11 ;m4;;m4exec
0_def_mcall:builtin;;m4builtin;nn00;m4;;m4builtin
0_setinfo:builtin;(;m4builtin

9.2.21 include

Applicable for: all

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

9.2.22 sinclude

Applicable for: all

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

9.2.23 place

Applicable for: bsd

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

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

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

9.2.24 splace

Applicable for: bsd

Similar to place just silent for file errors.

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

9.2.25 divert

Applicable for: all

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

9.2.26 undivert

Applicable for: all

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

9.2.27 divnum

Applicable for: all

0_define:\Bm4_divnum\ ;;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

9.2.28 __line__

Applicable for: gnu bsd

0_define:\Bm4___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

9.2.29 __file__

Applicable for: gnu bsd

0_define:\Bm4___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

9.2.30 __program__

Applicable for: gnu

0_define:\Bm4___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

9.2.31 __unix__

Applicable for: gnu

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

9.2.32 unix

Applicable for: v7 bsd

0_define:\Bm4_0_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

9.2.33 errprint

Applicable for: all

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

9.2.34 m4exit

Applicable for: posix gnu bsd

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

9.2.35 index

Applicable for: all

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

9.2.36 substr

Applicable for: all

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

9.2.37 translit

Applicable for: all

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

9.2.38 m4wrap

Applicable for: posix gnu bsd

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

9.2.39 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:\Bm4_esyscmd(;;shell;rr11 ;m4;;;m4exec
0_define:esyscmd;;shell;nn00;m4;;;m4builtin
0_setinfo:esyscmd;(;m4builtin

9.2.40 syscmd

Applicable for: all

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

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

9.2.41 sysval

Applicable for: all

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

9.2.42 maketemp

Applicable for: posix gnu bsd

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

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

9.2.43 mkstemp

Applicable for: posix gnu bsd

Same as maketemp, but the output is not recursive.

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

9.2.44 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.

The dnl uses a similar pattern as comments to read a single argument up to a newline.

0_pattern:m4dnl;[@00-@ff]~;begin-1
0_pattern:m4dnl;++-+
--+-;end stop
0_define:\Bm4_dnl\ ;;;++-+nn11
--+-;m4dnl;;;m4exec
0_define:dnl;;;++-+nn00
--+-;m4dnl;;;m4builtin
0_setinfo:dnl;\ ;m4builtin
0_define: 0_dnl;;;++-+nn00
--+-;m4dnl;;;m4exec

9.2.45 incr

Applicable for: all

0_define:\Bm4_incr(;$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

9.2.46 decr

Applicable for: posix gnu bsd

0_define:\Bm4_decr(;$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

9.2.47 shift

Applicable for: posix gnu bsd

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

9.2.48 indir

Applicable for: gnu bsd

This will just put the macro called by indir in the output and recurse this macro.

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

9.2.49 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:\Bm4_ifdef(;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

9.2.50 len

Applicable for: all

0_define:\Bm4_len(;$1;;nr11 ;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

9.2.51 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:\Bm4_ifelse(;$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
0_define:__ifelse(;$1;;rr01;m4if;; stack_a argnum =1 ifthen pop argnum =2 ifthen pop pop;0

9.2.52 eval

Applicable for: all

The arguments are parsed and evaluated during the argument collection. Therefore a specific pattern for the argument collection is defined in the same way as for the ifelse macro.

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;this part is doing nothing, it is here to test the memory use of pattern; 
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:\Bm4_eval(;;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

9.2.53 expr

Applicable for: bsd

Same as the eval macro of m4.

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

9.2.54 format

Applicable for: gnu bsd

This macro uses a pattern for the argument substitution to implement the printf like output.

0_pattern:m4format;[@00-@ff]~;stack_d 2
0_pattern:m4format;%;stack_e begin+0
0_tag_pat:m4format;1
0_append_pattern:m4format;-;
0_tag_pat:m4format;2
0_append_pattern:m4format;[0-9];stack_f begin+0
0_append_pattern:m4format;[0-9]*\D;stack_f get_st-1 endbegin
0_tag_pat:m4format;3
0_inter_pat:m4format;[0-9]+s;stack_e copyfr_f copyfr_d getarg copyto_d strlen - " " str* putoutst stack_d putout-0 1 +  
0_tag_pat:m4format;4
0_inter_pat:m4format;[0-9]+s;stack_e copyfr_f copyfr_d getarg dup putoutst strlen - " " str* putout-0 stack_d 1 + 
0_tag_pat:m4format;5
0_inter_pat:m4format;s;stack_e copyfr_d getarg putoutst stack_d 1 +
0_tag_pat:m4format;6
0_inter_pat:m4format;[1-9][0-9]*d;stack_e copyfr_f copyfr_d getarg 0 + copyto_d strlen - " " str* putoutst stack_d putout-0 1 +
0_tag_pat:m4format;7
0_inter_pat:m4format;[0][0-9]+d;stack_e copyfr_f get_st+2 copyfr_d getarg 0 + copyto_d strlen - "0" str* putoutst stack_d putout-0 1 +
0_tag_pat:m4format;8
0_inter_pat:m4format;d;stack_e copyfr_d getarg 0 + putoutst stack_d 1 +
0_link_pat:1;2;3;5;6;7;8
0_link_pat:2;4
0_define:\Bm4_format(;;;rr11 ;m4;m4format;;m4exec
0_define:format;;;nn00;m4;m4format;;m4builtin

9.2.55 dumpdef

Applicable for: posix gnu bsd

to do

0_define:\Bm4_dumpdef(;;;nr11 ;m4;;;m4exec

9.2.56 regexp

Applicable for: gnu bsd

to do


9.2.57 patsubst

Applicable for: gnu bsd

to do


9.2.58 traceon

Applicable for: posix gnu bsd

to do

nop

0_define:\Bm4_traceon\ ;;;nr11 ;m4;;;m4exec
0_define:traceon;;;nn00;m4;;;m4builtin
0_setinfo:traceon;\ ;m4builtin

9.2.59 traceoff

Applicable for: posix gnu bsd

to do

nop

0_define:\Bm4_traceoff\ ;;;nr11 ;m4;;;m4exec
0_define:traceoff;;;nn00;m4;;;m4builtin
0_setinfo:traceoff;\ ;m4builtin

9.2.60 debugmode

Applicable for: gnu

not implemented


9.2.61 debugfile

Applicable for: gnu

not implemented


9.2.62 end of emulation file, start of m4 files

Applicable for: all

Finally switch to the m4exec macro set.

The special chars for defining a set of characters is changed from "[" and "]" to bytes with values 1 and 2. This avoids an issue when similar characters in m4 are used to set quotes or comments.

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_chars_pattern:0_l10_r1-\@+*?~
0_atlast:++-+ 0_dnl
--+-
0_mset:m4exec
 0_dnl


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

9.3 M6 emulation example

9.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.

9.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.

9.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.

9.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

9.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

9.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

9.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

9.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

9.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 recurive in the GO macro.

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

9.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

9.3.11 COPY

Applicable for: all

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

9.3.12 SEQ

Applicable for: all

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

9.3.13 SNE

Applicable for: all

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

9.3.14 GT

Applicable for: all

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

9.3.15 GE

Applicable for: all

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

9.3.16 LT

Applicable for: all

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

9.3.17 LE

Applicable for: all

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

9.3.18 EQ

Applicable for: all

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

9.3.19 NE

Applicable for: all

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

9.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

9.3.21 SIZE

Applicable for: all

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

9.3.22 SUBSTR

Applicable for: all

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

9.3.23 ADD

Applicable for: all

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

9.3.24 SUB

Applicable for: all

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

9.3.25 MPY

Applicable for: all

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

9.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

9.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

9.3.28 DNL

Applicable for: all

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

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

9.3.29 Source, End, Trace

Applicable for: all

These macros are not implemented.

9.3.30 end of emulation file, start of m6 files

Applicable for: all

Finally switch to the m6exec macro set.

0_mset:m6exec


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

9.4 GPM emulation example

9.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.

9.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.

9.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.

9.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

9.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

9.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

9.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 /

9.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

9.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

9.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.

A program to set all the options for the define or push function is defined to be used by the DEF and the UPDATE macro. The definition of a new macro is appended with a zero character to activate the deletion of macros at the end of a macro by the arggpm argument substitution.

0_program:defargs;+-+ 
stack_a pop_to_3 "" "nn00" "gpm" "arggpm" "" "gpmdef"
stack_c getarg2 -+-"0_zero"+-+ cat putarg2-+-

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

0_define:DEF;0_three;push;nn00;gpm;arggpm; @defargs ;gpmdef

9.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

9.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

9.4.13 DEC

Applicable for: all

Similar to BIN.

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

9.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

9.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

9.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]

9.5 CPP emulation example

9.5.1 Introduction

The C pre processor emulation is an example of defining a macro language in m0.

The C pre processor is called a macro processor, but it intentionally lacks a lot of the characteristics of a macro processor. It is especially geared towards supporting the programming in C (obviously!) instead of supporting general macro processing.

That CPP differs from a general macro processor can be seen in the emulation by the use of specific argument collection patterns per directive and the handling of the exceptions to support the C programming.

9.5.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 cpp are generated. These versions are:

kr

The original K&R version of cpp, see Unix Time-Sharing System, UNIX programmer’s manual, Seventh Edition, Volume 2, Bell Laboratories, 1983.

c90

The version defined in the standard C90 (ANSI C).

c99

The version defined in the standard C99.

Code for all versions is indicated with all.

9.5.3 Main design

The c preprocessor emulation is performed in 2 stages, to keep edge cases easy to handle:

  1. All trigraphs are replaced and backlash newline are deleted.
  2. The directives and macro expansion are performed.

9.5.4 First stage, at the start

Applicable for: all

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

0_define:0_pattern:;;pattern;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_set_var:;;set_var;nr01;0

Setting the defaults. The first is also the default of m0. The second line defines the special characters for the arguments.

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

9.5.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

9.5.6 Trigraphs

Applicable for: all

Trigraphs are replaced.

0_define:??(;[;;rn00;;;;cpp
0_define:??);];;rn00;;;;cpp
0_define:??<;{;;rn00;;;;cpp
0_define:??>;};;rn00;;;;cpp
0_define:??=;#;;rn00;;;;cpp
0_define:??/;\;;rn00;;;;cpp
0_define:??';^;;rn00;;;;cpp
0_define:??!;|;;rn00;;;;cpp
0_define:??-;~;;rn00;;;;cpp

9.5.7 Backslash newline

Applicable for: all

Backslash newlines are deleted.

Using a special character for the \.

0_specialchar:\;\
0_define:+-+[@00-@5b@5d-@ff]\\
-+-;;;nn10;;;;cpp

9.5.8 End of emulation file, start of c files

Applicable for: all

Finally switch to the cpp macro set.

0_define:0_mset:;;macroset;nr01;0
0_mset:cpp

9.5.9 Second stage, at the start

Applicable for: all

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

0_define:0_pattern:;;pattern;nr01;0
0_define:0_pat_copy:;;copy_pat;nr01;0
0_define:0_pat_append:;;append_p;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_macro_part:;;part_m;nr01;0
0_define:0_macro_tag:;;tag_m;nr01;0
0_define:0_link:;;link_prt;nr01;0
0_define:0_pat_part:;;inter_p;nr01;0
0_define:0_pat_tag:;;tag_p;nr01;0
0_define:0_program:;;program;nr01;0
0_define:0_shell:;;shell;nr01;0

Setting the defaults. The first is also the default of m0. The other lines define the special characters for the arguments.

0_chars_pattern:[]-\@+*?~
0_chars_args:2$*@#$;101;102;103;cpp
0_chars_args:2%*@!%;101;102;103;cppdef
0_chars_args:2%*@!%;101;102;103;incl
0_chars_args:2$*@#$;111;112;103

9.5.10 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

9.5.11 Quoting in source

Applicable for: all

In the next part a macro with a pattern is used to have quoting operational in the source. Quoting can be nested. The nesting depth is counted in the pattern on stack b.

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;;nn00a;string;;;cpp
0_define:`;%1;;nn00;string;;;cppdef
0_define:`;%1;;nn00;string;;;incl

9.5.12 Strings in the source

Applicable for: all

A string with double quotes should not be changed by macros. A double quote preceded by a backslash should not be treated as a string start or end. To allow for empty strings and being able to detect the second double quote in the pattern, the pattern starts with the first double quote (see the second 1 for post size in the options).

0_pattern:str;[@00-@ff]~;begin
0_pattern:str;[@00-@5b@5d-@ff]";end-1 stop
0_define:[@00-@5b@5d-@ff]";"$1";;nn11";str;;;cpp

9.5.13 Comments

Applicable for: all

Also a comment is built as a macro. Comments are deleted or replaced with a space.

The patterns for the comment actually collect the comment. This is not necessary, but can be useful if another type of replacement text is wanted.

0_pattern:comment1;[@00-@ff]~;begin-1
0_pattern:comment1;*/;end stop

In K&R a comment is deleted.

0_define:/*;;;rn00;comment1;;;cpp

In later versions the comment is replaced by a space.

0_define:/*; ;;rn00;comment1;;;cpp

The // comment is only from C99 onwards supported.

0_pattern:comment2;[@00-@ff]~;begin-1
0_pattern:comment2;+-+
-+-;end stop
0_define://; ;;rn00;comment2;;;cpp

9.5.14 Special characters

Applicable for: all

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

The "\ " is used at the end of a macro to mean all characters except characters valid for a name. This ends the detection of a macro name.

The "\B" is used at the start of a macro to mean all characters except characters valid for a name. This is used to not start a macro inside a word.

0_specialchar: ;[@00-@2f@3a-@40@5b-@5e@60@7b-@ff]
0_specialchar:B;[@00-@40@5b-@5e@60@7b-@ff]

9.5.15 Collecting arguments of macros

Applicable for: all

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

It is similar to the argument collection in m4, but it will also delete white space at the end of an argument. In addition if no arguments are found the macro expansion is cancelled.

Further to emulate the behaviour of argument expansion and the use of # the top level macro will not use argument recursion.

0_specialchar:(;[@21-@27@29-@ff]
0_pattern:cpp_args;[@00-@ff]~;stack_c 0 stack_h m_depth =1 ifthen no_macro
0_pattern:cpp_args;(;stack_c 1 +
0_pattern:cpp_args;[@00- ]*[\(]~;stack_c dup =0 ifthen cancel 
0_pattern:cpp_args;[(,][@00- ]*[!-@ff];stack_a begin-1 ;1
0_pattern:cpp_args;[!-@ff][@00- ,)];stack_a setend-1 ;1
0_pattern:cpp_args;);stack_c 1 - dup =0 if stack_a pushend stop endif
0_pattern:cpp_args;,;stack_c dup <=1 if stack_a pushend endif

9.5.16 Start of directives

Applicable for: all

Directives start with a # and in versions after K&R can contain spaces in the front or back.

In K&R need to detect the newline first directly followed by the # and then the name of the directive. For this there is no need to have a start of directives, the start is included in the definition name of the directive.

0_specialchar:s;[ @07-@09@0b]

In C90 and onward need to detect the newline first, possible spaces, the #. Possible spaces after the # are in the name of the directive.

0_macro_part:+-+
[\s]*#-+-;Ls;cpp

0_macro_tag:dir_1;cpp

9.5.17 Argument collection for define

Applicable for: all

First a pattern to collect the arguments of the define is defined.

Using stack a for the name and definition of the macro. Stack b is used to store the names of the arguments. Stack c is used as information for the state of collection. The collection state = 0 at start, = 1 when collecting name of macro, = 2 when collecting argument names and = 3 when collecting the definition. This collection state is used to select if a program of a pattern part should run, since some pattern parts can be triggered at wrong moments.

The pattern will also remove the spaces in front and at the back of arguments and definition.

0_specialchar:a;[_a-zA-Z]
0_specialchar:A;[_a-zA-Z0-9]
0_pattern:define;[@00-@20]*[_a-zA-Z]~;stack_a begin-1 stack_c 0 
0_pat_tag:define;def1
0_pat_append:define;[_a-zA-Z0-9]*[@00-@20]~;stack_c dup =0 if stack_a end-1 begin stack_c 1 endif
0_pat_tag:define;def2
0_pat_part:define;[_a-zA-Z0-9]*[(]~;stack_c dup =0 if stack_a end-1 stack_c 2 endif
0_pat_append:define;[@00- ]*[!-@ff]~;stack_c dup =2 if stack_b begin-1 endif;1
0_pat_tag:define;def3
0_pat_part:define;[_a-zA-Z0-9]*[@21-@27@29-@2f@3a-@40@5b-@5e@60@7b-@ff]~;stack_c dup =0 if stack_a end-1  "Wrong name for macro" errprint endif
0_link:def1;def2;def3
0_pattern:define;,[@00- ]*[!-@ff]; stack_c dup =2 if stack_b begin-1  endif;1
0_pattern:define;[!-@ff][@00- ,)];stack_c dup =2 if stack_b setend-1 ;1
0_pattern:define;);stack_c dup =2 if stack_b pushend stack_c 3 endif
0_pattern:define;,;stack_c dup =2 if stack_b pushend endif
0_pattern:define;)[@00- ]*[!-@ff];stack_c dup =3 if stack_a begin-1  endif;1
0_pattern:define;[!-@ff][@00- ];stack_a setend-1 ;1
0_pattern:define;+-+
-+-;stack_a pushend stop

9.5.18 The define in C90 and later

Applicable for: c90 c99

The directive define is linked to the start of directives.

The define will call 1_define in the cppdef macro set to handle the define.

0_def_mcall:[\s]*define\s;1_define;cppdef;rn11;define;;cpp;Ll
0_link:dir_1;dir_1

9.5.19 The define in K&R

Applicable for: kr

The define will call 1_define in the cppdef macro set to handle the define.

0_def_mcall:+-+
#define\s-+-;1_define;cppdef;rn11;define;;cpp

9.5.20 Define in separate macro set cppdef

Applicable for: all

The two types of macros (with and without arguments) have to be defined differently.

A separate macro set for the definition of the macros is used to shield the definition from other macros.

A main macro (1_define) is called from the define in the cpp macro set. In this macro all the handling is done in the cppdef macro set.

The arguments in the definition are replaced with the default argument replacements (e.g. $1). The 2_def_args defines macros to replace the arguments in the definition with the default arguments. The 2_undef_args undefines these macros.

Notice that the default characters for argument substitution in the cppdef macro set are changed (% instead of $ and ! instead of #) to make the the substitution in the different macro sets easier.

The C90 and C99 version prohibit recursive macros. This is handled by the 3_blue and 3_enable macros in the cpp macro set.

0_program:setbase; 1 - dup >0 ifthen set_base
0_define:1_define;+-+2_def_args(%b*)m4_ifelse(%b!,0,`2_define:\B%1\ ;3_blue($0)'%2`3_enable($0);;rn11;;;;cpp
',`2_define:\B%1\ ;3_blue($0)'%2`3_enable($0);;rr11;cpp_args;;stack_h %b! @setbase;cpp
')2_undef_args(%b*) 
-+-;;rn00;;;;cppdef

The 3_blue will push the macro name with a definition consisting of the macro name. The new macro is not recursive and will thus not expand.

0_define:3_blue(;;push;nn01;cpp_args;;stack_a pop_to_2 dup "\B" cat-1 "\ " cat swap "" "nn11a" "" "" "" "cpp";cpp
0_define:3_enable(;;pop;nn01;cpp_args;;stack_a pop_to_2 "\B" cat-1 "\ " cat "cpp";cpp

The K&R version does not prohibit recursive macros

0_define:1_define;+-+2_def_args(%b*)m4_ifelse(%b!,0,`2_define:\B%1\ ;'%2`;;rn11;;;;cpp
',`2_define:\B%1\ ;'%2`;;rr11;cpp_args;;;cpp
')2_undef_args(%b*) 
-+-;;rn00;;;;cppdef

The macros used in the 1_define are defined here.

0_define:2_define:;;define;nn01;0;;;cppdef
0_pattern:defargs;[\(]~;stack_b argpos =0 ifthen abort 
0_pattern:defargs;[@00-@ff]~; stack_c 1 stack_a "" "" "" "rn11" "" "" "" "cppdef"
0_pattern:defargs;[(,][@00- ]*[!-@ff];stack_b begin-1 ;1
0_pattern:defargs;[,)];+-+ stack_b end
dup strlen >0 if
  "\B" cat-1 "\ " cat putarg1 
  stack_c dup "$" cat-1 putarg2 pop 1 +
  "define" fun_call 
endif -+-
0_pattern:defargs;); stop 
0_define:2_def_args(;;;nn01;defargs;;;cppdef
0_pattern:undefargs;[\(]~;stack_b argpos =0 ifthen abort 
0_pattern:undefargs;[@00-@ff]~; stack_a "" "cppdef"
0_pattern:undefargs;[(,][@00- ]*[!-@ff];stack_b begin-1 ;1
0_pattern:undefargs;[,)];+-+ stack_b end
dup strlen >0 if
  "\B" cat-1 "\ " cat putarg1 
  "undefine" fun_call 
endif -+-
0_pattern:undefargs;); stop 
0_define:2_undef_args(;;;nn01;undefargs;;;cppdef

9.5.21 ifelse use in define macro set

Applicable for: all

This is an ifelse like the m4 ifelse including the argument syntax. The pattern will do the comparisons and set the correct answer.

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:m4_ifelse(;%1;;rr01;m4if;; stack_a argnum =1 ifthen pop argnum =2 ifthen pop pop;cppdef

9.5.22 Strings in definition

Applicable for: c90 c99

An argument in a string should not be replaced. In K&R it should be replaced.

0_define:[@00-@5b@5d-@ff]";"%1";;nn11";str;;;cppdef

9.5.23 Making a string of an argument

Applicable for: c90 c99

The # is used to put quotes around an argument.

0_specialchar:#;[@00-@22@24-@ff]
0_pattern:stringy;[\A]~;stack_a begin-1 ;1
0_pattern:stringy;\A\ ;stack_a end-1 goback1 stop
0_pattern:stringy;+-+
-+-;stack_a end stop "no argument after #" errprint;1
0_define:\##\#;`"'%1`"';;rn11;stringy;;;cppdef

9.5.24 Concatenation of strings in definition

Applicable for: c90 c99

The ## is used to concatenate the part in front and afterwards.

The macro just deletes all spaces. It uses a virtual space to allow other macros to expand the text after the ##.

0_define:[\s]*##[\s]*\a;;;nn01 ;;;;cppdef

9.5.25 Variadic arguments

Applicable for: c99

Just replace the __VA_ARGS__ with the default to output all arguments. In the macro the start of the list is set.

0_define:__VA_ARGS__;$*;;nn00;;;;cppdef

9.5.26 The undef in C90 and later

Applicable for: c90 c99

The undef is using the argument collection pattern macroname.

0_pattern:macroname;[\a]~;stack_a begin-1
0_pattern:macroname;\A\ ;stack_a end-1  
0_pattern:macroname;+-+
-+-; stack_a pop_to_2 "\B" cat-1 "\ " cat stop
0_macro_tag:dir_2;cpp
0_define:[\s]*undef\s;;undefine;nn11;macroname;; "cpp";cpp;Ll
0_link:dir_1;dir_2

9.5.27 The undef in K&R

Applicable for: kr

Similar to the C90 version.

0_define:+-+
#define\s-+-;;undefine;nn11;macroname;; "cpp";cpp

9.5.28 Argument collection for include

Applicable for: all

First a pattern to collect the arguments of the include is defined.

Using stack a for the filename if in <>. Using stack b for the filename if in "".

0_specialchar:";[@00-@21@23-@ff]
0_pattern:inclarg;[<]~;stack_a begin no_macro
0_pattern:inclarg;>;stack_a end-1 stack_c 1 
0_pattern:inclarg;["]~;stack_b begin no_macro;1
0_pat_append:inclarg;[\"]*";stack_b end-1 stack_c 1;1
0_pattern:inclarg;+-+
-+-;stack_c =0 if "Error in name of include" errprint endif stop 

9.5.29 The include in C90 and later

Applicable for: c90 c99

The directive include is linked to the start of directives.

The include will set search directories and eventually call 1_include in the incl macro set to handle the include.

0_macro_tag:dir_3;cpp
0_define:[\s]*include\s;+-+3_define:`3_filename';3_findfile($1,3_sys_dirs)3_findfile($b0,3_local_dirs);;rn00;;;;cpp
3_push:`3_local_dirs';3_local_dirs,3_getdir(3_filename);;rn00;;;;cpp
3_include(3_filename)
3_pop:`3_local_dirs';cpp
-+-;;rr11;inclarg;;;cpp;Ll
0_link:dir_1;dir_3

9.5.30 The include in K&R

Applicable for: kr

Same as the C90 version, just macro name is different.

0_define:+-+
#include\s-+-;+-+3_define:`3_filename';3_findfile($1,3_sys_dirs)3_findfile($b0,3_local_dirs);;rn00;;;;cpp
3_push:`3_local_dirs';3_local_dirs,3_getdir(3_filename);;rn00;;;;cpp
3_include(3_filename)
3_pop:`3_local_dirs';cpp
-+-;;rr11;inclarg;;;cpp

9.5.31 Additional macros to support the include

Applicable for: all

0_define:3_define:;;define;nr01;0;;;cpp
0_define:3_push:;;push;nr01;0;;;cpp
0_define:3_pop:;;pop;nr01;0;;;cpp

9.5.32 Include in separate macro set incl

Applicable for: all

A separate macro set incl is used to perform the trigraph and backslash newline replacement of the first stage when including a file.

0_define:1_include;;include;rn00;;;;incl
0_def_mcall:3_include(;1_include;incl;rr01;cpp_args;;cpp

9.5.33 Trigraphs in include

Applicable for: all

Trigraphs are replaced.

0_define:??(;[;;rn00;;;;incl
0_define:??);];;rn00;;;;incl
0_define:??<;{;;rn00;;;;incl
0_define:??>;};;rn00;;;;incl
0_define:??=;#;;rn00;;;;incl
0_define:??/;\;;rn00;;;;incl
0_define:??';^;;rn00;;;;incl
0_define:??!;|;;rn00;;;;incl
0_define:??-;~;;rn00;;;;incl

9.5.34 Backslash newline in include

Applicable for: all

Backslash newlines are deleted.

Using a special character for the \.

0_specialchar:\;\
0_define:+-+[@00-@5b@5d-@ff]\\
-+-;;;nn10;;;;incl

9.5.35 Finding a file in a directory

Applicable for: all

Default directories are set.

The 3_findfile wil select the directory where the file was found.

0_define:3_local_dirs;.;;rn00;;;;cpp
0_define:3_sys_dirs;/usr/local/include,/usr/include;;rn00;;;;cpp
0_define:3_findfile(;;findfile;rr01;cpp_args;;;cpp

9.5.36 Getting the directory from a string

Applicable for: all

A macro to extract the directory from a string containing the file name including the directory.

0_pattern:getdir;[@00-@ff]~;stack_a begin-1 
0_pattern:getdir;/;stack_a argpos =0 if setend-0 else setend-1 endif  
0_pattern:getdir;);pushend stop
0_define:3_getdir(;$1;;nr00;getdir;;;cpp

9.5.37 Argument collection for if

Applicable for: all

This pattern will perform the evaluation of the expression of the if. This is similar to the pattern for the eval macro of the m4 emulation.

Stacks b and d are used for the calculations and parsing.

Stack c is used for the counting of brackets (( )).

Stack e is used for holding the status of argument collection for the defined operator.

It will output one of the macros 3_then or 3_else in stack a.

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:ifelse;[@00-@ff]~;stack_c 0 stack_d 1 stack_e 0
0_pattern:ifelse;\S[0-9];stack_b begin+1
0_pat_append:ifelse;[0-9a-zA-Z:]*\R;stack_b end-1 stack_d pop_to_0 0
0_pattern:ifelse;\B\a;stack_e dup >0 if stack_b begin+1 endif
0_pat_append:ifelse;[\A]*\ ;+-+stack_e dup >0 if
  stack_b end-1 "\B" cat-1 "\ " cat "cpp" 
  stack_d pop_to_0 0 stack_e pop 0 y_macro endif -+- 
0_pattern:ifelse;\Bdefined\ ;stack_b 31 opexif>= m?_num stack_d 1 stack_e pop 1 no_macro 
0_pattern:ifelse;+[0-9];+-+stack_d =0 if 
  stack_b 19 opexif>= + else stack_b 0 30 opexif>= + endif -+-
0_pattern:ifelse;-[0-9];+-+stack_d =0 if 
  stack_b 19 opexif>= - else stack_b 0 30 opexif>= - endif -+- 
0_pattern:ifelse;+\D;stack_b 19 opexif>= + stack_d 1 
0_pattern:ifelse;-\D;stack_b 19 opexif>= - stack_d 1
0_pattern:ifelse;\**\*;stack_b 20 opexif>= * stack_d 1
0_pattern:ifelse;/;stack_b 20 opexif>= / stack_d 1
0_pattern:ifelse;%;stack_b 20 opexif>= mod stack_d 1
0_pattern:ifelse;~;stack_b 29 opexif>= ~ stack_d 1
0_pattern:ifelse;!\=;stack_b 29 opexif>= ! stack_d 1
0_pattern:ifelse;<<;stack_b 18 opexif>= shift_l stack_d 1
0_pattern:ifelse;>>;stack_b 18 opexif>= shift_r stack_d 1
0_pattern:ifelse;\>>\>;stack_b 17 opexif>= > stack_d 1
0_pattern:ifelse;\<<\<;stack_b 17 opexif>= < stack_d 1
0_pattern:ifelse;>=;stack_b 17 opexif>= >= stack_d 1
0_pattern:ifelse;<=;stack_b 17 opexif>= <= stack_d 1
0_pattern:ifelse;==;stack_b 16 opexif>= = stack_d 1
0_pattern:ifelse;!=;stack_b 16 opexif>= != stack_d 1
0_pattern:ifelse;\&&\&;stack_b 15 opexif>= bit_and stack_d 1
0_pattern:ifelse;^;stack_b 14 opexif>= bit_exor stack_d 1
0_pattern:ifelse;\||\|;stack_b 13 opexif>= bit_or stack_d 1
0_pattern:ifelse;&&;stack_b 12 opexif>= and stack_d 1
0_pattern:ifelse;||;stack_b 11 opexif>= or stack_d 1
0_pattern:ifelse;(;stack_c 1 + dup >=2 if stack_b 0 oppush nop endif
0_pattern:ifelse;);stack_c 1 - dup >=1 if stack_b opexto nop endif 
0_pattern:ifelse;+-+
-+-;stack_b opexall dup =0  if stack_a "3_else" else stack_a "3_then"  endif stop 

9.5.38 The if in C90 and later

Applicable for: c90 c99

The directive include is linked to the start of directives.

It will output the macro 3_then or 3_else to select the proper text block.

0_macro_tag:dir_4;cpp
0_define:[\s]*if\s;$1;;rr11;ifelse;;;cpp;Ll
0_link:dir_1;dir_4

9.5.39 The if in K&R

Applicable for: kr

Same as the C90 version, just macro name is different.

0_define:+-+
#if\s-+-;$1;;rr11;ifelse;;;cpp

9.5.40 Pattern to select first text block

Applicable for: all

Pattern to select first text block and delete the rest.

Stack b is used to count the if endif blocks.

0_pattern:3then;[@00-@ff]~;stack_a begin-1 stack_b 1 
0_pattern:3then;+-+
[\s]*#-+-;
0_pat_tag:3then;then_1
0_pat_append:3then;[\s]*if\ ; stack_b 1 + 
0_pat_tag:3then;then_2
0_pat_part:3then;[\s]*else\ ; stack_b dup <=1 if stack_a pushend begin endif 
0_link:then_1;then_2
0_pat_tag:3then;then_3
0_pat_part:3then;[\s]*endif\ ; stack_b 1 - dup <=0 if stack_a pushend goback1 stop endif 
0_link:then_1;then_3
0_pat_tag:3then;then_4
0_pat_part:3then;[\s]*elif\ ;stack_b  dup <=1 if stack_a pushend begin endif 
0_link:then_1;then_4
0_pattern:3then;+-+
-+-; stack_a setend-0

9.5.41 The 3_then to select first text block

Applicable for: all

This macro is used when the if compare is true.

0_define:3_then;$1;;Rn00;3then;;;cpp

9.5.42 Pattern to select else text block

Applicable for: all

Pattern to select the else text block.

Stack b is used to count the if endif blocks.

Similar to the 3then pattern, but will stop at #elif and output 3_if macro.

0_pattern:3else;[@00-@ff]~;stack_a begin-1 stack_b 1 
0_pattern:3else;+-+
[\s]*#-+-;
0_pat_tag:3else;else_1
0_pat_append:3else;[\s]*if\ ; stack_b 1 + 
0_pat_tag:3else;else_2
0_pat_part:3else;[\s]*else\ ; stack_b dup <=1 if stack_a pushend begin endif 
0_link:else_1;else_2
0_pat_tag:3else;else_3
0_pat_part:3else;[\s]*endif\ ; stack_b 1 - dup <=0 if stack_a pushend goback1 stop endif 
0_link:else_1;else_3
0_pat_tag:3else;else_4
0_pat_part:3else;[\s]*elif\ ; stack_b dup <=1 if stack_a pushend pop_to_2 "3_if" goback1 stop endif 
0_link:else_1;else_4
0_pattern:3else;+-+
-+-;  stack_a setend-0

9.5.43 The 3_else to select else text block

Applicable for: all

This macro is used when the if compare is false.

0_define:3_else;$2;;Rn00;3else;;;cpp

9.5.44 The 3_if to test next part

Applicable for: all

This macro is used for performing an if like #if.

0_define:3_if;$1;;Rr00;ifelse;;;cpp
0_define:3_eval;$b0;;Rr00;ifelse;;;cpp

9.5.45 The ifdef and ifndef in C90 and later

Applicable for: c90 c99

Using pattern macroname that is also used by undef to get macro name.

0_macro_tag:dir_5;cpp
0_define:[\s]*ifdef\s;;ifmacro?;rn11;macroname;; "3_then" "3_else" "cpp" ;cpp;Ll
0_macro_tag:dir_6;cpp
0_define:[\s]*ifndef\s;;ifmacro?;rn11;macroname;; "3_else" "3_then" "cpp" ;cpp;Ll
0_link:dir_1;dir_5;dir_6

9.5.46 The ifdef and ifndef in K&R

Applicable for: kr

Same as the C90 version, just macro name is different.

0_define:+-+
#ifdef\s-+-;;ifmacro?;rn11;macroname;; "3_then" "3_else" "cpp" ;cpp
0_define:+-+
#ifndef\s-+-;;ifmacro?;rn11;macroname;; "3_else" "3_then" "cpp" ;cpp

9.5.47 The default macros

Applicable for: c90 c99

Default macros.

0_define:\B__FILE__\ ;"$2";get_var;rn11;;; -5 ;cpp
0_define:\B__LINE__\ ;;get_var;rn11;;; -4 ;cpp
0_define:\B__DATE__\ ;"0_shell:echo -n "$(date +"%b %e %Y")"
";;rn11;;;;cpp
0_define:\B__TIME__\ ;"0_shell:echo -n "$(date +"%H:%M:%S")"
";;rn11;;;;cpp
0_define:\B__STDC__\ ;1;;rn11;;;;cpp

For C99 some more default macros are defined.

0_define:\B__STDC_VERSION__\ ;199901L;;rn11;;;;cpp
0_define:\B__STDC_HOSTED__\ ;1;;rn11;;;;cpp

9.5.48 Some cleaning up of too many spaces and newlines

Applicable for: test

To make text compare with other cpp easier empty lines are deleted.

0_define:+-+\s
-+-;+-+
-+-;;rn00;;;;cpp
0_define:+-+

-+-;;;rn01;;;;cpp

9.5.49 End of emulation file, start of c files

Applicable for: all

Finally switch to the cpp macro set.

0_define:0_mset:;;macroset;nr01;0
0_mset:cpp


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