Canola  0.8.D001
lib/lexer/source.cc
Go to the documentation of this file.
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 }