]> granicus.if.org Git - re2c/commitdiff
- Fixed -i switch.
authorhelly <helly@642ea486-5414-0410-9d7f-a0204ed87703>
Sat, 15 Apr 2006 18:44:20 +0000 (18:44 +0000)
committerhelly <helly@642ea486-5414-0410-9d7f-a0204ed87703>
Sat, 15 Apr 2006 18:44:20 +0000 (18:44 +0000)
- Added configuration 'yyfill:enable' to allow suppression of YYFILL()
  blocks.

16 files changed:
CHANGELOG
code.cc
globals.h
htdocs/index.html
htdocs/manual.html
lessons/001_upn_calculator/calc_005.c
lessons/001_upn_calculator/calc_005.re
lessons/001_upn_calculator/calc_006.s.c [new file with mode: 0755]
lessons/001_upn_calculator/calc_006.s.re [new file with mode: 0755]
lessons/001_upn_calculator/readme.txt
main.cc
re2c.1.in
test/config5.c [moved from test/input13.c with 90% similarity]
test/config5.re [moved from test/input13.re with 100% similarity]
test/config6.c [new file with mode: 0755]
test/config6.re [new file with mode: 0755]

index a01a7355e54e590f9f3ec4cbfae3968e97943fc0..6852abfae7482e3b0cbb8c8dfb946f9528c0790c 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,7 @@
-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).
diff --git a/code.cc b/code.cc
index 382c38975a331b0d3b0481629bd49d590ac86e1b..ec826ac826e6902f41e9937808fd7c77c7587557 100644 (file)
--- a/code.cc
+++ b/code.cc
@@ -301,13 +301,16 @@ static void need(std::ostream &o, uint ind, uint n, bool & readCh, bool bSetMark
                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)
@@ -1461,7 +1464,7 @@ void genGetState(std::ostream &o, uint& ind, uint start_label)
 
 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";
        }
@@ -1500,6 +1503,10 @@ void Scanner::config(const Str& cfg, int num)
        {
                bUseStateNext = num != 0;
        }
+       else if (cfg.to_string() == "yyfill:enable")
+       {
+               bUseYYFill = num != 0;
+       }
        else
        {
                fatal("unrecognized configuration name or illegal integer value");
index 59103965369b35ef0f8c1410348e4373ea691f71..7ca838298aa7f2788b5744f81dff02d14158f6bf 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -35,6 +35,7 @@ extern bool yybmHexTable;
 extern bool bUseStateAbort;
 extern bool bUseStateNext;
 extern bool bWroteGetState;
+extern bool bUseYYFill;
 
 extern uint asc2ebc[256];
 extern uint ebc2asc[256];
index cb6388974f7287c73510b96148deb092418831da..ca954398e65b7aff1a232390b82edd6c7b00debd 100755 (executable)
@@ -76,8 +76,10 @@ provide re2c packages.</li>
 </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>
index b500083ba8f1589e7cac1533256fe4e001b1739c..63cf977f58ca45b8537b1647e2a074e066c846de 100755 (executable)
@@ -343,6 +343,10 @@ not want any indendation at all you can simply set this to <b>""</b>.</dd>
 <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
index 827e75f112abdc4fcef47b564a725a575a808364..9c4f624e7732534506a0a01212f6cb3e4a45aedd 100755 (executable)
@@ -1,6 +1,6 @@
 /* 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>
index 20e8bcb228bbc51be8cc4259eb54d4a076c8708d..9e3c50b4e8032200a2970761c100af9215785302 100755 (executable)
@@ -1,4 +1,4 @@
-/* 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
diff --git a/lessons/001_upn_calculator/calc_006.s.c b/lessons/001_upn_calculator/calc_006.s.c
new file mode 100755 (executable)
index 0000000..8caece7
--- /dev/null
@@ -0,0 +1,201 @@
+/* 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;
+       }
+}
diff --git a/lessons/001_upn_calculator/calc_006.s.re b/lessons/001_upn_calculator/calc_006.s.re
new file mode 100755 (executable)
index 0000000..8e16b25
--- /dev/null
@@ -0,0 +1,162 @@
+/* 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;
+       }
+}
index 99057629845e5c98240b51da5a45ad123e81c22e..565946565ec61ef255036e9338436b723338da1f 100755 (executable)
@@ -25,3 +25,11 @@ followed by the output filename:
 
 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
diff --git a/main.cc b/main.cc
index 25d2ee7b03c409629ecd990fc1769aa3d6142a29..7a2c5a1836586b4791d4a466a8e7af3360e206cd 100644 (file)
--- a/main.cc
+++ b/main.cc
@@ -32,6 +32,8 @@ bool wFlag = false;
 bool bUsedYYAccept = false;
 bool bUseStartLabel= false;
 bool bUseStateNext = false;
+bool bUseYYFill    = true;
+
 std::string startLabelName;
 uint maxFill = 1;
 uint next_label = 0;
index 900f9cc31265cd4fc5dd3a3abdfc320390acabe0..0bf833f5d275422fdebb3929169c868064352416 100644 (file)
--- a/re2c.1.in
+++ b/re2c.1.in
@@ -403,6 +403,11 @@ not want any indendation at all you can simply set this to \fB""\fP.
 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 
similarity index 90%
rename from test/input13.c
rename to test/config5.c
index 081a2812dc6e6acf3c278b6499d8e320f1f1c246..6305bde7ea7a33733cfcf95b9b04e0c57736c581 100755 (executable)
@@ -1,5 +1,5 @@
 /* Generated by re2c */
-#line 1 "input13.re"
+#line 1 "config5.re"
 // ignored
 // code
 
@@ -20,7 +20,7 @@ yy2:
        default:        goto yy3;
        }
 yy3:
-#line 11 "input13.re"
+#line 11 "config5.re"
        { return 0; }
 #line 26 "<stdout>"
 yy4:
@@ -52,11 +52,11 @@ yy9:
        }
 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
similarity index 100%
rename from test/input13.re
rename to test/config5.re
diff --git a/test/config6.c b/test/config6.c
new file mode 100755 (executable)
index 0000000..b1f8074
--- /dev/null
@@ -0,0 +1,139 @@
+/* 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;
+       }
+}
diff --git a/test/config6.re b/test/config6.re
new file mode 100755 (executable)
index 0000000..0dd3728
--- /dev/null
@@ -0,0 +1,40 @@
+#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;
+       }
+}