📄 inpbuf.cc
字号:
////////////////////////////////////////////////////////////////////////////////// inpbuf.cc//#include <string>#include "inpbuf.h"#include "scanner.h"#include <iomanip>#define MAX_ERRORS 30// Maximum number of errors before aborting compile. More than that and the// compiler is probably lost#define TAB_WIDTH 8struct input_buffer_t { int line_num; // Line number of text. input_buffer_t * next; // Next line. input_buffer_t * prev; // Previous line. string buf; // The (corrected) text of the line. unsigned int pointer; // Index of the next character to read. bool modified; // Were there any syntax corrections? string origBuf; // Original before syntax corrections. string messages; // Any error messages.};bool scanner_peeking = false;bool compile_ok = true;static input_buffer_t * first_line;// This is the root of the buffered source program.static input_buffer_t * current_line;// Current_line is one from which we return characters to the scanner.static int syntax_error_cnt = 0;static int insertion_cnt = 0;static int deletion_cnt = 0;static int semantic_error_cnt = 0;static int warning_cnt = 0;static bool compiler_dying = false;// Catch recursive calls to die_compiler.////////////////////////////////////////////////////////////////////////////////// Initialization and finalization functions.//////////// Initialize the input buffer module.//void init_input_buffer(void){ // fake a zero-th line that will be replaced immediately current_line = new input_buffer_t; first_line = current_line; current_line->buf = "\n"; current_line->origBuf = "\n"; current_line->next = NULL; current_line->prev = NULL; current_line->pointer = 1; current_line->line_num = 0; current_line->modified = false; current_line->messages = "";}////////// Print out all accumulated lines. Lines containing a syntax error are// printed first in their original form, then as modified, with a leading// '-S---------------- ', length-adjusted to come up to just before the// first non-blank character of the line.//static void flush_lines(void){ for (input_buffer_t *temp_line = first_line; temp_line != NULL ; temp_line = temp_line->next) { if (temp_line->modified || temp_line->messages.length() != 0) { if (temp_line->modified) { cout << setw(6) << temp_line->line_num << " " << temp_line->origBuf; // origBuf has its own trailing linefeed cout << "-S-----"; if (temp_line->buf[0] == '\n' || temp_line->buf[0] == ' ') cout << "-"; else cout << " "; unsigned int i; for (i = 0; temp_line->buf.length() >= i+1 && temp_line->buf[i] == ' ' && temp_line->buf[i+1] == ' '; i++) { cout << "-"; } cout << temp_line->buf.substr(i, temp_line->buf.length()); } else cout << setw(6) << temp_line->line_num << ": " << temp_line->buf; } //if modified or messages cout << temp_line->messages; }}////////// Print any error messages, and statistics about the compile.//void finalize_input_buffer(void){ flush_lines(); cout << "COMPLETED\n"; cout << " " << setw(4) << current_line->line_num << " line"; if (current_line->line_num != 1) cout << "s"; cout << " in program\n"; cout << " " << setw(4) << syntax_error_cnt << " syntax error"; if (syntax_error_cnt != 1) cout << "s"; cout << "\n"; cout << " " << setw(4) << insertion_cnt << " insertion"; if (insertion_cnt != 1) cout << "s"; cout << "\n"; cout << " " << setw(4) << deletion_cnt << " deletion"; if (deletion_cnt != 1) cout << "s"; cout << "\n"; cout << " " << setw(4) << semantic_error_cnt << " semantic error"; if (semantic_error_cnt != 1) cout << "s"; cout << "\n"; cout << " " << setw(4) << warning_cnt << " warning"; if (warning_cnt != 1) cout << "s"; cout << "\n";}////////////////////////////////////////////////////////////////////////////////// Interface to scanner.//////////// Read in one character from the buffer.//// If necessary, read one line of input, or move to next line if// one is buffered.// Convert tabs to spaces.//// Put '\n' at end of line.// Put FILE_END in first column of extra last line.//// Die if asked to return characters after end of file.//char read_char(void){ if (current_line->buf.length() == current_line->pointer) { assert(current_line->buf[0] != FILE_END); // can't return characters after end of file if (current_line->next != NULL) { current_line = current_line->next; } else { char temp[512]; char * sp; char * ep; unsigned int pos; char c; current_line->next = new input_buffer_t; current_line->next->line_num = current_line->line_num + 1; current_line->next->prev = current_line; current_line = current_line->next; strcpy(temp, ""); ep = temp + sizeof(temp) - 1; for (sp = temp, pos = 0; pos < sizeof(temp) - 2;) { if (cin.eof()) { *sp++ = FILE_END; *sp++ = '\n'; break; //leave for loop } cin.get(c); if (c == EOF) { *sp++ = FILE_END; *sp++ = '\n'; break; } if (c == '\n') { *sp++ = '\n'; break; } if (c == '\t') { for (int i = TAB_WIDTH - pos % TAB_WIDTH; i-- > 0; pos++) *sp++ = ' '; } else { *sp++ = c; pos++; } } *sp = '\0'; current_line->origBuf = current_line->buf = temp; current_line->pointer = 0; current_line->modified = false; current_line->next = NULL; current_line->messages = ""; } } return current_line->buf[current_line->pointer++];}////////// Try to put characters back into input stream.//void unread_chars(unsigned int how_many){ while (current_line->pointer < how_many) { how_many -= current_line->pointer; current_line->pointer = 0; assert((int) current_line->prev); // don't attempt to back up past beginning of program current_line = current_line->prev; } current_line->pointer -= how_many;}////////// Return location of character most recently read from the source program.// Scanner calls this after reading first character of new token.// We don't call it *before* reading first character of new token, because// we don't know what line that first character will be on until the scanner// has read and accepted it.//location_t get_source_location(void){ location_t l; l.line = current_line; l.column = current_line->pointer-1; return l;}////////////////////////////////////////////////////////////////////////////////// Interface to syntax error corrector.//static location_t old_location;// Point at which we should resume scanning when the corrector is done////////// Parser has discovered a syntax error the corrector will be looking ahead.// Save context, at first character of bad token (passed in).// ASSUME bad token began on this line.//void prepare_to_correct(location_t where){ old_location = where; scanner_peeking = true; syntax_error_cnt++;}////////// Corrector is looking ahead. Restore saved context. Leave the// scanner_peeking flag on until unwanted tokens have been deleted with// calls to scan.//void done_peeking(void){ current_line = old_location.line; current_line->pointer = old_location.column; for (input_buffer_t *t = current_line->next; t != NULL; t = t->next) { // Reset pointers in all peeked-at lines. t->pointer = 0; }}////////// Show that how_many tokens have been deleted. Leave pointer at first// character after the deletion. Current_line points to the current line.// The parser calls display_deletions before display_insertion.//void display_deletions(int how_many){ major_token_t dum_id; token_attrib_t dum_attrs; current_line->modified = true; deletion_cnt += how_many; for (int i = 0; i < how_many; i++) { // move past how_many tokens dum_id = token_get(dum_attrs); current_line->modified = true; dum_attrs.location.line->buf.erase(dum_attrs.location.column, dum_attrs.location.line->pointer - dum_attrs.location.column); } // Next char will be first AFTER deletions.}////////// Show that token has been inserted. Put it before current_line^.pointer.// Leave the pointer pointing after the change. This code is really// inefficient, but that's ok.//void display_insertion(string insertion){ insertion += ' '; current_line->buf.insert(current_line->pointer, insertion); current_line->modified = true; insertion_cnt = insertion_cnt + 1; current_line->pointer += insertion.length(); // Next char will be first after insertions.}////////// Corrector is done inserting and deleting tokens, return to normal state.//void done_correcting(void){ scanner_peeking = false;}////////////////////////////////////////////////////////////////////////////////// Manage listing and error messages.//////////// Utility routine called by both issue_error and issue_warning.// Marks the source line and adds the message msg. The mark looks like:// '-X------------------^', where the X is markChar and the caret appears// at the location specified by loc.//static void issue_message(string msg, char markChar, location_t loc){ string temp; temp = "-"; temp += markChar; for (int i = 0; i < 6 + loc.column; i++) temp += '-'; temp += "^\n"; loc.line->messages += temp; loc.line->messages += " "; loc.line->messages += msg; loc.line->messages += "\n";}////////// Issue non fatal error message and stop code generation.//void issue_error(location_t loc, string msg){ compile_ok = false; if (++semantic_error_cnt > MAX_ERRORS) die_compiler("Too many errors. Compilation aborted."); issue_message(msg, 'E', loc);}////////// Issue warning message.//void issue_warning(location_t loc, string msg){ warning_cnt++; issue_message(msg, 'W', loc);}////////// Halt the program..//void halt(void){ cout << "* Program halted!\n" << flush; exit(1999);}////////// Print fatal error message and kill the compiler.//void die_compiler(string msg) // NEED TO FIX CAST BELOW WHEN MOVING TO STANDARD STRINGS{ if (compiler_dying) { cout << "Recursive call to procedure \"die_compiler\".\n"; halt(); } compiler_dying = true; flush_lines(); cout << msg << "\n"; halt();}////////// Extract information from an input_buffer_t.//string get_line_info (const input_buffer_t *line, input_buffer_t *&next, int& line_num){ next = line->next; line_num = line->line_num; return line->origBuf;}////////// Returns the line number of this location_t.//int location_t::get_lineno(void) const{ return line->line_num;}////////// Returns the column number of this location_t.//int location_t::get_column(void) const{ return column;}// End of File
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -