Here is a small ruleset that recognises a list and prints it first forwards, and then backwards, putting commas between the elements of the list. The first element is required to be a word, and subsequent elements may be either word or number:
.left() - error output <- eof -; - sample output <- eof -; - word :X <- sample - list :X :X; list :B :F ';' <- sample 'here it is forwards: ' F '\n' 'here it is backwards: ' B '\n'eom; list :B :F word :X <- sample - list:{ X ', ' B } :{ F ', ' X }; list :B :F number :X <- sample - list:{ X ', ' B } :{ F ', ' X };
.left(20L) .[0-9] % { repeat .[0-9] % } { option '.' % repeat [0-9] % } toNum :N <- number :N; .[a-zA-Z] % { repeat .[a-zA-Z] % } toSym :W <- word :W; .[ \n\t] <- - ;
.left(30R) - anything <- line - ; eof <- line eof; '\n' <- line; - line <- error '--- not understood - skipping one line\n' eom; - eom <- output ; - out <- eom - ;
Here is the ruleset in action - it has been compiled to produce leftRecursion.gdc (the .gdc extension is used for examples where the same rules are being compiled to several different executable representations - it is a D language wrapping round the lmr load format)
[peri@a4 examples]$ ./leftRecursion.gdc a 1 2 c; here it is forwards: a, 1, 2, c here it is backwards: c, 2, 1, a
In the ruleset, the following rules are used to add words and numbers to the list:
list :B :F word :X <- sample - list:{ X ', ' B } :{ F ', ' X }; list :B :F number :X <- sample - list:{ X ', ' B } :{ F ', ' X };
The second rule (as the newest) will be tried first. So when a word is used in the body of a list, these rules will always try to recognise list :B :F number :X before falling back on the alternative list :B :F word :X. It can be seen in the lm-diagram output below that this involves re-establishing two levels of right-nesting.
Fortunately the language machine is designed specifically to deal with this kind of situation in a reasonably efficient way. Where performance is important, it's best to avoid backtracks - for example:
- word :X <- item :X; - number :X <- item :X; list :F :B item :X <- sample - list:{ X ', ' B } :{ F ', ' X };
lm-diagram output
[peri@a4 examples]$ ./leftRecursion.gdc -W 40 -t D a 1 2 c; eof 'a' ? eof 'a' .------------000001 | sample 'a' |? sample 'a' |.-----------000002 || word 'a' ||? word 'a' ||.----------000003 ||| % ' ' ||| repeat ' ' ||| [a-zA-Z] ' ' |||? [a-zA-Z] ' ' |||- [a-zA-Z] ' ' ||| toSym ' ' ||| : ' ' ||'----------000003---------- ----------000003-------------. || word word | || : : | |'-----------000002---------- ----------000002------------.| | sample list || |? sample list ?? |.-----------000005 || || : : || || : : || || 000002------------'| || 000003-------------' || number ' ' ||? number ' ' || number '1' ||? number '1' ||.----------000007 ||| % ' ' ||| repeat ' ' ||| [0-9] ' ' |||? [0-9] ' ' |||- [0-9] ' ' ||| option ' ' ||| '.' ' ' |||? '.' ' ' |||- '.' ' ' ||| toNum ' ' ||| : ' ' ||'----------000007---------- ----------000007-------------. || number number | || : : | |'-----------000005---------- ----------000005------------.| | sample list || |? sample list ?? |.-----------000010 || || : : || || : : || || 000005------------'| || 000007-------------' || number ' ' ||? number ' ' || number '2' ||? number '2' ||.----------000012 ||| % ' ' ||| repeat ' ' ||| [0-9] ' ' |||? [0-9] ' ' |||- [0-9] ' ' ||| option ' ' ||| '.' ' ' |||? '.' ' ' |||- '.' ' ' ||| toNum ' ' ||| : ' ' ||'----------000012---------- ----------000012-------------. || number number | || : : | |'-----------000010---------- ----------000010------------.| | sample list || |? sample list ?? |.-----------000015 || || : : || || : : || || 000010------------'| || 000012-------------' || number ' ' ||? number ' ' || number 'c' ||? number 'c' ||- number 'c' || : : || || : : || || 000010------------'| || 000012-------------' || word ' ' ||? word ' ' || word 'c' ||? word 'c' ||.----------000018 ||| % ';' ||| repeat ';' ||| [a-zA-Z] ';' |||? [a-zA-Z] ';' |||- [a-zA-Z] ';' ||| toSym ';' ||| : ';' ||'----------000018---------- ----------000018-------------. || word word | || : : | |'-----------000015---------- ----------000015------------.| | sample list || |? sample list ?? |.-----------000019 || || : : || || : : || || 000015------------'| || 000018-------------' || number ';' ||? number ';' ||- number ';' || : : || || : : || || 000015------------'| || 000018-------------' || word ';' ||? word ';' ||- word ';' || : : || || : : || || 000015------------'| || 000018-------------' || ';' ';' |'-----------000019---------- ----------000019-------------. | sample sample | | output 'h' | |? output 'h' ? |.-----------000020 | || eom 'h' | ||? eom 'h' ? ||.----------000021 | ||| out 'h' | h ||'----------000021 | || eom 'e' | ||? eom 'e' ? ||.----------000022 | ||| out 'e' | e ||'----------000022 | || eom 'r' | ||? eom 'r' ? ||.----------000023 | ||| out 'r' | r ||'----------000023 | || eom 'e' | ||? eom 'e' ? ||.----------000024 | ||| out 'e' | e ||'----------000024 | || eom ' ' | ||? eom ' ' ? ||.----------000025 | ||| out ' ' | ||'----------000025 | || eom 'i' | ||? eom 'i' ? ||.----------000026 | ||| out 'i' | i ||'----------000026 | || eom 't' | ||? eom 't' ? ||.----------000027 | ||| out 't' | t ||'----------000027 | || eom ' ' | ||? eom ' ' ? ||.----------000028 | ||| out ' ' | ||'----------000028 | || eom 'i' | ||? eom 'i' ? ||.----------000029 | ||| out 'i' | i ||'----------000029 | || eom 's' | ||? eom 's' ? ||.----------000030 | ||| out 's' | s ||'----------000030 | || eom ' ' | ||? eom ' ' ? ||.----------000031 | ||| out ' ' | ||'----------000031 | || eom 'f' | ||? eom 'f' ? ||.----------000032 | ||| out 'f' | f ||'----------000032 | || eom 'o' | ||? eom 'o' ? ||.----------000033 | ||| out 'o' | o ||'----------000033 | || eom 'r' | ||? eom 'r' ? ||.----------000034 | ||| out 'r' | r ||'----------000034 | || eom 'w' | ||? eom 'w' ? ||.----------000035 | ||| out 'w' | w ||'----------000035 | || eom 'a' | ||? eom 'a' ? ||.----------000036 | ||| out 'a' | a ||'----------000036 | || eom 'r' | ||? eom 'r' ? ||.----------000037 | ||| out 'r' | r ||'----------000037 | || eom 'd' | ||? eom 'd' ? ||.----------000038 | ||| out 'd' | d ||'----------000038 | || eom 's' | ||? eom 's' ? ||.----------000039 | ||| out 's' | s ||'----------000039 | || eom ':' | ||? eom ':' ? ||.----------000040 | ||| out ':' | : ||'----------000040 | || eom ' ' | ||? eom ' ' ? ||.----------000041 | ||| out ' ' | ||'----------000041 | || eom ' ' | ||? eom ' ' ? ||.----------000042 | ||| out ' ' | ||'----------000042 | || eom a | ||? eom a ? ||.----------000043 | ||| out a | a ||'----------000043 | || eom ',' | ||? eom ',' ? ||.----------000044 | ||| out ',' | , ||'----------000044 | || eom ' ' | ||? eom ' ' ? ||.----------000045 | ||| out ' ' | ||'----------000045 | || eom 1 | ||? eom 1 ? ||.----------000046 | ||| out 1 | 1 ||'----------000046 | || eom ',' | ||? eom ',' ? ||.----------000047 | ||| out ',' | , ||'----------000047 | || eom ' ' | ||? eom ' ' ? ||.----------000048 | ||| out ' ' | ||'----------000048 | || eom 2 | ||? eom 2 ? ||.----------000049 | ||| out 2 | 2 ||'----------000049 | || eom ',' | ||? eom ',' ? ||.----------000050 | ||| out ',' | , ||'----------000050 | || eom ' ' | ||? eom ' ' ? ||.----------000051 | ||| out ' ' | ||'----------000051 | || eom c | ||? eom c ? ||.----------000052 | ||| out c | c ||'----------000052 | || eom '\n' | ||? eom '\n' ? ||.----------000053 | ||| out '\n' |
||'----------000053 | || eom 'h' | ||? eom 'h' ? ||.----------000054 | ||| out 'h' | h ||'----------000054 | || eom 'e' | ||? eom 'e' ? ||.----------000055 | ||| out 'e' | e ||'----------000055 | || eom 'r' | ||? eom 'r' ? ||.----------000056 | ||| out 'r' | r ||'----------000056 | || eom 'e' | ||? eom 'e' ? ||.----------000057 | ||| out 'e' | e ||'----------000057 | || eom ' ' | ||? eom ' ' ? ||.----------000058 | ||| out ' ' | ||'----------000058 | || eom 'i' | ||? eom 'i' ? ||.----------000059 | ||| out 'i' | i ||'----------000059 | || eom 't' | ||? eom 't' ? ||.----------000060 | ||| out 't' | t ||'----------000060 | || eom ' ' | ||? eom ' ' ? ||.----------000061 | ||| out ' ' | ||'----------000061 | || eom 'i' | ||? eom 'i' ? ||.----------000062 | ||| out 'i' | i ||'----------000062 | || eom 's' | ||? eom 's' ? ||.----------000063 | ||| out 's' | s ||'----------000063 | || eom ' ' | ||? eom ' ' ? ||.----------000064 | ||| out ' ' | ||'----------000064 | || eom 'b' | ||? eom 'b' ? ||.----------000065 | ||| out 'b' | b ||'----------000065 | || eom 'a' | ||? eom 'a' ? ||.----------000066 | ||| out 'a' | a ||'----------000066 | || eom 'c' | ||? eom 'c' ? ||.----------000067 | ||| out 'c' | c ||'----------000067 | || eom 'k' | ||? eom 'k' ? ||.----------000068 | ||| out 'k' | k ||'----------000068 | || eom 'w' | ||? eom 'w' ? ||.----------000069 | ||| out 'w' | w ||'----------000069 | || eom 'a' | ||? eom 'a' ? ||.----------000070 | ||| out 'a' | a ||'----------000070 | || eom 'r' | ||? eom 'r' ? ||.----------000071 | ||| out 'r' | r ||'----------000071 | || eom 'd' | ||? eom 'd' ? ||.----------000072 | ||| out 'd' | d ||'----------000072 | || eom 's' | ||? eom 's' ? ||.----------000073 | ||| out 's' | s ||'----------000073 | || eom ':' | ||? eom ':' ? ||.----------000074 | ||| out ':' | : ||'----------000074 | || eom ' ' | ||? eom ' ' ? ||.----------000075 | ||| out ' ' | ||'----------000075 | || eom c | ||? eom c ? ||.----------000076 | ||| out c | c ||'----------000076 | || eom ',' | ||? eom ',' ? ||.----------000077 | ||| out ',' | , ||'----------000077 | || eom ' ' | ||? eom ' ' ? ||.----------000078 | ||| out ' ' | ||'----------000078 | || eom 2 | ||? eom 2 ? ||.----------000079 | ||| out 2 | 2 ||'----------000079 | || eom ',' | ||? eom ',' ? ||.----------000080 | ||| out ',' | , ||'----------000080 | || eom ' ' | ||? eom ' ' ? ||.----------000081 | ||| out ' ' | ||'----------000081 | || eom 1 | ||? eom 1 ? ||.----------000082 | ||| out 1 | 1 ||'----------000082 | || eom ',' | ||? eom ',' ? ||.----------000083 | ||| out ',' | , ||'----------000083 | || eom ' ' | ||? eom ' ' ? ||.----------000084 | ||| out ' ' | ||'----------000084 | || eom a | ||? eom a ? ||.----------000085 | ||| out a | a ||'----------000085 | || eom '\n' | ||? eom '\n' ? ||.----------000086 | ||| out '\n' |
||'----------000086 | || eom eom | |'-----------000020---------- ----------000020------------.| | output output || '------------000001 || 000020------------'| 000019-------------' eof '\n' ? eof '\n' eof eof [peri@a4 examples]$