gpreproc.cc
来自「Gambit 是一个游戏库理论软件」· CC 代码 · 共 447 行
CC
447 行
//// $Source: /home/gambit/CVS/gambit/sources/gcl/gpreproc.cc,v $// $Date: 2002/08/27 18:57:17 $// $Revision: 1.3 $//// DESCRIPTION:// Implementation of class to preprocess GCL input//// This file is part of Gambit// Copyright (c) 2002, The Gambit Project//// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.//#include <ctype.h>#include "gpreproc.h"#include "base/system.h"#include "gsm.h"//-------------------------------------------------------------------------// gPreprocessor: private auxiliary member functions//-------------------------------------------------------------------------bool gPreprocessor::ExpectText(const char *p_text){ int length = strlen(p_text); char c; if (m_InputStack.Peek()->eof()) return false; for (int i = 0; i < length; i++) { GetChar(c); if (m_InputStack.Peek()->eof() || c != p_text[i]) return false; } return true;}//// Note: filename might be changed after this call//gInput *gPreprocessor::LoadInput(gText &p_name){ gInput *infile = NULL; extern char *_SourceDir; const char *SOURCE = _SourceDir; const char SLASH = System::Slash(); bool search = (strchr((char *) p_name, SLASH) == NULL); gText IniFileName = p_name; gList<gText> paths; paths.Append(p_name); if (search) { if (System::GetEnv("HOME") != NULL) paths.Append(System::Slashify(((gText) System::GetEnv("HOME") + (gText) SLASH + (gText) p_name))); if (System::GetEnv("GCLLIB") != NULL) paths.Append(System::Slashify(((gText) System::GetEnv("GCLLIB") + (gText) SLASH + (gText) p_name))); if (SOURCE != NULL) paths.Append(System::Slashify((gText) SOURCE + (gText) SLASH + (gText) p_name)); } for (int i = 1; i <= paths.Length(); i++) { try { infile = new gFileInput(paths[i]); p_name = paths[i]; return infile; } // This #ifdef is here because under AIX with g++ 2.8.1, this // catch handler is causing a coredump.#ifdef _AIX catch (...) {#else catch (gFileInput::OpenFailed &) {#endif // _AIX } } return 0;}void gPreprocessor::SetPrompt(bool p_prompt){ if (m_InputStack.Peek() == m_CmdLine) m_CmdLine->SetPrompt(p_prompt); }void gPreprocessor::GetChar(char &p_char){ // Input is sought first from any open Include[] files // (in particular, gclini.gcl and other command-line arguments); // then from any unexecuted parts of the initString; // finally, from the GCL::CommandLine object ("standard input") if (m_InputStack.Depth() > 1 && !m_InputStack.Peek()->eof()) { if (m_InputStack.Peek()->getpos() == 0L) { m_environment.OutputStream() << "GCL: Reading file \""; m_environment.OutputStream() << m_FileNameStack.Peek(); m_environment.OutputStream() << "\".\n"; } m_InputStack.Peek()->get(p_char); if (EOL(p_char)) { ++m_LineNumberStack.Peek(); } } else if (m_StartupString.Length() > 0) { p_char = m_StartupString[0u]; m_StartupString = m_StartupString.Right(m_StartupString.Length() - 1); } else { m_InputStack.Peek()->get(p_char); if (EOL(p_char)) ++m_LineNumberStack.Peek(); } // This is a bit of a hack to eliminate spurious error messages at the // end of include files. if (!isprint(p_char) && !isspace(p_char)) { p_char = '\n'; } m_RawLine += p_char;}bool gPreprocessor::IsQuoteEscapeSequence(const gText &p_line) const{ bool backslash = false; char c = p_line[p_line.Length() - 1]; if (c == '\"') { // if there's an odd number of consecutive backslashes, // then it's an escape sequence unsigned int i = 2; while (p_line.Length() >= i && p_line[p_line.Length() - i] == '\\') { backslash = !backslash; i++; } } return backslash;}gPreprocessor::gPreprocessor(GSM &p_environment, GCL::CommandLine *p_cmdline, const char *p_cmd /* = NULL */) : m_environment(p_environment), m_CmdLine(p_cmdline), m_PrevFileName("console"), m_PrevLineNumber(1), m_StartupString(p_cmd){ m_InputStack.Push(m_CmdLine); m_FileNameStack.Push(m_PrevFileName); m_LineNumberStack.Push(m_PrevLineNumber); if (p_cmd && !EOL(m_StartupString[m_StartupString.Length() - 1])) m_StartupString += '\n';}gPreprocessor::~gPreprocessor(){ while (m_InputStack.Depth() > 1) delete m_InputStack.Pop();}//-------------------------------------------------------------------// GetLine// Does the main pre-processing job.//// This function handles the following://// o Include[] statements. If the file exists, it is included, and the// Include[] function call is replaced with "True". If the file is// not found or there is a syntax error, it is replaced with "False".// // o Strips all comments. The comment types processed are C and C++ // style comments.// // o Filter out explicit continuations, i.e., a backslash at the end // of the line. Only works if the backslash is the last character// on the line; trailing spaces are not accepted.//// o Handle implicit continuations (bracket matching)// If brackets are open at a carriage return, then the CR is// replaced with a space.//--------------------------------------------------------------------- gText gPreprocessor::GetLine(void){ m_RawLine = ""; // If no more input available, return nothing. if (m_StartupString.Length() == 0 && eof()) { return ""; } // Record the current file name and line number. m_PrevFileName = m_FileNameStack.Peek(); m_PrevLineNumber = m_LineNumberStack.Peek(); // This is initialized to work with the explicit continuation // processing code. The backslask will be stripped. gText line = '\\'; gText errorMsg; char c = 0; bool quote = false; bool error = false; int bracket = 0; bool continuation = false; while (line.Right(1) == '\\' && !error) { // Strip the trailing backslash line = line.Left(line.Length() - 1); while (m_StartupString.Length () > 0 || !m_InputStack.Peek()->eof()) { GetChar(c); if (m_StartupString.Length() > 0 || !m_InputStack.Peek()->eof()) { // Ignore CR or replace with space as appropriate. if (!EOL(c)) line += c; else { if (line.Right(1) == '\\') { break; } else if (bracket > 0) { line += '\n'; } else { line += '\n'; break; } } if (c == '[') { // Turn off prompts until the bracket is matched. if (bracket == 0) SetPrompt(false); ++bracket; } else if (c == ']') { // If brackets are matched, turn prompt back on. --bracket; if (bracket == 0) SetPrompt(true); if (bracket < 0) bracket = 0; } else if (c == '\"') { // In the middle of a string; accept everything // until the closing quote mark is found. SetPrompt(false); quote = !quote; while ((!m_InputStack.Peek()->eof() || m_StartupString.Length() > 0) && quote) { GetChar(c); line += c; if (c == '\"' && !IsQuoteEscapeSequence(line)) quote = !quote; } SetPrompt(true); } if (line.Right(2) == "//") { // In a line comment. Ignore everything until // end of line. line = line.Left(line.Length() - 2); while ((!m_InputStack.Peek()->eof() || m_StartupString.Length() > 0) && !EOL(c)) GetChar(c); line += '\n'; } else if (line.Right(2) == "/*") { // In a C style comment. Ignore everything until // comment closing is found. line = line.Left(line.Length() - 2); SetPrompt(false); gText comment = " "; while ((!m_InputStack.Peek()->eof() || m_StartupString.Length() > 0) && (comment.Right(2) != "*/" || quote)) { GetChar(c); comment += c; if (c == '\"') { bool escapeSeq = false; if (quote) escapeSeq = IsQuoteEscapeSequence(comment); if (!escapeSeq) quote = !quote; } } SetPrompt(true); } // // Handle Include[] directives // else if (line.Right(7) == "Include") { line = line.Left(line.Length() - 7); c = ' '; while ((!m_InputStack.Peek()->eof() || m_StartupString.Length() > 0) && c == ' ') GetChar(c); if (c != '[') { line += "False;"; errorMsg = "Include[] syntax error; opening '[' not found"; error = true; break; } c = ' '; while ((!m_InputStack.Peek()->eof() || m_StartupString.Length() > 0) && c == ' ') GetChar(c); if (c != '\"') { line += "False;"; errorMsg = "Include[] syntax error; opening '\"' not found"; error = true; break; } gText filename; c = ' '; while ((!m_InputStack.Peek()->eof() || m_StartupString.Length() > 0) && c != '\"' && !EOL(c)) { GetChar(c); if (c != '\"') filename += c; } if (EOL(c)) { line += "False;"; errorMsg = "Include[] syntax error; closing '\"' not found"; error = true; break; } c = ' '; while ((!m_InputStack.Peek()->eof() || m_StartupString.Length() > 0) && c == ' ') GetChar(c); if (c != ']') { line += "False;"; errorMsg = "Include[] syntax error; closing ']' not found"; error = true; break; } // bring in the rest of this line gText restOfLine; c = ' '; while ((!m_InputStack.Peek()->eof() || m_StartupString.Length () > 0) && !EOL(c)) { GetChar(c); restOfLine += c; } // note: filename might be changed after this call gInput *input = LoadInput(filename); if (input) { line += "True;"; m_InputStack.Push(input); m_FileNameStack.Push(filename); m_LineNumberStack.Push(1); } else { line += "False;"; m_environment.ErrorStream() << "GCL Warning: Include file \"" << filename; m_environment.ErrorStream() << "\" not found.\n"; } line += restOfLine; break; } // "Include" // // Handle GetPath directive // else if (line.Right(9) == "GetPath[]") { line = line.Left(line.Length() - 9); line += gText('"') + GetFileName() + gText('"'); } } } // This outer loop deals with explicit line continuation characters if (line.Right( 1 ) == '\\') { if (!continuation) SetPrompt(false); continuation = true; } } if (continuation) SetPrompt(true); if (error) { m_environment.ErrorStream() << "GCL Error: " << errorMsg << '\n'; } if (m_InputStack.Peek()->eof()) { if (m_InputStack.Depth() > 1) { delete m_InputStack.Pop(); } else m_InputStack.Pop(); m_FileNameStack.Pop(); m_LineNumberStack.Pop(); } return line;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?