Canola  0.8.D001
test_number_z/lex.cc
Go to the documentation of this file.
00001 //
00002 // canola - canon canola 1614p emulator
00003 // Copyright (C) 2012 Peter Miller
00004 //
00005 // This program is free software; you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License, version 3, as
00007 // published by the Free Software Foundation.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License along
00015 // with this program. If not, see <http://www.gnu.org/licenses/>.
00016 //
00017 
00018 #include <lib/ac/stdio.h>
00019 #include <libexplain/getchar.h>
00020 #include <libexplain/output.h>
00021 #include <libexplain/ungetc.h>
00022 
00023 #include <lib/number/z.h>
00024 
00025 #include <test_number_z/lex.h>
00026 #include <test_number_z/grammar.yacc.h>
00027 
00028 
00029 static int number_of_errors;
00030 static int line_number = 1;
00031 static bool prev_was_eoln;
00032 
00033 
00034 void
00035 lex_end(void)
00036 {
00037     if (number_of_errors > 0)
00038     {
00039         explain_output_error_and_die
00040         (
00041             "found %d error%s",
00042             number_of_errors,
00043             (number_of_errors == 1 ? "" : "s")
00044         );
00045     }
00046 }
00047 
00048 
00049 static bool
00050 have(char c)
00051 {
00052     int t = explain_getchar_or_die();
00053     if (t == EOF)
00054         return false;
00055     if (t != c)
00056     {
00057         ungetc(t, stdin);
00058         return false;
00059     }
00060     return true;
00061 }
00062 
00063 
00064 int
00065 grammar_lex(void)
00066 {
00067     if (prev_was_eoln)
00068         ++line_number;
00069     for (;;)
00070     {
00071         int c = explain_getchar_or_die();
00072         switch (c)
00073         {
00074         case EOF:
00075             return 0;
00076 
00077         case '\t':
00078             break;
00079 
00080         case '\n':
00081             prev_was_eoln = true;
00082             return EOLN;
00083 
00084         case ' ':
00085             break;
00086 
00087         case '!':
00088             if (have('='))
00089                 return NE;
00090             return JUNK;
00091 
00092         case '%':
00093             return MOD;
00094 
00095         case '(':
00096             return LP;
00097 
00098         case ')':
00099             return RP;
00100 
00101         case '*':
00102             return MUL;
00103 
00104         case '+':
00105             return PLUS;
00106 
00107         case '-':
00108             return MINUS;
00109 
00110         case '/':
00111             return DIV;
00112 
00113         case '0': case '1': case '2': case '3': case '4':
00114         case '5': case '6': case '7': case '8': case '9':
00115             {
00116                 number_z n;
00117                 for (;;)
00118                 {
00119                     n.build(c - '0');
00120 
00121                     c = explain_getchar_or_die();
00122                     switch (c)
00123                     {
00124                     case EOF:
00125                         break;
00126 
00127                     case '0': case '1': case '2': case '3': case '4':
00128                     case '5': case '6': case '7': case '8': case '9':
00129                         continue;
00130 
00131                     default:
00132                         explain_ungetc_or_die(c, stdin);
00133                         break;
00134                     }
00135                     break;
00136                 }
00137                 grammar_lval.lv_number = new number_z(n);
00138             }
00139             return NUMBER;
00140 
00141         case '<':
00142             if (have('='))
00143                 return LE;
00144             return LT;
00145 
00146         case '=':
00147             if (have('='))
00148                 return EQ;
00149             return JUNK;
00150 
00151         case '>':
00152             if (have('='))
00153                 return GE;
00154             return GT;
00155 
00156         default:
00157             return JUNK;
00158         }
00159     }
00160 }
00161 
00162 
00163 void
00164 grammar_error(const char *text)
00165 {
00166     explain_output_error("%d: %s", line_number, text);
00167     ++number_of_errors;
00168 }
00169 
00170 
00171 
00172 // vim: set ts=8 sw=4 et :