Canola
0.8.D001
|
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 :