Canola
0.8.D001
|
00001 // 00002 // canola - canon canola 1614p emulator 00003 // Copyright (C) 2011 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/config.h> 00019 #include <libexplain/fopen.h> 00020 #include <libexplain/fclose.h> 00021 #include <libexplain/getc.h> 00022 00023 #include <lib/calculator.h> 00024 #include <lib/lexer.h> 00025 #include <lib/std_string_printf.h> 00026 00027 00028 lexer::source::~source() 00029 { 00030 close(); 00031 } 00032 00033 00034 lexer::source::source(const std::string &a_filename, calculator &a_subject) : 00035 filename(a_filename), 00036 subject(a_subject), 00037 fp(0), 00038 line_number(1), 00039 prev_was_newline(false), 00040 position(0) 00041 { 00042 std::string fn = lexer::include_search_path.find(filename); 00043 fp = fopen(fn.c_str(), "r"); 00044 if (!fp) 00045 subject.on_error("%s", explain_fopen(fn.c_str(), "r")); 00046 00047 // Use the actual file name for error messages, and also opcode locations. 00048 filename = fn; 00049 } 00050 00051 00052 lexer::source::pointer 00053 lexer::source::create(const std::string &a_filename, calculator &a_subject) 00054 { 00055 return pointer(new source(a_filename, a_subject)); 00056 } 00057 00058 00059 void 00060 lexer::source::close(void) 00061 { 00062 if (fp) 00063 { 00064 if (fclose(fp)) 00065 subject.on_error("%s", explain_fclose(fp)); 00066 fp = 0; 00067 } 00068 } 00069 00070 00071 int 00072 lexer::source::getch(void) 00073 { 00074 if (prev_was_newline) 00075 { 00076 ++line_number; 00077 prev_was_newline = false; 00078 } 00079 if (!pushback.empty()) 00080 { 00081 int c = pushback.back(); 00082 pushback.pop_back(); 00083 ++position; 00084 prev_was_newline = (c == '\n'); 00085 return c; 00086 } 00087 if (!fp) 00088 return EOF; 00089 int c = getc(fp); 00090 if (c == EOF) 00091 { 00092 if (ferror(fp)) 00093 subject.on_error("%s", explain_getc(fp)); 00094 close(); 00095 } 00096 else 00097 ++position; 00098 prev_was_newline = (c == '\n'); 00099 return c; 00100 } 00101 00102 00103 void 00104 lexer::source::ungetch(int c) 00105 { 00106 if (c == '\n') 00107 prev_was_newline = false; 00108 if (c != EOF) 00109 { 00110 pushback.push_back(c); 00111 --position; 00112 assert(position >= 0); 00113 } 00114 } 00115 00116 00117 void 00118 lexer::source::set_line_number(int n) 00119 { 00120 assert(n > 0); 00121 line_number = n; 00122 } 00123 00124 00125 void 00126 lexer::source::error(const char *fmt, ...) 00127 { 00128 va_list ap; 00129 va_start(ap, fmt); 00130 error_v(fmt, ap); 00131 va_end(ap); 00132 } 00133 00134 00135 void 00136 lexer::source::error_v(const char *fmt, va_list ap) 00137 { 00138 std::string text = std_string_printf_v(fmt, ap); 00139 subject.on_error("%s: %d: %s", filename.c_str(), line_number, text.c_str()); 00140 close(); 00141 } 00142 00143 00144 location::pointer 00145 lexer::source::get_location(void) 00146 const 00147 { 00148 assert(position >= 0); 00149 return location::create(filename, line_number, position, 0); 00150 }