⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 elexcompiler.cpp

📁 用于词法分析的词法分析器
💻 CPP
字号:
/*  $Id: ElexCompiler.cpp,v 1.12 1997/05/18 10:57:56 matt Exp $  Elex compiler class.    (c) Matt Phillips, Sep 17th.  */#include <strstream.h>#include "ElexCompiler.h"#include "ElexScanner.h"#define ArraySize(a) (sizeof (a) / sizeof (*(a)))ElexCompiler::ElexCompiler (BufferedInputStream &i, ostream &co) :  codeOut (co), scanner (i, errors){  scanner.getNext ();  // cue scanner     parseScannerDef ();     if (nErrors () == 0)  {    scannerDef.fsm.clearEpsilonCycles ();    scannerDef.fsm.clearEpsilon ();    scannerDef.fsm.resolve ();    scannerDef.fsm.optimize ();  }}void ElexCompiler::parseSymbols (){  while (scanner.getSymbol () == ElexScanner::SymIdent)  {    // store token name    string token (scanner.getText ());    scannerDef.tokens.add (token);    scanner.getNext ();  } }void ElexCompiler::parseDefines (){  while (scanner.getSymbol () == ElexScanner::SymIdent)  {    // store symbol name    string symbol (scanner.getText ());    scanner.getNext ();    mustbe (ElexScanner::SymEquals);    if (scanner.getSymbol () == ElexScanner::SymString)    {      // store regexp      Fsm *fsm = parseRegexp ();      if (fsm)	symbols.add (symbol, *fsm);      scanner.getNext ();    } else      mustbeError (ElexScanner::SymString);  }    }void ElexCompiler::parseDeclarations (){  for (;;)  {    if (have (ElexScanner::SymSymbols))    {      parseSymbols ();    } else if (have (ElexScanner::SymDefines))    {      parseDefines ();    } else      break;  }}Fsm *ElexCompiler::parseRegexp (){  const string &regexp = scanner.getText ();  istrstream stream (regexp.data (), regexp.length ());  BufferedInputStream istr (stream);  istr.line = scanner.getSymbolLine ();  istr.col = scanner.getSymbolColumn () + 1;  istr.filename = scanner.getInput ().filename;     RegexpCompiler regComp (istr, scannerDef.prodNo, symbols);  int regErrs = regComp.nErrors ();  // merge errors/warnings  regComp.getErrors ().mergeWith (errors);    if (regErrs > 0)  {    return 0;  } else  {    Fsm *fsm = new Fsm;    regComp.getFsm ().mergeWith (*fsm);    return fsm;  }}void ElexCompiler::outputCodeFrag (){  InputStream &str = scanner.getInput ();  int spaces = 0;  // output language (if any)  while (!isspace (str.peek ()) && !str.eof ())  {    codeOut << (char)str.peek ();    str.get ();  }  codeOut << endl;  // skip past \n  for (; str.peek () != '\n' && !str.eof (); str.get ());  str.get ();  for ( ; !str.eof (); str.get ()) // return's inside loop  {    switch (str.peek ())    {    case ' ':      spaces++;      break;    case '\t':      spaces += (8 - str.getColumn () % 8);      break;    case '>':      str.get ();      return;    default:      codeOut << '>';      // print any buffered spaces/tabs      for (int c = 0; c < spaces; c++)      {	codeOut << ' ';      }      spaces = 0;	       // output the rest of the line      while (str.peek () != '\n')      {	codeOut << char (str.peek ());	str.get ();      }      codeOut << endl;    }  }  warning ("unterminated code fragment");}void ElexCompiler::parseCodeFrags (){  codeOut << "*\n";  while (scanner.getSymbol () == ElexScanner::SymLessThan)  {    outputCodeFrag ();    scanner.getNext ();  }}void ElexCompiler::parseProduction (){  if (scanner.getSymbol () == ElexScanner::SymIdent)  {    string ident (scanner.getText ());    scanner.getNext ();    if (scanner.getSymbol () == ElexScanner::SymString)    {	scannerDef.productions.addTail (ident);	parseRegexProduction (ident);    } else if (scanner.getSymbol () == ElexScanner::SymLessThan)    {      // an event production      scannerDef.productions.addTail (ident);      parseCodeFrags ();    } else      error ("regular expression or code fragment expected here");  } else if (scanner.getSymbol () == ElexScanner::SymString)  {    // the production name is a the string version of its number    ostrstream str;    str << scannerDef.prodNo << '\0';    string prodName (str.str ());    scannerDef.productions.addTail (prodName);    delete str.str ();    parseRegexProduction (prodName);  } else  {    error ("identifier or regular expression expected here");  }}void ElexCompiler::parseRegexProduction (const string &prodName){  Fsm *fsm = parseRegexp ();  // merge FSM with the total FSM  if (fsm)  {    scannerDef.fsm.head ().addEdge (fsm->head ());    fsm->mergeWith (scannerDef.fsm);  }  delete fsm;  scanner.getNext ();  parseCodeFrags ();}  void ElexCompiler::parseProductions (){  // maybe a warning if current symbol is not an 'on'?  while (have (ElexScanner::SymOn))  {    parseProduction ();    scannerDef.prodNo++;  }}void ElexCompiler::parseScannerDef (){  scannerDef.fsm.addState ();  // handle initial frags  parseCodeFrags ();  mustbe (ElexScanner::SymScanner);  if (scanner.getSymbol () == ElexScanner::SymIdent)  {    // store scanner name    scannerDef.name = scanner.getText ();    scanner.getNext ();  } else    error ("scanner name required");  if (have (ElexScanner::SymColon))  {    if (scanner.getSymbol () == ElexScanner::SymIdent)    {      // store base class name      scannerDef.base = scanner.getText ();      scanner.getNext ();    } else      error ("base class name required");  }  parseDeclarations ();  mustbe (ElexScanner::SymBegin);     parseProductions ();  mustbe (ElexScanner::SymEnd);}void ElexCompiler::mustbeError (int sym){  static char *errStrs [] =  {    "scanner keyword expected", /*token*/0,    /*define*/0, "missing 'begin'", "missing 'end'", /*on*/0,    /*event*/0, /*comma*/0, "missing '='", /*colon*/"missing ':'",    "identifier expected", "code fragment expected",    "regular expression expected"  };  if (sym == ElexScanner::SymEOF)    error ("end of file expected");  else  {    CHECK (sym >= 0 && sym < ArraySize (errStrs),	 "mustbeError symbol out of range");    error (errStrs [sym]);  }}int ElexCompiler::mustbe (int sym){  if (scanner.getSymbol () != sym)  {    mustbeError (sym);    return 0;  } else  {    scanner.getNext ();    return 1;  }}int ElexCompiler::have (int sym){  if (scanner.getSymbol () != sym)    return 0;  else  {    scanner.getNext ();    return 1;  }}void ElexCompiler::error (const char *msg){  errors.error (string (msg),		scanner.getInput ().getFilename (),		scanner.getSymbolLine (),		scanner.getSymbolColumn ());}void ElexCompiler::warning (const char *msg){  errors.warning (string (msg),		  scanner.getInput ().getFilename (),		  scanner.getSymbolLine (),		  scanner.getSymbolColumn ());}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -