Back to index

lightning-sunbird  0.9+nobinonly
morkParser.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-  */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #ifndef _MORKPARSER_
00039 #define _MORKPARSER_ 1
00040 
00041 #ifndef _MORK_
00042 #include "mork.h"
00043 #endif
00044 
00045 #ifndef _MORKBLOB_
00046 #include "morkBlob.h"
00047 #endif
00048 
00049 #ifndef _MORKSINK_
00050 #include "morkSink.h"
00051 #endif
00052 
00053 #ifndef _MORKYARN_
00054 #include "morkYarn.h"
00055 #endif
00056 
00057 #ifndef _MORKCELL_
00058 #include "morkCell.h"
00059 #endif
00060 
00061 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00062  
00063 /*=============================================================================
00064  * morkPlace: stream byte position and stream line count
00065  */
00066 
00067 class morkPlace {
00068 public:
00069   mork_pos   mPlace_Pos;   // byte offset in an input stream
00070   mork_line  mPlace_Line;  // line count in an input stream
00071   
00072   void ClearPlace()
00073   {
00074     mPlace_Pos = 0; mPlace_Line = 0;
00075   }
00076 
00077   void SetPlace(mork_pos inPos, mork_line inLine)
00078   {
00079     mPlace_Pos = inPos; mPlace_Line = inLine;
00080   }
00081 
00082   morkPlace() { mPlace_Pos = 0; mPlace_Line = 0; }
00083   
00084   morkPlace(mork_pos inPos, mork_line inLine)
00085   { mPlace_Pos = inPos; mPlace_Line = inLine; }
00086   
00087   morkPlace(const morkPlace& inPlace)
00088   : mPlace_Pos(inPlace.mPlace_Pos), mPlace_Line(inPlace.mPlace_Line) { }
00089 };
00090 
00091 /*=============================================================================
00092  * morkGlitch: stream place and error comment describing a parsing error
00093  */
00094 
00095 class morkGlitch {
00096 public:
00097   morkPlace    mGlitch_Place;   // place in stream where problem happened
00098   const char*  mGlitch_Comment; // null-terminated ASCII C string
00099 
00100   morkGlitch() { mGlitch_Comment = 0; }
00101   
00102   morkGlitch(const morkPlace& inPlace, const char* inComment)
00103   : mGlitch_Place(inPlace), mGlitch_Comment(inComment) { }
00104 };
00105 
00106 /*=============================================================================
00107  * morkMid: all possible ways needed to express an alias ID in Mork syntax
00108  */
00109 
00110 /*| morkMid: an abstraction of all the variations we might need to support
00111 **| in order to present an ID through the parser interface most cheaply and
00112 **| with minimum transformation away from the original text format.
00113 **|
00114 **|| An ID can have one of four forms:
00115 **| 1) idHex            (mMid_Oid.mOid_Id <- idHex)
00116 **| 2) idHex:^scopeHex  (mMid_Oid.mOid_Id <- idHex, mOid_Scope <- scopeHex)
00117 **| 3) idHex:scopeName  (mMid_Oid.mOid_Id <- idHex, mMid_Buf <- scopeName)
00118 **| 4) columnName       (mMid_Buf <- columnName, for columns in cells only)
00119 **|
00120 **|| Typically, mMid_Oid.mOid_Id will hold a nonzero integer value for
00121 **| an ID, but we might have an optional scope specified by either an integer
00122 **| in hex format, or a string name.  (Note that while the first ID can be
00123 **| scoped variably, any integer ID for a scope is assumed always located in
00124 **| the same scope, so the second ID need not be disambiguated.)
00125 **|
00126 **|| The only time mMid_Oid.mOid_Id is ever zero is when mMid_Buf alone
00127 **| is nonzero, to indicate an explicit string instead of an alias appeared.
00128 **| This case happens to make the representation of columns in cells somewhat
00129 **| easier to represent, since columns can just appear as a string name; and
00130 **| this unifies those interfaces with row and table APIs expecting IDs.
00131 **|
00132 **|| So when the parser passes an instance of morkMid to a subclass, the 
00133 **| mMid_Oid.mOid_Id slot should usually be nonzero.  And the other two
00134 **| slots, mMid_Oid.mOid_Scope and mMid_Buf, might both be zero, or at
00135 **| most one of them will be nonzero to indicate an explicit scope; the
00136 **| parser is responsible for ensuring at most one of these is nonzero.
00137 |*/
00138 class morkMid {
00139 public:
00140   mdbOid          mMid_Oid;  // mOid_Scope is zero when not specified
00141   const morkBuf*  mMid_Buf;  // points to some specific buf subclass
00142   
00143   morkMid()
00144   { mMid_Oid.mOid_Scope = 0; mMid_Oid.mOid_Id = morkId_kMinusOne;
00145    mMid_Buf = 0; }
00146   
00147   void InitMidWithCoil(morkCoil* ioCoil)
00148   { mMid_Oid.mOid_Scope = 0; mMid_Oid.mOid_Id = morkId_kMinusOne;
00149    mMid_Buf = ioCoil; }
00150     
00151   void ClearMid()
00152   { mMid_Oid.mOid_Scope = 0; mMid_Oid.mOid_Id = morkId_kMinusOne;
00153    mMid_Buf = 0; }
00154 
00155   morkMid(const morkMid& other)
00156   : mMid_Oid(other.mMid_Oid), mMid_Buf(other.mMid_Buf) { }
00157   
00158   mork_bool HasNoId() const // ID is unspecified?
00159   { return ( mMid_Oid.mOid_Id == morkId_kMinusOne ); }
00160   
00161   mork_bool HasSomeId() const // ID is specified?
00162   { return ( mMid_Oid.mOid_Id != morkId_kMinusOne ); }
00163 };
00164 
00165 /*=============================================================================
00166  * morkSpan: start and end stream byte position and stream line count
00167  */
00168 
00169 class morkSpan {
00170 public:
00171   morkPlace   mSpan_Start;
00172   morkPlace   mSpan_End;
00173 
00174 public: // methods
00175   
00176 public: // inlines
00177   morkSpan() { } // use inline empty constructor for each place
00178   
00179   morkPlace* AsPlace() { return &mSpan_Start; }
00180   const morkPlace* AsConstPlace() const { return &mSpan_Start; }
00181   
00182   void SetSpan(mork_pos inFromPos, mork_line inFromLine,
00183     mork_pos inToPos, mork_line inToLine)
00184   {
00185     mSpan_Start.SetPlace(inFromPos, inFromLine);
00186     mSpan_End.SetPlace(inToPos,inToLine);
00187   }
00188 
00189   // setting end, useful to terminate a span using current port span end:
00190   void SetEndWithEnd(const morkSpan& inSpan) // end <- span.end
00191   { mSpan_End = inSpan.mSpan_End; }
00192 
00193   // setting start, useful to initiate a span using current port span end:
00194   void SetStartWithEnd(const morkSpan& inSpan) // start <- span.end
00195   { mSpan_Start = inSpan.mSpan_End; }
00196   
00197   void ClearSpan()
00198   {
00199     mSpan_Start.mPlace_Pos = 0; mSpan_Start.mPlace_Line = 0;
00200     mSpan_End.mPlace_Pos = 0; mSpan_End.mPlace_Line = 0;
00201   }
00202 
00203   morkSpan(mork_pos inFromPos, mork_line inFromLine,
00204     mork_pos inToPos, mork_line inToLine)
00205   : mSpan_Start(inFromPos, inFromLine), mSpan_End(inToPos, inToLine)
00206   {  /* empty implementation */ }
00207 };
00208 
00209 /*=============================================================================
00210  * morkParser: for parsing Mork text syntax
00211  */
00212 
00213 #define morkParser_kMinGranularity 512 /* parse at least half 0.5K at once */
00214 #define morkParser_kMaxGranularity (64 * 1024) /* parse at most 64 K at once */
00215 
00216 #define morkDerived_kParser     /*i*/ 0x5073 /* ascii 'Ps' */
00217 #define morkParser_kTag     /*i*/ 0x70417253 /* ascii 'pArS' */
00218 
00219 // These are states for the simple parsing virtual machine.  Needless to say,
00220 // these must be distinct, and preferrably in a contiguous integer range.
00221 // Don't change these constants without looking at switch statements in code.
00222 #define morkParser_kCellState      0 /* cell is tightest scope */
00223 #define morkParser_kMetaState      1 /* meta is tightest scope */
00224 #define morkParser_kRowState       2 /* row is tightest scope */
00225 #define morkParser_kTableState     3 /* table is tightest scope */
00226 #define morkParser_kDictState      4 /* dict is tightest scope */
00227 #define morkParser_kPortState      5 /* port is tightest scope */
00228 
00229 #define morkParser_kStartState     6 /* parsing has not yet begun */
00230 #define morkParser_kDoneState      7 /* parsing is complete */
00231 #define morkParser_kBrokenState    8 /* parsing is to broken to work */
00232 
00233 class morkParser /*d*/ : public morkNode {
00234 
00235 // public: // slots inherited from morkNode (meant to inform only)
00236   // nsIMdbHeap*       mNode_Heap;
00237 
00238   // mork_base      mNode_Base;     // must equal morkBase_kNode
00239   // mork_derived   mNode_Derived;  // depends on specific node subclass
00240   
00241   // mork_access    mNode_Access;   // kOpen, kClosing, kShut, or kDead
00242   // mork_usage     mNode_Usage;    // kHeap, kStack, kMember, kGlobal, kNone
00243   // mork_able      mNode_Mutable;  // can this node be modified?
00244   // mork_load      mNode_Load;     // is this node clean or dirty?
00245   
00246   // mork_uses      mNode_Uses;     // refcount for strong refs
00247   // mork_refs      mNode_Refs;     // refcount for strong refs + weak refs
00248 
00249 // ````` ````` ````` `````   ````` ````` ````` `````  
00250 protected: // protected morkParser members
00251   
00252   nsIMdbHeap*   mParser_Heap;   // refcounted heap used for allocation
00253   morkStream*   mParser_Stream; // refcounted input stream
00254 
00255   mork_u4       mParser_Tag; // must equal morkParser_kTag
00256   mork_count    mParser_MoreGranularity; // constructor inBytesPerParseSegment
00257 
00258   mork_u4       mParser_State; // state where parser should resume
00259 
00260   // after finding ends of group transactions, we can re-seek the start:
00261   mork_pos      mParser_GroupContentStartPos; // start of this group
00262 
00263   morkMid       mParser_TableMid; // table mid if inside a table
00264   morkMid       mParser_RowMid;   // row mid if inside a row
00265   morkMid       mParser_CellMid;  // cell mid if inside a row
00266   mork_gid      mParser_GroupId;  // group ID if inside a group
00267 
00268   mork_bool     mParser_InPort;  // called OnNewPort but not OnPortEnd?
00269   mork_bool     mParser_InDict;  // called OnNewDict but not OnDictEnd?
00270   mork_bool     mParser_InCell;  // called OnNewCell but not OnCellEnd?
00271   mork_bool     mParser_InMeta;  // called OnNewMeta but not OnMetaEnd?
00272 
00273   mork_bool     mParser_InPortRow;  // called OnNewPortRow but not OnPortRowEnd?
00274   mork_bool     mParser_InRow;    // called OnNewRow but not OnNewRowEnd?
00275   mork_bool     mParser_InTable;  // called OnNewMeta but not OnMetaEnd?
00276   mork_bool     mParser_InGroup;  // called OnNewGroup but not OnGroupEnd?
00277 
00278   mork_change   mParser_AtomChange;  // driven by mParser_Change 
00279   mork_change   mParser_CellChange;  // driven by mParser_Change 
00280   mork_change   mParser_RowChange;   // driven by mParser_Change 
00281   mork_change   mParser_TableChange; // driven by mParser_Change 
00282 
00283   mork_change   mParser_Change;     // driven by modifier in text 
00284   mork_bool     mParser_IsBroken;   // has the parse become broken?
00285   mork_bool     mParser_IsDone;     // has the parse finished?
00286   mork_bool     mParser_DoMore;     // mParser_MoreGranularity not exhausted? 
00287 
00288   morkMid       mParser_Mid;   // current alias being parsed
00289   // note that mParser_Mid.mMid_Buf points at mParser_ScopeCoil below:
00290 
00291   // blob coils allocated in mParser_Heap
00292   morkCoil     mParser_ScopeCoil;   // place to accumulate ID scope blobs
00293   morkCoil     mParser_ValueCoil;   // place to accumulate value blobs
00294   morkCoil     mParser_ColumnCoil;  // place to accumulate column blobs
00295   morkCoil     mParser_StringCoil;  // place to accumulate string blobs
00296 
00297   morkSpool    mParser_ScopeSpool;  // writes to mParser_ScopeCoil
00298   morkSpool    mParser_ValueSpool;  // writes to mParser_ValueCoil
00299   morkSpool    mParser_ColumnSpool; // writes to mParser_ColumnCoil
00300   morkSpool    mParser_StringSpool; // writes to mParser_StringCoil
00301 
00302   // yarns allocated in mParser_Heap
00303   morkYarn      mParser_MidYarn;   // place to receive from MidToYarn()
00304 
00305   // span showing current ongoing file position status:
00306   morkSpan      mParser_PortSpan; // span of current db port file
00307 
00308   // various spans denoting nested subspaces inside the file's port span:
00309   morkSpan      mParser_GroupSpan; // span of current transaction group
00310   morkSpan      mParser_DictSpan;
00311   morkSpan      mParser_AliasSpan;
00312   morkSpan      mParser_MetaSpan;
00313   morkSpan      mParser_TableSpan;
00314   morkSpan      mParser_RowSpan;
00315   morkSpan      mParser_CellSpan;
00316   morkSpan      mParser_ColumnSpan;
00317   morkSpan      mParser_SlotSpan;
00318 
00319 private: // convenience inlines
00320 
00321   mork_pos HerePos() const
00322   { return mParser_PortSpan.mSpan_End.mPlace_Pos; }
00323 
00324   void SetHerePos(mork_pos inPos)
00325   { mParser_PortSpan.mSpan_End.mPlace_Pos = inPos; }
00326 
00327   void CountLineBreak()
00328   { ++mParser_PortSpan.mSpan_End.mPlace_Line; }
00329   
00330 // { ===== begin morkNode interface =====
00331 public: // morkNode virtual methods
00332   virtual void CloseMorkNode(morkEnv* ev); // CloseParser() only if open
00333   virtual ~morkParser(); // assert that CloseParser() executed earlier
00334   
00335 public: // morkYarn construction & destruction
00336   morkParser(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
00337     morkStream* ioStream,  // the readonly stream for input bytes
00338     mdb_count inBytesPerParseSegment, // target for ParseMore()
00339     nsIMdbHeap* ioSlotHeap);
00340       
00341   void CloseParser(morkEnv* ev); // called by CloseMorkNode();
00342 
00343 private: // copying is not allowed
00344   morkParser(const morkParser& other);
00345   morkParser& operator=(const morkParser& other);
00346 
00347 public: // dynamic type identification
00348   mork_bool IsParser() const
00349   { return IsNode() && mNode_Derived == morkDerived_kParser; }
00350   
00351 // } ===== end morkNode methods =====
00352 
00353 public: // errors and warnings
00354   static void UnexpectedEofError(morkEnv* ev);
00355   static void EofInsteadOfHexError(morkEnv* ev);
00356   static void ExpectedEqualError(morkEnv* ev);
00357   static void ExpectedHexDigitError(morkEnv* ev, int c);
00358   static void NonParserTypeError(morkEnv* ev);
00359   static void UnexpectedByteInMetaWarning(morkEnv* ev);
00360 
00361 public: // other type methods
00362   mork_bool GoodParserTag() const { return mParser_Tag == morkParser_kTag; }
00363   void NonGoodParserError(morkEnv* ev);
00364   void NonUsableParserError(morkEnv* ev);
00365   // call when IsNode() or GoodParserTag() is false
00366   
00367 // ````` ````` ````` `````   ````` ````` ````` `````  
00368 public: // in virtual morkParser methods, data flow subclass to parser
00369 
00370     virtual void MidToYarn(morkEnv* ev,
00371       const morkMid& inMid,  // typically an alias to concat with strings
00372       mdbYarn* outYarn) = 0;
00373     // The parser might ask that some aliases be turned into yarns, so they
00374     // can be concatenated into longer blobs under some circumstances.  This
00375     // is an alternative to using a long and complex callback for many parts
00376     // for a single cell value.
00377   
00378 // ````` ````` ````` `````   ````` ````` ````` `````  
00379 public: // out virtual morkParser methods, data flow parser to subclass
00380 
00381 // The virtual methods below will be called in a pattern corresponding
00382 // to the following grammar isomorphic to the Mork grammar.  There should
00383 // be no exceptions, so subclasses can rely on seeing an appropriate "end"
00384 // method whenever some "new" method has been seen earlier.  In the event
00385 // that some error occurs that causes content to be flushed, or sudden early
00386 // termination of a larger containing entity, we will always call a more
00387 // enclosed "end" method before we call an "end" method with greater scope.
00388 
00389 // Note the "mp" prefix stands for "Mork Parser":
00390 
00391 // mp:Start     ::= OnNewPort mp:PortItem* OnPortEnd
00392 // mp:PortItem  ::= mp:Content | mp:Group | OnPortGlitch
00393 // mp:Group     ::= OnNewGroup mp:GroupItem* mp:GroupEnd
00394 // mp:GroupItem ::= mp:Content | OnGroupGlitch
00395 // mp:GroupEnd  ::= OnGroupCommitEnd | OnGroupAbortEnd
00396 // mp:Content   ::= mp:PortRow | mp:Dict | mp:Table | mp:Row
00397 // mp:PortRow   ::= OnNewPortRow mp:RowItem* OnPortRowEnd
00398 // mp:Dict      ::= OnNewDict mp:DictItem* OnDictEnd
00399 // mp:DictItem  ::= OnAlias | OnAliasGlitch | mp:Meta | OnDictGlitch
00400 // mp:Table     ::= OnNewTable mp:TableItem* OnTableEnd
00401 // mp:TableItem ::= mp:Row | mp:MetaTable | OnTableGlitch
00402 // mp:MetaTable ::= OnNewMeta mp:MetaItem* mp:Row OnMetaEnd
00403 // mp:Meta      ::= OnNewMeta mp:MetaItem* OnMetaEnd
00404 // mp:MetaItem  ::= mp:Cell | OnMetaGlitch
00405 // mp:Row       ::= OnMinusRow? OnNewRow mp:RowItem* OnRowEnd
00406 // mp:RowItem   ::= mp:Cell | mp:Meta | OnRowGlitch
00407 // mp:Cell      ::= OnMinusCell? OnNewCell mp:CellItem? OnCellEnd
00408 // mp:CellItem  ::= mp:Slot | OnCellForm | OnCellGlitch
00409 // mp:Slot      ::= OnValue | OnValueMid | OnRowMid | OnTableMid
00410 
00411 
00412   // Note that in interfaces below, mork_change parameters kAdd and kNil
00413   // both mean about the same thing by default.  Only kCut is interesting,
00414   // because this usually means to remove members instead of adding them.
00415 
00416   virtual void OnNewPort(morkEnv* ev, const morkPlace& inPlace) = 0;
00417   virtual void OnPortGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;  
00418   virtual void OnPortEnd(morkEnv* ev, const morkSpan& inSpan) = 0;  
00419 
00420   virtual void OnNewGroup(morkEnv* ev, const morkPlace& inPlace, mork_gid inGid) = 0;
00421   virtual void OnGroupGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;  
00422   virtual void OnGroupCommitEnd(morkEnv* ev, const morkSpan& inSpan) = 0;  
00423   virtual void OnGroupAbortEnd(morkEnv* ev, const morkSpan& inSpan) = 0;  
00424 
00425   virtual void OnNewPortRow(morkEnv* ev, const morkPlace& inPlace, 
00426     const morkMid& inMid, mork_change inChange) = 0;
00427   virtual void OnPortRowGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;  
00428   virtual void OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan) = 0;  
00429 
00430   virtual void OnNewTable(morkEnv* ev, const morkPlace& inPlace,
00431     const morkMid& inMid, mork_bool inCutAllRows) = 0;
00432   virtual void OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
00433   virtual void OnTableEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
00434     
00435   virtual void OnNewMeta(morkEnv* ev, const morkPlace& inPlace) = 0;
00436   virtual void OnMetaGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
00437   virtual void OnMetaEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
00438 
00439   virtual void OnMinusRow(morkEnv* ev) = 0;
00440   virtual void OnNewRow(morkEnv* ev, const morkPlace& inPlace, 
00441     const morkMid& inMid, mork_bool inCutAllCols) = 0;
00442   virtual void OnRowPos(morkEnv* ev, mork_pos inRowPos) = 0;  
00443   virtual void OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;  
00444   virtual void OnRowEnd(morkEnv* ev, const morkSpan& inSpan) = 0;  
00445 
00446   virtual void OnNewDict(morkEnv* ev, const morkPlace& inPlace) = 0;
00447   virtual void OnDictGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;  
00448   virtual void OnDictEnd(morkEnv* ev, const morkSpan& inSpan) = 0;  
00449 
00450   virtual void OnAlias(morkEnv* ev, const morkSpan& inSpan,
00451     const morkMid& inMid) = 0;
00452 
00453   virtual void OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
00454 
00455   virtual void OnMinusCell(morkEnv* ev) = 0;
00456   virtual void OnNewCell(morkEnv* ev, const morkPlace& inPlace,
00457     const morkMid* inMid, const morkBuf* inBuf) = 0;
00458   // Exactly one of inMid and inBuf is nil, and the other is non-nil.
00459   // When hex ID syntax is used for a column, then inMid is not nil, and
00460   // when a naked string names a column, then inBuf is not nil.
00461     
00462   virtual void OnCellGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
00463   virtual void OnCellForm(morkEnv* ev, mork_cscode inCharsetFormat) = 0;
00464   virtual void OnCellEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
00465     
00466   virtual void OnValue(morkEnv* ev, const morkSpan& inSpan,
00467     const morkBuf& inBuf) = 0;
00468 
00469   virtual void OnValueMid(morkEnv* ev, const morkSpan& inSpan,
00470     const morkMid& inMid) = 0;
00471 
00472   virtual void OnRowMid(morkEnv* ev, const morkSpan& inSpan,
00473     const morkMid& inMid) = 0;
00474 
00475   virtual void OnTableMid(morkEnv* ev, const morkSpan& inSpan,
00476     const morkMid& inMid) = 0;
00477   
00478 // ````` ````` ````` `````   ````` ````` ````` `````  
00479 protected: // protected parser helper methods
00480 
00481   void ParseLoop(morkEnv* ev); // find parse continuation and resume
00482 
00483   void StartParse(morkEnv* ev); // prepare for parsing
00484   void StopParse(morkEnv* ev); // terminate parsing & call needed methods
00485 
00486   int NextChar(morkEnv* ev); // next non-white content
00487 
00488   void OnCellState(morkEnv* ev);
00489   void OnMetaState(morkEnv* ev);
00490   void OnRowState(morkEnv* ev);
00491   void OnTableState(morkEnv* ev);
00492   void OnDictState(morkEnv* ev);
00493   void OnPortState(morkEnv* ev);
00494   void OnStartState(morkEnv* ev);
00495   
00496   void ReadCell(morkEnv* ev);
00497   void ReadRow(morkEnv* ev, int c);
00498   void ReadRowPos(morkEnv* ev);
00499   void ReadTable(morkEnv* ev);
00500   void ReadTableMeta(morkEnv* ev);
00501   void ReadDict(morkEnv* ev);
00502   mork_bool ReadContent(morkEnv* ev, mork_bool inInsideGroup);
00503   void ReadGroup(morkEnv* ev);
00504   mork_bool ReadEndGroupId(morkEnv* ev);
00505   mork_bool ReadAt(morkEnv* ev, mork_bool inInsideGroup);
00506   mork_bool FindGroupEnd(morkEnv* ev);
00507   void ReadMeta(morkEnv* ev, int inEndMeta);
00508   void ReadAlias(morkEnv* ev);
00509   mork_id ReadHex(morkEnv* ev, int* outNextChar);
00510   morkBuf* ReadValue(morkEnv* ev);
00511   morkBuf* ReadName(morkEnv* ev, int c);
00512   mork_bool ReadMid(morkEnv* ev, morkMid* outMid);
00513   void ReadDictForm(morkEnv *ev);
00514   void ReadCellForm(morkEnv *ev, int c);
00515   
00516   mork_bool MatchPattern(morkEnv* ev, const char* inPattern);
00517   
00518   void EndSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan);
00519   void EndSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan);
00520   void StartSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan);
00521   
00522   void StartSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan);
00523   
00524   
00525   // void EndSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan)
00526   // { MORK_USED_2(ev,ioSpan); }
00527   
00528   // void EndSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan)
00529   // { MORK_USED_2(ev,ioSpan); }
00530   
00531   // void StartSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan)
00532   // { MORK_USED_2(ev,ioSpan); }
00533   
00534   // void StartSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan)
00535   // { MORK_USED_2(ev,ioSpan); }
00536   
00537   int eat_line_break(morkEnv* ev, int inLast);
00538   int eat_line_continue(morkEnv* ev); // last char was '\\'
00539   int eat_comment(morkEnv* ev); // last char was '/'
00540   
00541 // ````` ````` ````` `````   ````` ````` ````` `````  
00542 public: // public non-poly morkParser methods
00543     
00544   mdb_count ParseMore( // return count of bytes consumed now
00545     morkEnv* ev,          // context
00546     mork_pos* outPos,     // current byte pos in the stream afterwards
00547     mork_bool* outDone,   // is parsing finished?
00548     mork_bool* outBroken  // is parsing irreparably dead and broken?
00549   );
00550   
00551   
00552 public: // typesafe refcounting inlines calling inherited morkNode methods
00553   static void SlotWeakParser(morkParser* me,
00554     morkEnv* ev, morkParser** ioSlot)
00555   { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
00556   
00557   static void SlotStrongParser(morkParser* me,
00558     morkEnv* ev, morkParser** ioSlot)
00559   { morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
00560 };
00561 
00562 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00563 
00564 #endif /* _MORKPARSER_ */
00565