📄 elexcompiler.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 ®exp = 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 + -