Revisión | 653 (tree) |
---|---|
Tiempo | 2017-07-08 09:26:20 |
Autor | y-moriguchi |
Example: m4 macro processor
@@ -69,6 +69,7 @@ | ||
69 | 69 | private string commentBegin; |
70 | 70 | private string commentEnd; |
71 | 71 | public ACNode Special { get; private set; } |
72 | + public bool SuppressComment { get; private set; } | |
72 | 73 | public string QuoteBegin |
73 | 74 | { |
74 | 75 | get |
@@ -212,13 +213,13 @@ | ||
212 | 213 | |
213 | 214 | if(mname.Equals("define")) |
214 | 215 | { |
215 | - if(lst.Count < 2) | |
216 | + if(lst.Count < 1) | |
216 | 217 | { |
217 | 218 | WriteUnevalMacro(mname, lst); |
218 | 219 | } |
219 | 220 | else |
220 | 221 | { |
221 | - DefineMacro(lst[0], lst[1]); | |
222 | + DefineMacro(lst[0], lst.Count > 1 ? lst[1] : ""); | |
222 | 223 | } |
223 | 224 | return true; |
224 | 225 | } |
@@ -236,7 +237,7 @@ | ||
236 | 237 | } |
237 | 238 | else if(mname.Equals("pushdef")) |
238 | 239 | { |
239 | - if(lst.Count < 2) | |
240 | + if(lst.Count < 1) | |
240 | 241 | { |
241 | 242 | WriteUnevalMacro(mname, lst); |
242 | 243 | return true; |
@@ -250,7 +251,7 @@ | ||
250 | 251 | mstk = new List<string>(); |
251 | 252 | macros.Add(lst[0], mstk); |
252 | 253 | } |
253 | - mstk.Add(lst[1]); | |
254 | + mstk.Add(lst.Count > 1 ? lst[1] : ""); | |
254 | 255 | return true; |
255 | 256 | } |
256 | 257 | else if(mname.Equals("popdef")) |
@@ -270,6 +271,20 @@ | ||
270 | 271 | } |
271 | 272 | return true; |
272 | 273 | } |
274 | + else if(mname.Equals("defn")) | |
275 | + { | |
276 | + if(lst.Count < 1) | |
277 | + { | |
278 | + WriteUnevalMacro(mname, lst); | |
279 | + return true; | |
280 | + } | |
281 | + else if(macros.ContainsKey(lst[0])) | |
282 | + { | |
283 | + mstk = macros[lst[0]]; | |
284 | + Write(mstk[mstk.Count - 1]); | |
285 | + } | |
286 | + return true; | |
287 | + } | |
273 | 288 | else if(mname.Equals("ifdef")) |
274 | 289 | { |
275 | 290 | if(lst.Count < 2) |
@@ -444,6 +459,35 @@ | ||
444 | 459 | } |
445 | 460 | return true; |
446 | 461 | } |
462 | + else if(mname.Equals("substr")) | |
463 | + { | |
464 | + int pos, len; | |
465 | + | |
466 | + if(lst.Count < 3) | |
467 | + { | |
468 | + WriteUnevalMacro(mname, lst); | |
469 | + } | |
470 | + else | |
471 | + { | |
472 | + if(!int.TryParse(lst[1], out pos) || !int.TryParse(lst[2], out len)) | |
473 | + { | |
474 | + throw new M4Exception(); | |
475 | + } | |
476 | + else if(pos < 0 && pos >= lst[0].Length) | |
477 | + { | |
478 | + throw new M4Exception(); | |
479 | + } | |
480 | + else if(len < 0 && len + pos >= lst[0].Length) | |
481 | + { | |
482 | + throw new M4Exception(); | |
483 | + } | |
484 | + else | |
485 | + { | |
486 | + Write(lst[0].Substring(pos, len)); | |
487 | + } | |
488 | + } | |
489 | + return true; | |
490 | + } | |
447 | 491 | else if(mname.Equals("translit")) |
448 | 492 | { |
449 | 493 | if(lst.Count < 3) |
@@ -530,8 +574,11 @@ | ||
530 | 574 | { |
531 | 575 | M4Object m4obj = new M4Object(this); |
532 | 576 | List<string> mstk = macros[mname]; |
577 | + string mbody; | |
533 | 578 | |
534 | - m4obj.Reader = new StringReader(mstk[mstk.Count - 1]); | |
579 | + m4obj.SuppressComment = true; | |
580 | + mbody = ScanArgs(mstk[mstk.Count - 1], mname, lst); | |
581 | + m4obj.Reader = new StringReader(mbody); | |
535 | 582 | m4obj.macroName = mname; |
536 | 583 | m4obj.args = lst; |
537 | 584 | M4p.Eval(m4obj); |
@@ -538,6 +585,93 @@ | ||
538 | 585 | } |
539 | 586 | } |
540 | 587 | |
588 | + private string ScanArgs(string body, string macroName, List<string> args) | |
589 | + { | |
590 | + int arg; | |
591 | + char c; | |
592 | + StringBuilder b = new StringBuilder(), n; | |
593 | + | |
594 | + for(int i = 0; i < body.Length; i++) | |
595 | + { | |
596 | + c = body[i]; | |
597 | + if(c == '$') | |
598 | + { | |
599 | + if(++i >= body.Length) | |
600 | + { | |
601 | + b.Append(c); | |
602 | + } | |
603 | + else if((c = body[i]) >= '0' && c <= '9') | |
604 | + { | |
605 | + n = new StringBuilder(); | |
606 | + for(; i < body.Length && (c = body[i]) >= '0' && c <= '9'; i++) | |
607 | + { | |
608 | + n.Append(c); | |
609 | + } | |
610 | + i--; | |
611 | + arg = int.Parse(n.ToString()); | |
612 | + if(arg == 0 && macroName != null) | |
613 | + { | |
614 | + b.Append(macroName); | |
615 | + } | |
616 | + else if(arg > 0 && args != null) | |
617 | + { | |
618 | + if(arg - 1 < args.Count) | |
619 | + { | |
620 | + b.Append(args[arg - 1]); | |
621 | + } | |
622 | + } | |
623 | + } | |
624 | + else if("#@*".IndexOf(c) >= 0) | |
625 | + { | |
626 | + switch(c) | |
627 | + { | |
628 | + case '#': | |
629 | + b.Append(args.Count); | |
630 | + break; | |
631 | + case '*': | |
632 | + for(int j = 0; j < args.Count; j++) | |
633 | + { | |
634 | + b.Append(args[j]); | |
635 | + if(j < args.Count - 1) | |
636 | + { | |
637 | + b.Append(','); | |
638 | + } | |
639 | + } | |
640 | + break; | |
641 | + case '@': | |
642 | + for(int j = 0; j < args.Count; j++) | |
643 | + { | |
644 | + b.Append(QuoteBegin + args[j] + QuoteEnd); | |
645 | + if(j < args.Count - 1) | |
646 | + { | |
647 | + b.Append(','); | |
648 | + } | |
649 | + } | |
650 | + break; | |
651 | + } | |
652 | + } | |
653 | + else | |
654 | + { | |
655 | + b.Append('$'); | |
656 | + b.Append(c); | |
657 | + } | |
658 | + } | |
659 | + else if(c == '\u0001') | |
660 | + { | |
661 | + b.Append(QuoteBegin); | |
662 | + } | |
663 | + else if(c == '\u0002') | |
664 | + { | |
665 | + b.Append(QuoteEnd); | |
666 | + } | |
667 | + else | |
668 | + { | |
669 | + b.Append(c); | |
670 | + } | |
671 | + } | |
672 | + return b.ToString(); | |
673 | + } | |
674 | + | |
541 | 675 | private void AddAllSplited(List<string> nlst, string text) |
542 | 676 | { |
543 | 677 | int cnt = 0, par = 0; |
@@ -549,13 +683,13 @@ | ||
549 | 683 | c = text[i]; |
550 | 684 | if(cnt > 0) |
551 | 685 | { |
552 | - if(text.IndexOf(QuoteBegin) == i + QuoteBegin.Length) | |
686 | + if(text.IndexOf(QuoteBegin) == i) | |
553 | 687 | { |
554 | 688 | b.Append(QuoteBegin); |
555 | 689 | i += QuoteBegin.Length - 1; |
556 | 690 | cnt++; |
557 | 691 | } |
558 | - else if(text.IndexOf(QuoteEnd) == i + QuoteEnd.Length) | |
692 | + else if(text.IndexOf(QuoteEnd) == i) | |
559 | 693 | { |
560 | 694 | b.Append(QuoteEnd); |
561 | 695 | i += QuoteEnd.Length - 1; |
@@ -580,7 +714,7 @@ | ||
580 | 714 | } |
581 | 715 | else |
582 | 716 | { |
583 | - if(text.IndexOf(QuoteBegin) == i + QuoteBegin.Length) | |
717 | + if(text.IndexOf(QuoteBegin) == i) | |
584 | 718 | { |
585 | 719 | b.Append(QuoteBegin); |
586 | 720 | i += QuoteBegin.Length - 1; |
@@ -612,7 +746,7 @@ | ||
612 | 746 | |
613 | 747 | foreach(string str in lst) |
614 | 748 | { |
615 | - evd = EvalToString(str); | |
749 | + evd = EvalToString(Regex.Replace(str, "^[ \n\t]+", "")); | |
616 | 750 | AddAllSplited(nlst, evd); |
617 | 751 | } |
618 | 752 | EvalMacroEvaled(mname, nlst); |
@@ -622,6 +756,7 @@ | ||
622 | 756 | { |
623 | 757 | M4Object m4obj = new M4Object(this); |
624 | 758 | |
759 | + m4obj.SuppressComment = true; | |
625 | 760 | m4obj.Reader = new StringReader(text); |
626 | 761 | M4p.Eval(m4obj); |
627 | 762 | } |
@@ -632,6 +767,7 @@ | ||
632 | 767 | TextWriter tmp; |
633 | 768 | StringWriter sw; |
634 | 769 | |
770 | + m4obj.SuppressComment = true; | |
635 | 771 | m4obj.Reader = new StringReader(text); |
636 | 772 | tmp = divertBuffers[divnum]; |
637 | 773 | m4obj.divertBuffers[divnum] = sw = new StringWriter(); |
@@ -640,51 +776,6 @@ | ||
640 | 776 | return sw.ToString(); |
641 | 777 | } |
642 | 778 | |
643 | - public void WriteArg(int arg) | |
644 | - { | |
645 | - if(arg == 0 && macroName != null) | |
646 | - { | |
647 | - Eval(macroName); | |
648 | - } | |
649 | - else if(arg > 0 && args != null) | |
650 | - { | |
651 | - if(arg - 1 < args.Count) | |
652 | - { | |
653 | - Eval(args[arg - 1]); | |
654 | - } | |
655 | - } | |
656 | - } | |
657 | - | |
658 | - public void WriteArgFunny(int ch) | |
659 | - { | |
660 | - switch(ch) | |
661 | - { | |
662 | - case '#': | |
663 | - Write(args.Count); | |
664 | - break; | |
665 | - case '*': | |
666 | - for(int i = 0; i < args.Count; i++) | |
667 | - { | |
668 | - Eval(args[i]); | |
669 | - if(i < args.Count - 1) | |
670 | - { | |
671 | - Write(','); | |
672 | - } | |
673 | - } | |
674 | - break; | |
675 | - case '@': | |
676 | - for(int i = 0; i < args.Count; i++) | |
677 | - { | |
678 | - Write(args[i]); | |
679 | - if(i < args.Count - 1) | |
680 | - { | |
681 | - Write(','); | |
682 | - } | |
683 | - } | |
684 | - break; | |
685 | - } | |
686 | - } | |
687 | - | |
688 | 779 | public void Flush() { |
689 | 780 | for(int i = 1; i < MaxDivert; i++) |
690 | 781 | { |
@@ -949,19 +1040,20 @@ | ||
949 | 1040 | using(StreamReader sr = new StreamReader(args[cnt])) |
950 | 1041 | { |
951 | 1042 | m4obj = new M4Object(m4obj, sr); |
952 | - M4p.Eval(m4obj); | |
1043 | + m4obj = M4p.Eval(m4obj); | |
1044 | + m4obj.Flush(); | |
953 | 1045 | } |
954 | 1046 | } |
955 | 1047 | } |
956 | 1048 | else |
957 | 1049 | { |
958 | - while(!M4p.EvalFromConsole(m4obj)) | |
1050 | + while((m4obj = M4p.EvalFromConsole(m4obj)) != null) | |
959 | 1051 | { |
960 | 1052 | Console.WriteLine(); |
961 | 1053 | m4obj.DnlFlg = false; |
1054 | + m4obj.Flush(); | |
962 | 1055 | } |
963 | 1056 | } |
964 | - m4obj.Flush(); | |
965 | 1057 | Environment.Exit(0); |
966 | 1058 | } |
967 | 1059 | } |
@@ -0,0 +1,25 @@ | ||
1 | +rm test/testtmp*.txt | |
2 | + | |
3 | +awk ' | |
4 | +BEGIN { no = 1; } | |
5 | +/^-+$/ { close(sprintf("test/testtmp%04d.txt", no)); no++; next; } | |
6 | +{ print > (sprintf("test/testtmp%04d.txt", no)); } | |
7 | +' test.txt | |
8 | + | |
9 | +for i in test/testtmp*.txt | |
10 | +do | |
11 | + j=`echo $i | sed 's/\.txt//'` | |
12 | + if ! m4 $i > $j.out1.txt | |
13 | + then | |
14 | + echo "$i - original failed" | |
15 | + elif ! mono --debug m4.exe $i > $j.out2.txt | |
16 | + then | |
17 | + echo "$i - exe failed" | |
18 | + elif diff $j.out1.txt $j.out2.txt | |
19 | + then | |
20 | + echo "$i - Success" | |
21 | + else | |
22 | + echo "$i - failed" | |
23 | + fi | |
24 | +done | |
25 | + |
@@ -0,0 +1,242 @@ | ||
1 | +This is a plain text. | |
2 | +------------- | |
3 | +define(`plain',`macro') | |
4 | +This is a plain text. | |
5 | +------------- | |
6 | +define(`plain',`macro') | |
7 | +This is a `plain' text. | |
8 | +------------- | |
9 | +define(`plain',`macro') | |
10 | +This is a ``plain'' text. | |
11 | +------------- | |
12 | +define(`plain', `macro') | |
13 | +This is a plain text. | |
14 | +------------- | |
15 | +define(`plain', macro) | |
16 | +This is a plain text. | |
17 | +------------- | |
18 | +define(`plain',macro ) | |
19 | +This is a plain text. | |
20 | +------------- | |
21 | +define(`plain' ,macro ) | |
22 | +This is a plain text. | |
23 | +------------- | |
24 | +define( plain, macro) | |
25 | +This is a plain text. | |
26 | +------------- | |
27 | +define(X,Y) | |
28 | +define(Y,`macro') | |
29 | +This is a X text. | |
30 | +------------- | |
31 | +define(X,`macro | |
32 | +newline') | |
33 | +This is a X text. | |
34 | +------------- | |
35 | +define(X,`test') | |
36 | +define(`test',`macro') | |
37 | +This is a X text. | |
38 | +------------- | |
39 | +define(X,``test'') | |
40 | +define(`test',`macro') | |
41 | +This is a X text. | |
42 | +------------- | |
43 | +define(X,`$1 -> $2') | |
44 | +X(a,b) | |
45 | +X(`a',`b') | |
46 | +X( a , b ) | |
47 | +X(a) | |
48 | +X( a ) | |
49 | +X() | |
50 | +------------- | |
51 | +define(X,`$0$#') | |
52 | +X(a) | |
53 | +------------- | |
54 | +define(`echo1',`$*') | |
55 | +define(pen,pineapple) | |
56 | +echo1(`I',`have',`a',`pen') | |
57 | +echo1(`I',`have',`a',``pen'') | |
58 | +------------- | |
59 | +define(`echo1',`$@') | |
60 | +define(pen,pineapple) | |
61 | +echo1(`I',`have',`a',`pen') | |
62 | +echo1(`I',`have',`a',``pen'') | |
63 | +------------- | |
64 | +define(`X',`XJapan') | |
65 | +X : Kurenai | |
66 | +undefine(`X') | |
67 | +X : Kurenai | |
68 | +------------- | |
69 | +define(`X',`XJapan') | |
70 | +X : Kurenai | |
71 | +pushdef(`X',``X'') | |
72 | +X : Kurenai | |
73 | +popdef(`X') | |
74 | +X : Kurenai | |
75 | +------------- | |
76 | +include(`zinc.txt') | |
77 | +------------- | |
78 | +sinclude(`zinc.txt') | |
79 | +------------- | |
80 | +define(`inc', sinclude(`zinc.txt')) | |
81 | +inc | |
82 | +Syoko Hoshi : Kurenai | |
83 | +inc | |
84 | +------------- | |
85 | +ifdef(`COND',``COND' is defined... | |
86 | +`COND' is COND.',`COND is *NOT* defined!') | |
87 | +------------- | |
88 | +define(`COND') | |
89 | +ifdef(`COND',``COND' is defined... | |
90 | +`COND' is COND.',`COND is *NOT* defined!') | |
91 | +------------- | |
92 | +define(`COND', `condition A') | |
93 | +ifdef(`COND',``COND' is defined... | |
94 | +`COND' is COND.',`COND is *NOT* defined!') | |
95 | +------------- | |
96 | +define(`COND', 1) | |
97 | +ifelse(COND,1,``COND' is one',``COND' is COND') | |
98 | +------------- | |
99 | +define(`COND', 3) | |
100 | +ifelse(COND,1,``COND' is one',``COND' is COND') | |
101 | +------------- | |
102 | +define(`COND', 1) | |
103 | +ifelse(COND,1,``COND' is one',COND,2,``COND' is two',``COND' is COND') | |
104 | +------------- | |
105 | +define(`COND', 2) | |
106 | +ifelse(COND,1,``COND' is one',COND,2,``COND' is two',``COND' is COND') | |
107 | +------------- | |
108 | +define(`COND', 3) | |
109 | +ifelse(COND,1,``COND' is one',COND,2,``COND' is two',``COND' is COND') | |
110 | +------------- | |
111 | +define(`last',`ifelse($#,1,$1,`last(shift($@))')') | |
112 | +last(foo,bar,baz,quux) | |
113 | +------------- | |
114 | +define(`reverse',`ifelse($#,1,$1,`reverse(shift($@)) $1')') | |
115 | +reverse(`foo',`bar',`baz',`quux') | |
116 | +------------- | |
117 | +define(`forloop', | |
118 | + `pushdef(`$1', `$2')_forloop(`$1', `$2', `$3', `$4')popdef(`$1')') | |
119 | +define(`_forloop', | |
120 | + `$4`'ifelse($1, `$3', , | |
121 | + `define(`$1', incr($1))_forloop(`$1', `$2', `$3', `$4')')') | |
122 | +forloop(`i', 1, 8, `i ') | |
123 | +forloop(`i', 1, 4, `forloop(`j', 1, 8, `(i, j) ') | |
124 | +') | |
125 | +------------- | |
126 | +changequote(/*,*/) | |
127 | +define(/*reverse*/,/*ifelse($#,1,$1,/*reverse(shift($@)) $1*/)*/) | |
128 | +reverse(/*foo*/,/*bar*/,/*baz*/,/*quux*/) | |
129 | +------------- | |
130 | +changecom(/*,*/) | |
131 | +define(`X',`XFree86') | |
132 | +/* comment for X */ | |
133 | +# for X Window System | |
134 | +------------- | |
135 | +X | |
136 | +define(`X',`test') | |
137 | +X | |
138 | +define(`X',`test')dnl | |
139 | +X | |
140 | +------------- | |
141 | +incr(1) | |
142 | +decr(2) | |
143 | +------------- | |
144 | +eval(1) | |
145 | +eval(+1) | |
146 | +eval(-1) | |
147 | +eval(2 ** 3) | |
148 | +eval(5 * 3) | |
149 | +eval(5 / 3) | |
150 | +eval(5 % 3) | |
151 | +eval(5 + 3) | |
152 | +eval(5 - 3) | |
153 | +eval(5 == 3) | |
154 | +eval(3 == 3) | |
155 | +eval(5 != 3) | |
156 | +eval(3 != 3) | |
157 | +eval(5 >= 3) | |
158 | +eval(3 >= 3) | |
159 | +eval(2 >= 3) | |
160 | +eval(5 <= 3) | |
161 | +eval(3 <= 3) | |
162 | +eval(2 <= 3) | |
163 | +eval(5 > 3) | |
164 | +eval(3 > 3) | |
165 | +eval(2 > 3) | |
166 | +eval(5 < 3) | |
167 | +eval(3 < 3) | |
168 | +eval(2 < 3) | |
169 | +eval(!5) | |
170 | +eval(~5) | |
171 | +eval(7 & 3) | |
172 | +eval(5 | 3) | |
173 | +eval(7 ^ 3) | |
174 | +eval(5 && 3) | |
175 | +eval(5 && 0) | |
176 | +eval(0 && 3) | |
177 | +eval(0 && 0) | |
178 | +eval(5 || 3) | |
179 | +eval(5 || 0) | |
180 | +eval(0 || 3) | |
181 | +eval(0 || 0) | |
182 | +eval(2 ** +3) | |
183 | +eval(2 ** 3 * 2) | |
184 | +eval(2 ** (3 * 2)) | |
185 | +eval(2 + 3 * 5) | |
186 | +eval(5 * (3 + 2)) | |
187 | +eval(2 - 3 * 5) | |
188 | +eval(5 / (3 + 2)) | |
189 | +eval(2 % 3 * 5) | |
190 | +eval(5 % (3 + 2)) | |
191 | +eval(2 == 5 + 3) | |
192 | +eval(2 == 5 - 3) | |
193 | +eval(2 != 5 + 3) | |
194 | +eval(2 != 5 - 3) | |
195 | +eval(2 <= 5 + 3) | |
196 | +eval(2 <= 5 - 3) | |
197 | +eval(2 >= 5 + 3) | |
198 | +eval(2 >= 5 - 3) | |
199 | +eval(2 < 5 + 3) | |
200 | +eval(2 < 5 - 3) | |
201 | +eval(2 > 5 + 3) | |
202 | +eval(2 > 5 - 3) | |
203 | +eval(5 + (3 == 2)) | |
204 | +eval(5 - (3 == 2)) | |
205 | +eval(5 + (3 != 2)) | |
206 | +eval(5 - (3 != 2)) | |
207 | +eval(5 + (3 <= 2)) | |
208 | +eval(5 - (3 <= 2)) | |
209 | +eval(5 + (3 >= 2)) | |
210 | +eval(5 - (3 >= 2)) | |
211 | +eval(5 + (3 < 2)) | |
212 | +eval(5 - (3 < 2)) | |
213 | +eval(5 + (3 > 2)) | |
214 | +eval(5 - (3 > 2)) | |
215 | +eval(!5 == 1) | |
216 | +eval(!5 != 1) | |
217 | +eval(!5 <= 1) | |
218 | +eval(!5 >= 1) | |
219 | +eval(!5 < 1) | |
220 | +eval(!5 > 1) | |
221 | +eval(~5 == 1) | |
222 | +eval(~5 != 1) | |
223 | +eval(~5 <= 1) | |
224 | +eval(~5 >= 1) | |
225 | +eval(~5 < 1) | |
226 | +eval(~5 > 1) | |
227 | +eval(2 & !5) | |
228 | +eval(2 | 3 & 5) | |
229 | +eval(2 ^ 3 & 5) | |
230 | +eval(2 && 3 | 5) | |
231 | +eval(2 || 3 && 5) | |
232 | +------------- | |
233 | +define(`reverse',`ifelse($#,1,$1,`reverse(shift($@)) $1')') | |
234 | +defn(`reverse') | |
235 | +------------- | |
236 | +len(aaaaaaa) | |
237 | +substr(abcdefg,3,2) | |
238 | +substr(abcdefg,0,7) | |
239 | +substr(abcdefg,6,1) | |
240 | +------------- | |
241 | +define(`X',`I have a pen. I have an apple.') | |
242 | +translit(X,`a-z',`A-Z') | |
\ No newline at end of file |