-Version 0.10.2 (2006-04-13)
+Version 0.10.2 (2006-??-??)
---------------------------
+- Fixed -i switch.
+- Added configuration 'yyfill:enable' to allow suppression of YYFILL() blocks.
- Added tutorial like lessons to re2c.
- Added /*!ignore!re2c */ to support documenting of re2c source.
- Fixed issue with multiline re2c comments (/*!max:re2c ... */ and alike).
o << indent(ind) << "YYSETSTATE(" << fillIndex << ");\n";
}
- if (n == 1)
+ if (bUseYYFill)
{
- o << indent(ind) << "if(YYLIMIT == YYCURSOR) YYFILL(1);\n";
- }
- else
- {
- o << indent(ind) << "if((YYLIMIT - YYCURSOR) < " << n << ") YYFILL(" << n << ");\n";
+ if (n == 1)
+ {
+ o << indent(ind) << "if(YYLIMIT == YYCURSOR) YYFILL(1);\n";
+ }
+ else
+ {
+ o << indent(ind) << "if((YYLIMIT - YYCURSOR) < " << n << ") YYFILL(" << n << ");\n";
+ }
}
if (fFlag)
std::ostream& operator << (std::ostream& o, const file_info& li)
{
- if (li.ln)
+ if (li.ln && !iFlag)
{
o << "#line " << li.ln->get_line() << " \"" << li.fname << "\"\n";
}
{
bUseStateNext = num != 0;
}
+ else if (cfg.to_string() == "yyfill:enable")
+ {
+ bUseYYFill = num != 0;
+ }
else
{
fatal("unrecognized configuration name or illegal integer value");
extern bool bUseStateAbort;
extern bool bUseStateNext;
extern bool bWroteGetState;
+extern bool bUseYYFill;
extern uint asc2ebc[256];
extern uint ebc2asc[256];
</ul>
<hr />
<h1>Changelog</h1>
-<h2>2006-04-13: 0.10.2</h2>
+<h2>2006-??-??: 0.10.2</h2>
<ul>
+<li>Fixed -i switch.</li>
+<li>Added configuration 'yyfill:enable' to allow suppression of YYFILL() blocks.</li>
<li>Added tutorial like lessons to re2c.</li>
<li>Added /*!ignore!re2c */ to support documenting of re2c source.</li>
<li>Fixed issue with multiline re2c comments (/*!max:re2c ... */ and alike).</li>
<dt><i>re2c:yybm:hex</i> <b>=</b> 0 <b>;</b></dt>
<dd>If set to zero then a decimal table is being used else a hexadecimal table
will be generated.</dd>
+<dt><i>re2c:yyfill:enable</i> <b>=</b> 1 <b>;</b></dt>
+<dd>Set this to zero to suppress generation of YYFILL(). When using this be sure
+to verify that the generated scanner does not read behind input. Allowing
+this behavior might introduce sever security issues to you programs.</dd>
<dt><i>re2c:startlabel</i> <b>=</b> 0 <b>;</b></dt>
<dd>If set to a non zero integer then the start label of the next scanner
blocks will be generated even if not used by the scanner itself. Otherwise the
/* Generated by re2c */
#line 1 "calc_005.re"
-/* re2c lesson_001, calc_004, (c) M. Boerger 2006 */
+/* re2c lesson_001, calc_005, (c) M. Boerger 2006 */
#include <stdlib.h>
#include <stdio.h>
-/* re2c lesson_001, calc_004, (c) M. Boerger 2006 */
+/* re2c lesson_001, calc_005, (c) M. Boerger 2006 */
/*!ignore:re2c
- turning this lesson into an easy calculator
--- /dev/null
+/* Generated by re2c */
+#line 1 "calc_006.s.re"
+/* re2c lesson_001, calc_006, (c) M. Boerger 2006 */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define DEBUG(stmt) stmt
+
+int stack[4];
+int depth = 0;
+
+int push_num(const char *t, const char *l, int radix)
+{
+ int num = 0;
+
+ if (depth >= sizeof(stack))
+ {
+ return 3;
+ }
+
+ --t;
+ while(++t < l)
+ {
+ num = num * radix + (*t - '0');
+ }
+ DEBUG(printf("Num: %d\n", num));
+
+ stack[depth++] = num;
+ return 0;
+}
+
+int stack_add()
+{
+ if (depth < 2) return 4;
+
+ --depth;
+ stack[depth-1] = stack[depth-1] + stack[depth];
+ return 0;
+}
+
+int stack_sub()
+{
+ if (depth < 2) return 4;
+
+ --depth;
+ stack[depth-1] = stack[depth-1] - stack[depth];
+ return 0;
+}
+
+int scan(char *s, int l)
+{
+ char *p = s;
+ char *t;
+ int res = 0;
+
+ #define YYCTYPE char
+ #define YYCURSOR p
+
+ if (l > 1 && s[l-2] == '0' && s[l-1] >= '0' && s[l-1] <= '9') return 2;
+
+ while(!res)
+ {
+ t = p;
+
+#line 68 "<stdout>"
+ {
+ YYCTYPE yych;
+
+ yych = *YYCURSOR;
+ if(yych <= '*') {
+ if(yych <= 0x09) {
+ if(yych <= 0x00) goto yy11;
+ if(yych <= 0x08) goto yy13;
+ } else {
+ if(yych != ' ') goto yy13;
+ }
+ } else {
+ if(yych <= '-') {
+ if(yych <= '+') goto yy7;
+ if(yych <= ',') goto yy13;
+ goto yy9;
+ } else {
+ if(yych <= '/') goto yy13;
+ if(yych <= '0') goto yy4;
+ if(yych <= '9') goto yy6;
+ goto yy13;
+ }
+ }
+ ++YYCURSOR;
+ yych = *YYCURSOR;
+ goto yy21;
+yy3:
+#line 108 "calc_006.s.re"
+ { continue; }
+#line 98 "<stdout>"
+yy4:
+ ++YYCURSOR;
+ if((yych = *YYCURSOR) <= '/') goto yy5;
+ if(yych <= '9') goto yy17;
+yy5:
+#line 110 "calc_006.s.re"
+ { res = push_num(t, p, 10); continue; }
+#line 106 "<stdout>"
+yy6:
+ yych = *++YYCURSOR;
+ goto yy16;
+yy7:
+ ++YYCURSOR;
+#line 111 "calc_006.s.re"
+ { res = stack_add(); continue; }
+#line 114 "<stdout>"
+yy9:
+ ++YYCURSOR;
+#line 112 "calc_006.s.re"
+ { res = stack_sub(); continue; }
+#line 119 "<stdout>"
+yy11:
+ ++YYCURSOR;
+#line 113 "calc_006.s.re"
+ { res = depth == 1 ? 0 : 2; continue; }
+#line 124 "<stdout>"
+yy13:
+ ++YYCURSOR;
+#line 114 "calc_006.s.re"
+ { res = 1; continue; }
+#line 129 "<stdout>"
+yy15:
+ ++YYCURSOR;
+ yych = *YYCURSOR;
+yy16:
+ if(yych <= '/') goto yy5;
+ if(yych <= '9') goto yy15;
+ goto yy5;
+yy17:
+ ++YYCURSOR;
+ yych = *YYCURSOR;
+ if(yych <= '/') goto yy19;
+ if(yych <= '9') goto yy17;
+yy19:
+#line 109 "calc_006.s.re"
+ { res = push_num(t, p, 8); continue; }
+#line 145 "<stdout>"
+yy20:
+ ++YYCURSOR;
+ yych = *YYCURSOR;
+yy21:
+ if(yych == 0x09) goto yy20;
+ if(yych == ' ') goto yy20;
+ goto yy3;
+ }
+#line 115 "calc_006.s.re"
+
+ }
+ return res;
+}
+
+int main(int argc, char **argv)
+{
+ if (argc > 1)
+ {
+ char *inp;
+ int res = 0, argp = 0, len;
+
+ while(!res && ++argp < argc)
+ {
+ inp = argv[argp];
+ len = strlen(inp);
+ if (inp[0] == '\"' && inp[len-1] == '\"')
+ {
+ ++inp;
+ len -=2;
+ }
+ res = scan(inp, len);
+ }
+ switch(res)
+ {
+ case 0:
+ printf("Result: %d\n", stack[0]);
+ return 0;
+ case 1:
+ fprintf(stderr, "Illegal character in input.\n");
+ return 1;
+ case 2:
+ fprintf(stderr, "Premature end of input.\n");
+ return 2;
+ case 3:
+ fprintf(stderr, "Stack overflow.\n");
+ return 3;
+ case 4:
+ fprintf(stderr, "Stack underflow.\n");
+ return 4;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "%s <expr>\n", argv[0]);
+ return 0;
+ }
+}
--- /dev/null
+/* re2c lesson_001, calc_006, (c) M. Boerger 2006 */
+/*!ignore:re2c
+
+- avoiding YYFILL()
+ . We use the inplace configuration re2c:yyfill to suppress generation of
+ YYFILL() blocks. This of course means we no longer have to provide the
+ macro.
+ . We also drop the YYMARKER stuff since we know that re2c does not generate
+ it for this example.
+ . Since re2c does no longer check for out of data situations we must do this.
+ For that reason we first reintroduce our zero rule and second we need to
+ ensure that the scanner does not take more than one bytes in one go.
+
+ In the example suppose "0" is passed. The scanner reads the first "0" and
+ then is in an undecided state. The scanner can earliest decide on the next
+ char what the token is. In case of a zero the input ends and it was a
+ number, 0 to be precise. In case of a didit it is and the next character
+ needs to be read. In case of any other character the scanner has found an
+ error with the any rule [^].
+
+ Now the above shows that re2c may read two characters directly. But only if
+ the first is a "0". So we could easily check that if the first char is "0"
+ another charcter is present.
+
+ if (p[0] == '0' && p[1] == '\0') return 2;
+
+ But instead of doing so in every loop we can optimize by taking into
+ account what we know from our input analysis. That is a problem can only
+ arise when the second last character is a "0" and the last is any digit.
+
+ if (l > 1 && s[l-2] == '0' && s[l-1] >= '0' && s[l-1] <= '9') return 2;
+
+- optimizing the generated code by using -s command line switch of re2c
+ . This tells re2c to generate code that uses if statements rather
+ then endless switch/case expressions where appropriate.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define DEBUG(stmt) stmt
+
+int stack[4];
+int depth = 0;
+
+int push_num(const char *t, const char *l, int radix)
+{
+ int num = 0;
+
+ if (depth >= sizeof(stack))
+ {
+ return 3;
+ }
+
+ --t;
+ while(++t < l)
+ {
+ num = num * radix + (*t - '0');
+ }
+ DEBUG(printf("Num: %d\n", num));
+
+ stack[depth++] = num;
+ return 0;
+}
+
+int stack_add()
+{
+ if (depth < 2) return 4;
+
+ --depth;
+ stack[depth-1] = stack[depth-1] + stack[depth];
+ return 0;
+}
+
+int stack_sub()
+{
+ if (depth < 2) return 4;
+
+ --depth;
+ stack[depth-1] = stack[depth-1] - stack[depth];
+ return 0;
+}
+
+int scan(char *s, int l)
+{
+ char *p = s;
+ char *t;
+ int res = 0;
+
+ #define YYCTYPE char
+ #define YYCURSOR p
+
+ if (l > 1 && s[l-2] == '0' && s[l-1] >= '0' && s[l-1] <= '9') return 2;
+
+ while(!res)
+ {
+ t = p;
+/*!re2c
+ re2c:indent:top = 2;
+ re2c:yyfill:enable = 0;
+
+ DIGIT = [0-9] ;
+ OCT = "0" DIGIT+ ;
+ INT = "0" | ( [1-9] DIGIT* ) ;
+ WS = [ \t]+ ;
+
+ WS { continue; }
+ OCT { res = push_num(t, p, 8); continue; }
+ INT { res = push_num(t, p, 10); continue; }
+ "+" { res = stack_add(); continue; }
+ "-" { res = stack_sub(); continue; }
+ "\000" { res = depth == 1 ? 0 : 2; continue; }
+ [^] { res = 1; continue; }
+*/
+ }
+ return res;
+}
+
+int main(int argc, char **argv)
+{
+ if (argc > 1)
+ {
+ char *inp;
+ int res = 0, argp = 0, len;
+
+ while(!res && ++argp < argc)
+ {
+ inp = argv[argp];
+ len = strlen(inp);
+ if (inp[0] == '\"' && inp[len-1] == '\"')
+ {
+ ++inp;
+ len -=2;
+ }
+ res = scan(inp, len);
+ }
+ switch(res)
+ {
+ case 0:
+ printf("Result: %d\n", stack[0]);
+ return 0;
+ case 1:
+ fprintf(stderr, "Illegal character in input.\n");
+ return 1;
+ case 2:
+ fprintf(stderr, "Premature end of input.\n");
+ return 2;
+ case 3:
+ fprintf(stderr, "Stack overflow.\n");
+ return 3;
+ case 4:
+ fprintf(stderr, "Stack underflow.\n");
+ return 4;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "%s <expr>\n", argv[0]);
+ return 0;
+ }
+}
The input files *.re each contain basic step by comments that explain what is
going on and what you can see in the examples.
+
+In order to optimize the generated code we will use the -s command line switch
+of re2c. This tells re2c to generate code that uses if statements rather
+then endless switch/case expressions where appropriate. Note that the file name
+extension is actually '.s.re' to tell the test system to use the -s switch. To
+invoke re2 you do the following:
+
+ re2c -s -o test.c calc_006.s.re
bool bUsedYYAccept = false;
bool bUseStartLabel= false;
bool bUseStateNext = false;
+bool bUseYYFill = true;
+
std::string startLabelName;
uint maxFill = 1;
uint next_label = 0;
If set to zero then a decimal table is being used else a hexadecimal table
will be generated.
.TP
+\fIre2c:yyfill:enable\fP \fB=\fP 1 \fB;\fP
+Set this to zero to suppress generation of YYFILL(). When using this be sure
+to verify that the generated scanner does not read behind input. Allowing
+this behavior might introduce sever security issues to you programs.
+.TP
\fIre2c:startlabel\fP \fB=\fP 0 \fB;\fP
If set to a non zero integer then the start label of the next scanner blocks
will be generated even if not used by the scanner itself. Otherwise the normal
/* Generated by re2c */
-#line 1 "input13.re"
+#line 1 "config5.re"
// ignored
// code
default: goto yy3;
}
yy3:
-#line 11 "input13.re"
+#line 11 "config5.re"
{ return 0; }
#line 26 "<stdout>"
yy4:
}
yy10:
++YYCURSOR;
-#line 10 "input13.re"
+#line 10 "config5.re"
{ return 1; }
#line 58 "<stdout>"
}
-#line 13 "input13.re"
+#line 13 "config5.re"
// ignored
// max
--- /dev/null
+/* Generated by re2c */
+#line 1 "config6.re"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+int scan(char *s)
+{
+ char *p = s;
+
+ #define YYCTYPE char
+ #define YYCURSOR p
+
+ for(;;)
+ {
+
+#line 18 "<stdout>"
+ {
+ YYCTYPE yych;
+
+ yych = *YYCURSOR;
+ switch(yych){
+ case 0x00: goto yy10;
+ case '+': goto yy6;
+ case '-': goto yy8;
+ case '0': goto yy2;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy4;
+ default: goto yy12;
+ }
+yy2:
+ ++YYCURSOR;
+ switch((yych = *YYCURSOR)) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy16;
+ default: goto yy3;
+ }
+yy3:
+#line 20 "config6.re"
+ { printf("Num\n"); continue; }
+#line 57 "<stdout>"
+yy4:
+ ++YYCURSOR;
+ yych = *YYCURSOR;
+ goto yy15;
+yy5:
+#line 19 "config6.re"
+ { printf("Num\n"); continue; }
+#line 65 "<stdout>"
+yy6:
+ ++YYCURSOR;
+#line 21 "config6.re"
+ { printf("+\n"); continue; }
+#line 70 "<stdout>"
+yy8:
+ ++YYCURSOR;
+#line 22 "config6.re"
+ { printf("-\n"); continue; }
+#line 75 "<stdout>"
+yy10:
+ ++YYCURSOR;
+#line 23 "config6.re"
+ { printf("EOF\n"); return 0; }
+#line 80 "<stdout>"
+yy12:
+ ++YYCURSOR;
+#line 24 "config6.re"
+ { printf("ERR\n"); return 1; }
+#line 85 "<stdout>"
+yy14:
+ ++YYCURSOR;
+ yych = *YYCURSOR;
+yy15:
+ switch(yych){
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy14;
+ default: goto yy5;
+ }
+yy16:
+ ++YYCURSOR;
+ yych = *YYCURSOR;
+ switch(yych){
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy16;
+ default: goto yy18;
+ }
+yy18:
+#line 18 "config6.re"
+ { printf("Oct\n"); continue; }
+#line 122 "<stdout>"
+ }
+#line 25 "config6.re"
+
+ }
+}
+
+int main(int argc, char **argv)
+{
+ if (argc > 1)
+ {
+ return scan(argv[1]);
+ }
+ else
+ {
+ fprintf(stderr, "%s <expr>\n", argv[0]);
+ return 1;
+ }
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+int scan(char *s)
+{
+ char *p = s;
+
+ #define YYCTYPE char
+ #define YYCURSOR p
+
+ for(;;)
+ {
+/*!re2c
+ re2c:indent:top = 2;
+ re2c:yyfill:enable = 0;
+
+ "0"[0-9]+ { printf("Oct\n"); continue; }
+ [1-9][0-9]* { printf("Num\n"); continue; }
+ "0" { printf("Num\n"); continue; }
+ "+" { printf("+\n"); continue; }
+ "-" { printf("-\n"); continue; }
+ "\000" { printf("EOF\n"); return 0; }
+ [^] { printf("ERR\n"); return 1; }
+*/
+ }
+}
+
+int main(int argc, char **argv)
+{
+ if (argc > 1)
+ {
+ return scan(argv[1]);
+ }
+ else
+ {
+ fprintf(stderr, "%s <expr>\n", argv[0]);
+ return 1;
+ }
+}