Canola
0.8.D001
|
00001 // 00002 // canola - canon canola 1614p emulator 00003 // Copyright (C) 2011, 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.h> 00024 00025 #include <test_number/lex.h> 00026 #include <test_number/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 return true; 00057 explain_ungetc_or_die(t, stdin); 00058 return false; 00059 } 00060 00061 00062 int 00063 grammar_lex(void) 00064 { 00065 if (prev_was_eoln) 00066 ++line_number; 00067 for (;;) 00068 { 00069 int c = explain_getchar_or_die(); 00070 switch (c) 00071 { 00072 case EOF: 00073 return 0; 00074 00075 case '\t': 00076 break; 00077 00078 case '\n': 00079 prev_was_eoln = true; 00080 return EOLN; 00081 00082 case ' ': 00083 break; 00084 00085 case '!': 00086 if (have('=')) 00087 return NE; 00088 return JUNK; 00089 00090 case '(': 00091 return LP; 00092 00093 case ')': 00094 return RP; 00095 00096 case '*': 00097 return MUL; 00098 00099 case '+': 00100 return PLUS; 00101 00102 case ',': 00103 return COMMA; 00104 00105 case '-': 00106 return MINUS; 00107 00108 case '/': 00109 return DIV; 00110 00111 case '0': case '1': case '2': case '3': case '4': 00112 case '5': case '6': case '7': case '8': case '9': 00113 { 00114 number n; 00115 bool dotted = false; 00116 for (;;) 00117 { 00118 if (dotted) 00119 n.insert_digit_after_dot(c - '0'); 00120 else 00121 n.insert_digit_before_dot(c - '0'); 00122 get_more: 00123 c = explain_getchar_or_die(); 00124 switch (c) 00125 { 00126 case EOF: 00127 break; 00128 00129 case '.': 00130 dotted = true; 00131 n.insert_dot(); 00132 goto get_more; 00133 00134 case '0': case '1': case '2': case '3': case '4': 00135 case '5': case '6': case '7': case '8': case '9': 00136 continue; 00137 00138 default: 00139 explain_ungetc_or_die(c, stdin); 00140 break; 00141 } 00142 break; 00143 } 00144 grammar_lval.lv_number = new number(n); 00145 } 00146 return NUMBER; 00147 00148 case '<': 00149 if (have('=')) 00150 return LE; 00151 return LT; 00152 00153 case '=': 00154 if (have('=')) 00155 return EQ; 00156 return JUNK; 00157 00158 case '>': 00159 if (have('=')) 00160 return GE; 00161 return GT; 00162 00163 case '_': 00164 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 00165 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': 00166 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': 00167 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': 00168 case 'Y': case 'Z': 00169 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 00170 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': 00171 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': 00172 case 's': case 't': case 'u': case 'v': case 'w': case 'x': 00173 case 'y': case 'z': 00174 { 00175 std::string name; 00176 for (;;) 00177 { 00178 name += (char)c; 00179 00180 c = explain_getchar_or_die(); 00181 switch (c) 00182 { 00183 case EOF: 00184 break; 00185 00186 case '0': case '1': case '2': case '3': case '4': 00187 case '5': case '6': case '7': case '8': case '9': 00188 case '_': 00189 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 00190 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': 00191 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': 00192 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': 00193 case 'Y': case 'Z': 00194 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 00195 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': 00196 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': 00197 case 's': case 't': case 'u': case 'v': case 'w': case 'x': 00198 case 'y': case 'z': 00199 continue; 00200 00201 default: 00202 explain_ungetc_or_die(c, stdin); 00203 break; 00204 } 00205 break; 00206 } 00207 if (name == "sqrt") 00208 return SQRT; 00209 if (name == "round_down") 00210 return FLOOR; 00211 } 00212 return JUNK; 00213 00214 default: 00215 return JUNK; 00216 } 00217 } 00218 } 00219 00220 00221 void 00222 grammar_error(const char *text) 00223 { 00224 explain_output_error("%d: %s", line_number, text); 00225 ++number_of_errors; 00226 } 00227 00228 00229 // vim: set ts=8 sw=4 et :