2024-05-04 20:21:50 +03:00
unit GOLDParserEngine;
2015-05-14 22:35:07 +03:00
2024-05-04 20:21:50 +03:00
{$zerobasedstrings on}
2015-05-14 22:35:07 +03:00
//----------------------------------------------------------------------
// Gold Parser engine for PascalABC.NET, v0.1
// Project site http://pascalabc.net/
// See more details on http://www.devincook.com/goldparser/
//
// Original code is written in VB by Devin Cook (GOLDParser@DevinCook.com)
//
// This translation is done by Tkachuk Aleksander (darkstarta@mail.ru)
//
// The translation is based on the other engine translations:
// C# engine by Vladimir Morozov (vmoroz@hotmail.com)
// Delphi engine by Alexandre Rai (riccio@gmx.at)
// C# engine by Marcus Klimstra (klimstra@home.nl)
//----------------------------------------------------------------------
interface
uses System,
System. Text ,
System. IO;
const
//SymbolType enum
SymbolTypeNonTerminal = 0 ;
SymbolTypeTerminal = 1 ;
SymbolTypeWhiteSpace = 2 ;
SymbolTypeEnd = 3 ;
SymbolTypeCommentStart= 4 ;
SymbolTypeCommentEnd = 5 ;
SymbolTypeCommentLine = 6 ;
SymbolTypeError = 7 ;
//LRAction enum
LRActionNone = 0 ;
LRActionShift = 1 ;
LRActionReduce = 2 ;
LRActionGoto = 3 ;
LRActionAccept = 4 ;
LRActionError = 5 ;
//const in ObjectMap
MAXINDEX = 2 5 5 ;
GROWTH = 3 2 ;
MINSIZE = 3 2 ;
MAXARRAYCOUNT = 1 2 ;
INVALIDKEY = MaxInt;
//ParseMessage enum
ParseMessageEmpty = 0 ;
ParseMessageTokenRead = 1 ;
ParseMessageReduction = 2 ;
ParseMessageAccept = 3 ;
ParseMessageNotLoadedError = 4 ;
ParseMessageLexicalError = 5 ;
ParseMessageSyntaxError = 6 ;
ParseMessageCommentError = 7 ;
ParseMessageInternalError = 8 ;
ParseMessageCommentBlockRead = 9 ;
ParseMessageCommentLineRead = 1 0 ;
//enum RecordType
RecordTypeParameters = 8 0 ; //'P'
RecordTypeTableCounts = 8 4 ; //'T'
RecordTypeInitial = 7 3 ; //'I'
RecordTypeSymbols = 8 3 ; //'S'
RecordTypeCharSets = 6 7 ; //'C'
RecordTypeRules = 8 2 ; //'R'
RecordTypeDfaStates = 6 8 ; //'D'
RecordTypeLRStates = 7 6 ; //'L'
RecordTypeComment = 3 3 ; //'!'
//enum EntryType
EntryTypeEmpty = 6 9 ; //'E'
EntryTypeInteger = 7 3 ; //'I'
EntryTypeString = 8 3 ; //'S'
EntryTypeBoolean = 6 6 ; //'B'
EntryTypeByte = 9 8 ; //'b'
//enum TokenParseResult
TokenParseResultEmpty = 0 ;
TokenParseResultAccept = 1 ;
TokenParseResultShift = 2 ;
TokenParseResultReduceNormal = 3 ;
TokenParseResultReduceEliminated = 4 ;
TokenParseResultSyntaxError = 5 ;
TokenParseResultInternalError = 6 ;
charEnter = #13 ;
charReset = #10 ;
charTab = #9 ;
charEndOfFile = #0 ;
type
ParseMessage = integer ;
TokenParseResult = integer ;
Symbol = class
Index : integer ; // symbol index in symbol table
Name : string ; // name of the symbol
SymbolType: integer ; // type of the symbol
m_text: string ; // printable representation of symbol
m_quotedChars: string ;
public
constructor( index : integer ; name : string ; symType: integer ) ;
function IsQuotedChar( value: char ) : boolean ;
function FormatTerminalSymbol( source: string ) : string ;
function ToString: string ; override ;
end ;
Entry = record //internal in ObjectMap
Key: integer ;
Value: object ;
end ;
MapProvider = class
m_count: integer ;
constructor ; begin end ;
function GetIndex( key: integer ) : object ; virtual ;
property Index [ i: integer ] : object read GetIndex; default ;
function GetEntry( key: integer ) : Entry; virtual ;
procedure Add( key: integer ; value: object ) ; virtual ;
procedure Remove( key: integer ) ; virtual ;
end ;
SortedMapProvider = class( MapProvider)
m_entries: array of Entry;
m_lastKey: integer ;
constructor( capacity: integer ) ;
function GetIndex( key: integer ) : object ; override ; //possible error!
function GetEntry( key: integer ) : Entry; override ;
procedure Add( key: integer ; value: object ) ; override ;
procedure Remove( key: integer ) ; virtual ;
function FindIndex( key: integer ) : integer ; //possible error!
function FindInsertIndex( key: integer ; var found: boolean ) : integer ; //possible error!
end ;
IndexMapProvider = class( MapProvider)
m_array: array of object ;
constructor ;
function GetIndex( key: integer ) : object ; override ;
function GetEntry( key: integer ) : Entry; override ;
procedure Add( key: integer ; value: object ) ; override ;
end ;
ArrayMapProvider = class( MapProvider)
m_entries: array of Entry;
constructor( capacity: integer ) ;
function GetIndex( key: integer ) : object ; override ;
function GetEntry( key: integer ) : Entry; override ;
procedure Add( key: integer ; value: object ) ; override ;
end ;
Unassigned = class
constructor ; begin end ;
end ;
ObjectMap = class
m_readonly: boolean ;
m_mapProvider: MapProvider;
constructor ;
function getCount: integer ;
property Count: integer read GetCount;
procedure SetReadOnly( value: boolean ) ;
function GetIndex( key: integer ) : object ;
procedure SetIndex( key: integer ; value: object ) ;
property ReadOnly : boolean read m_readonly write SetReadOnly;
public
property Index [ i: integer ] : object read GetIndex write SetIndex; default ;
function GetKey( index : integer ) : integer ;
procedure Remove( key: integer ) ;
procedure Add( key: integer ; value: object ) ;
procedure SetMapProvider( readOnly : boolean ) ;
end ;
DfaState = class
Index : integer ;
AcceptSymbol: Symbol;
m_transitionVector: ObjectMap;
constructor( Index : integer ; acceptSymbol: Symbol; transitionVector: ObjectMap) ;
end ;
LRStateAction = class
Index : integer ;
StateSymbol: Symbol;
Action: integer ;
Value: integer ;
constructor( Index : integer ; StateSymbol: Symbol; Action: integer ; Value: integer ) ;
end ;
LRState = class
Index : integer ;
m_actions: array of LRStateAction;
m_transitionVector: array of LRStateAction;
constructor( Index : integer ; actions: array of LRStateAction; transitionVector: array of LRStateAction) ;
function ActionCount: integer ;
function GetAction( index : integer ) : LRStateAction;
function GetActionBySymbolIndex( symbolIndex: integer ) : LRStateAction;
end ;
Rule = class
Index : integer ;
NonTerminal: Symbol;
m_symbols: array of Symbol;
ContainsOneNonTerminal: boolean ;
m_hasEmpty: boolean ;
public
constructor( index : integer ; nonTerminal: Symbol; symbols: array of Symbol) ;
function GetIndex( key: integer ) : Symbol;
property this[ i: integer ] : Symbol read GetIndex; default ;
function Name : string ;
function Count: integer ;
function Definition: string ;
function ToString: string ; override ;
end ;
DfaEdge = record
CharSetIndex: integer ;
TargetIndex: integer ;
end ;
Grammar = class
Name : string ; // Name of the grammar
Version: string ; // Version of the grammar
Author: string ; // Author of the grammar
About: string ; // Grammar description
m_startSymbolIndex: integer ; // Start symbol index
CaseSensitive: boolean ; // Grammar is case sensitive or not
// Tables read from the binary grammar file
m_symbolTable: array of Symbol; // Symbol table
m_charSetTable: array of string ; // Charset table
m_ruleTable: array of Rule; // Rule table
m_dfaStateTable: array of DfaState; // DFA state table
m_lrStateTable: array of LRState; // LR state table
// Initial states
m_dfaInitialStateIndex: integer ; // DFA initial state index
DfaInitialState: DfaState; // DFA initial state
m_lrInitialState: integer ; // LR initial state
// Internal state of grammar parser
m_reader: BinaryReader; // Source of the grammar
m_entryCount: integer ; // Number of entries left
m_errorSymbol: Symbol;
EndSymbol: Symbol;
constructor( reader: BinaryReader) ;
function FileHeader: string ;
function StartSymbol: Symbol;
function InitialLRState: LRState;
private
procedure Load;
function ReadNextRecord: integer ;
procedure ReadHeader;
procedure ReadTableCounts;
procedure ReadInitialStates;
procedure ReadSymbols;
procedure ReadCharSets;
procedure ReadRules;
procedure ReadDfaStates;
procedure ReadLRStates;
function CreateDfaTransitionVector( edges: array of DfaEdge) : ObjectMap;
procedure ReadEmptyEntry;
function ReadStringEntry: string ;
function ReadInt16Entry: integer ;
function ReadByteEntry: byte ;
function ReadBoolEntry: boolean ;
function ReadEntryType: integer ;
function ReadString: string ;
function ReadInt16: integer ;
function ReadByte: byte ;
function ReadBool: boolean ;
procedure OptimizeDfaTransitionVectors;
end ;
xParser = object ; //class!
SourceLineReadCallback = procedure( pars: xParser; lineStart, lineLength: integer ) ;
//internal in Parser
Token = record
m_symbol: Symbol; // Token symbol.
m_text: string ; // Token text.
m_start: integer ; // Token start stream start.
m_length: integer ; // Token length.
m_lineNumber: integer ; // Token source line number. (1-based).
m_linePosition: integer ; // Token position in source line (1-based).
m_syntaxNode: object ; // Syntax node which can be attached to the token.
end ;
//internal in Parser
LRStackItem = record
m_token: Token; // Token in the LR stack item.
m_state: LRState; // LR state associated with the item.
m_rule: Rule; // Reference to a grammar rule if the item contains non-terminal.
end ;
LALRParser = class
m_grammar: Grammar; // Grammar of parsed language.
TrimReductions: boolean ; // Allowes to minimize reduction tree.
m_textReader: System. IO. TextReader; // Data to parse.
m_buffer: array of char ; // Buffer to keep current characters.
m_bufferSize, // Size of the buffer.
m_bufferStartIndex, // Absolute position of buffered first character.
m_charIndex, // Index of character in the buffer.
m_preserveChars, // Number of characters to preserve when buffer is refilled.
m_lineStart, // Relative position of line start to the buffer beginning.
m_lineLength, // Length of current source line.
m_lineNumber, // Current line number.
m_commentLevel: integer ; // Keeps stack level for embedded comments
m_commentText: StringBuilder; // Current comment text.
SourceLineReadWenLineRead: SourceLineReadCallback; // Called when line reading finished.
m_token: Token; // Current token
m_inputTokens: array of Token; // Stack of input tokens.
m_inputTokenCount: integer ; // How many tokens in the input.
m_lrStack: array of LRStackItem; // Stack of LR states used for LR parsing.
m_lrStackIndex: integer ; // Index of current LR state in the LR parsing stack.
m_lrState: LRState; // Current LR state.
m_reductionCount: integer ; // Number of items in reduction. It is Undefined if no reducton available.
m_expectedTokens: array of Symbol; // What tokens are expected in case of error?
const MinimumBufferSize = 4 0 9 6 ; // Minimum size of char buffer.
const EndOfString: char = char( 0 ) ; // Designates last string terminator.
const MinimumInputTokenCount = 2 ; // Minimum input token stack size.
const MinimumLRStackSize = 2 5 6 ; // Minimum size of reduction stack.
const Undefined = - 1 ; // Used for undefined int values.
constructor( tr: TextReader; grm: Grammar) ;
function LanguageGrammar: Grammar;
function TextReader: System. IO. TextReader;
function CharPosition: integer ;
function LineNumber: integer ; // Gets current line number. It is 1-based.
function LinePosition: integer ; // Gets current char position in the current source line. It is 1-based.
function LineText: string ; // Gets current source line text. It can be truncated if line is longer than 2048 characters.
function ReadBuffer: integer ; // Reads next characters to the buffer.
procedure MoveBy( delta: integer ) ; // Increments current char index by delta character positions.
procedure MoveToLineEnd; // Moves current char pointer to the end of source line.
procedure SetTokenSymbol( value: Symbol) ;
function GetTokenSymbol: Symbol;
property TokenSymbol: Symbol read GetTokenSymbol write SetTokenSymbol;
function GetTokenText: string ;
procedure SetTokenText( text : string ) ;
property TokenText: string read GetTokenText write SetTokenText; // Gets or sets current token text.
function GetTokenSyntaxNode: object ;
procedure SetTokenSyntaxNode( text : object ) ;
property TokenSyntaxNode: object read GetTokenSyntaxNode write SetTokenSyntaxNode; // Gets or sets token syntax object associated with the current token or reduction.
function TokenString: string ; // Returns string representation of the token.
procedure PushInputToken( sym: Symbol; text : string ; syntaxNode: object ) ; // Pushes a token to the input token stack.
function PopInputToken: Symbol; // Pops token from the input token stack.
function ReadToken: Symbol; // Reads next token from the input stream.
procedure DiscardInputToken; // Removes current token and pops next token from the input stack.
function CurrentLRState: LRState;
function ReductionRule: Rule;
function ReductionCount: integer ;
function GetReductionSyntaxNode( index : integer ) : object ;
function GetExpectedTokens: array of Symbol;
function Parse: ParseMessage; // Executes next step of parser and returns parser state.
procedure ProcessBlockComment;
function CommentText: string ; // Gets current comment text.
function ParseToken: TokenParseResult;
/// <summary>
/// Gets or sets current token position relative to input stream beginning.
/// </summary>
// public int TokenCharPosition
// {
// get { return m_token.m_start; }
// set { m_token.m_start = value; }
// }
/// <summary>
/// Gets or sets current token text length.
/// </summary>
// public int TokenLength
// {
// get { return m_token.m_length; }
// set { m_token.m_length = value; }
// }
/// <summary>
/// Gets or sets current token line number. It is 1-based.
/// </summary>
// public int TokenLineNumber
// {
// get { return m_token.m_lineNumber; }
// set { m_token.m_lineNumber = value; }
// }
/// <summary>
/// Gets or sets current token position in current source line. It is 1-based.
/// </summary>
// public int TokenLinePosition
// {
// get { return m_token.m_linePosition; }
// set { m_token.m_linePosition = value; }
// }
end ;
var UnassignedValue: Unassigned;
implementation
//------------------------------------------------------------------------------
//Symbol members
//------------------------------------------------------------------------------
constructor Symbol. Create( index : integer ; name : string ; symType: integer ) ;
begin
m_quotedChars : = '|-+*?()[]{}<>!' ;
self. Index : = index ;
self. Name : = name ;
self. SymbolType : = symType;
end ;
function Symbol. IsQuotedChar( value: char ) : boolean ;
begin
result : = m_quotedChars. IndexOf( value) > = 0 ;
end ;
function Symbol. FormatTerminalSymbol( source: string ) : string ;
var res: StringBuilder;
i: integer ;
ch: char ;
begin
res : = new StringBuilder;
for i: = 0 to source. Length - 1 do begin//string[0]
ch : = source[ i] ;
if ch = '' '' then
res. Append( '' '' )
else
if IsQuotedChar( ch) or ( ch = '"' ) then
res. Append( '' '' + ch + '' '' )
else
res. Append( ch) ;
end ;
result : = res. ToString;
end ;
function Symbol. ToString: string ;
begin
if m_text= nil then
case SymbolType of
SymbolTypeNonTerminal:
m_text : = '<' + Name + '>' ;
SymbolTypeTerminal:
m_text : = FormatTerminalSymbol( Name ) ;
else
m_text : = '(' + Name + ')' ;
end ;
result : = m_text;
end ;
//------------------------------------------------------------------------------
//MapProvider members
//------------------------------------------------------------------------------
function MapProvider. GetIndex( key: integer ) : object ;
begin
result : = - 1 ;
end ;
function MapProvider. GetEntry( key: integer ) : Entry;
begin
end ;
procedure MapProvider. Add( key: integer ; value: object ) ;
begin
end ;
procedure MapProvider. Remove( key: integer ) ;
begin
raise new System. InvalidOperationException( ) ;
end ;
//------------------------------------------------------------------------------
//SortedMapProvider members
//------------------------------------------------------------------------------
constructor SortedMapProvider. Create( capacity: integer ) ;
begin
SetLength( m_entries, capacity) ;
end ;
function SortedMapProvider. GetIndex( key: integer ) : object ; //override;//possible error!
var minIndex, maxIndex, midIndex: integer ;
begin
minIndex : = 0 ;
maxIndex : = m_count - 1 ;
result : = nil ;
if ( maxIndex > = 0 ) and ( key < = m_lastKey) then begin
while minIndex < maxIndex do begin
midIndex : = ( maxIndex + minIndex) div 2 ;
if key < = m_entries[ midIndex] . Key then
maxIndex : = midIndex
else
minIndex : = midIndex + 1 ;
end ;
if key = m_entries[ minIndex] . Key then
result : = m_entries[ minIndex] . Value;
end ;
end ;
function SortedMapProvider. GetEntry( key: integer ) : Entry; //override;
begin
result : = m_entries[ key] ;
end ;
procedure SortedMapProvider. Add( key: integer ; value: object ) ; //override;
var found: boolean ;
index : integer ;
entries: array of Entry;
begin
index : = FindInsertIndex( key, found) ;
if found then begin
m_entries[ index ] . Value : = value;
exit;
end ;
if m_count > = m_entries. Length then begin
SetLength( entries, m_entries. Length + GROWTH) ;
System. Array . Copy( m_entries, 0 , entries, 0 , m_entries. Length ) ;
m_entries : = entries;
end ;
if index < m_count then
System. Array . Copy( m_entries, index , m_entries, index + 1 , m_count - index )
else
m_lastKey : = key;
m_entries[ index ] . Key : = key;
m_entries[ index ] . Value : = value;
m_count : = m_count + 1 ;
end ;
procedure SortedMapProvider. Remove( key: integer ) ; //virtual;
var index , tailSize: integer ;
begin
index : = FindIndex( key) ;
if index > = 0 then begin
tailSize : = ( m_count - 1 ) - index ;
if tailSize > 0 then begin
System. Array . Copy( m_entries, index + 1 , m_entries, index , tailSize) ;
end else
if m_count > 1 then begin
m_lastKey : = m_entries[ m_count - 2 ] . Key;
end else begin
m_lastKey : = INVALIDKEY;
end ;
m_count : = m_count - 1 ;
m_entries[ m_count] . Key : = INVALIDKEY;
m_entries[ m_count] . Value : = nil ;
end ;
end ;
function SortedMapProvider. FindIndex( key: integer ) : integer ; //possible error!
var minIndex, maxIndex, midIndex: integer ;
begin
minIndex : = 0 ;
result : = - 1 ;
if ( m_count > 0 ) and ( key < = m_lastKey) then begin
maxIndex : = m_count - 1 ;
while minIndex < maxIndex do begin
midIndex : = ( maxIndex + minIndex) div 2 ;
if key < = m_entries[ midIndex] . Key then
maxIndex : = midIndex
else
minIndex : = midIndex + 1 ;
end ;
if key = m_entries[ minIndex] . Key then
result : = minIndex;
end ;
end ;
function SortedMapProvider. FindInsertIndex( key: integer ; var found: boolean ) : integer ; //possible error!
var minIndex, maxIndex, midIndex: integer ;
begin
minIndex : = 0 ;
found : = false ;
result : = m_count;
if ( m_count > 0 ) and ( key < = m_lastKey) then begin
maxIndex : = m_count - 1 ;
while minIndex < maxIndex do begin
midIndex : = ( maxIndex + minIndex) div 2 ;
if key < = m_entries[ midIndex] . Key then
maxIndex : = midIndex
else
minIndex : = midIndex + 1 ;
end ;
found : = key = m_entries[ minIndex] . Key;
result : = minIndex;
end ;
end ;
//------------------------------------------------------------------------------
//IndexMapProvider members
//------------------------------------------------------------------------------
constructor IndexMapProvider. Create;
var i: integer ;
begin
SetLength( m_array, MAXINDEX + 1 ) ;
for i: = 0 to m_array. Length - 1 do
m_array[ i] : = UnassignedValue;
end ;
function IndexMapProvider. GetIndex( key: integer ) : object ; //override;
begin
if ( key > = m_array. Length ) or ( key < 0 ) then
result : = nil
else
result : = m_array[ key] ;
end ;
function IndexMapProvider. GetEntry( key: integer ) : Entry; //override;
var idx, i: integer ;
value: object ;
entr: Entry;
begin
idx : = - 1 ;
result : = entr;
for i : = 0 to m_array. Length - 1 do begin
value : = m_array[ i] ;
if value < > UnassignedValue then
idx : = idx + 1 ;
if idx = key then begin
entr. key : = i;
entr. value : = value;
exit;
end ;
end ;
end ;
procedure IndexMapProvider. Add( key: integer ; value: object ) ; //override;
begin
m_array[ key] : = value;
m_count : = m_count + 1 ;
end ;
//------------------------------------------------------------------------------
//ArrayMapProvider members
//------------------------------------------------------------------------------
constructor ArrayMapProvider. Create( capacity: integer ) ;
begin
SetLength( m_entries, capacity) ;
end ;
function ArrayMapProvider. GetIndex( key: integer ) : object ; //override;
var i, entryKey: integer ;
entr: Entry;
begin
i : = m_count;
result : = nil ;
while i> 0 do begin
i : = i - 1 ;
entr : = m_entries[ i] ;
entryKey : = entr. Key;
if entryKey < key then begin
continue;
end else
if entryKey = key then begin
result : = entr. Value;
break;
end else
if entryKey > key then begin
result : = nil ;
break;
end ;
end ;
end ;
function ArrayMapProvider. GetEntry( key: integer ) : Entry; //override;
begin
result : = m_entries[ key] ;
end ;
procedure ArrayMapProvider. Add( key: integer ; value: object ) ; //override;
begin
m_entries[ m_count] . Key : = key;
m_entries[ m_count] . Value : = value;
m_count : = m_count + 1 ;
end ;
//------------------------------------------------------------------------------
//ObjectMap members
//------------------------------------------------------------------------------
constructor ObjectMap. Create;
begin
m_mapProvider : = new SortedMapProvider( MINSIZE) ;
end ;
function ObjectMap. getCount: integer ;
begin
result : = m_mapProvider. m_count;
end ;
procedure ObjectMap. SetReadOnly( value: boolean ) ;
begin
if m_readonly< > value then
SetMapProvider( value) ;
m_readonly : = value;
end ;
function ObjectMap. GetIndex( key: integer ) : object ;
begin
result : = m_mapProvider[ key] ;
end ;
procedure ObjectMap. SetIndex( key: integer ; value: object ) ;
begin
m_mapProvider. Add( key, value) ;
end ;
function ObjectMap. GetKey( index : integer ) : integer ;
begin
result : = m_mapProvider. GetEntry( index ) . Key;
end ;
procedure ObjectMap. Remove( key: integer ) ;
begin
m_mapProvider. Remove( key) ;
end ;
procedure ObjectMap. Add( key: integer ; value: object ) ;
begin
m_mapProvider. Add( key, Entry( value) ) ;
end ;
procedure ObjectMap. SetMapProvider( readOnly : boolean ) ;
var i, count: integer ;
provider: MapProvider;
pr: SortedMapProvider;
entr: Entry;
begin
count : = m_mapProvider. m_count;
provider : = m_mapProvider;
if readOnly then begin
pr : = m_mapProvider as SortedMapProvider;
if pr. m_lastKey < = MAXINDEX then begin
provider : = new IndexMapProvider;
end else
if ( count < = MAXARRAYCOUNT) then begin
provider : = new ArrayMapProvider( m_mapProvider. m_count) ;
end ;
end else begin
if not ( provider is SortedMapProvider) then
provider : = new SortedMapProvider( m_mapProvider. m_count) ;
end ;
if provider < > m_mapProvider then begin
for i: = 0 to count- 1 do begin
entr : = m_mapProvider. GetEntry( i) ;
provider. Add( entr. Key, entr. Value) ;
end ;
m_mapProvider : = provider;
end ;
end ;
//------------------------------------------------------------------------------
//DFAState members
//------------------------------------------------------------------------------
constructor DFAState. Create( Index : integer ; acceptSymbol: Symbol; transitionVector: ObjectMap) ;
begin
self. Index : = Index ;
self. AcceptSymbol : = AcceptSymbol;
m_transitionVector : = transitionVector;
end ;
//------------------------------------------------------------------------------
//LRStateAction members
//------------------------------------------------------------------------------
constructor LRStateAction. Create( Index : integer ; StateSymbol: Symbol; Action: integer ; Value: integer ) ;
begin
self. Index : = Index ;
self. StateSymbol : = StateSymbol;
self. Action : = Action;
self. Value : = Value;
end ;
//------------------------------------------------------------------------------
//LRState members
//------------------------------------------------------------------------------
constructor LRState. Create( Index : integer ; actions: array of LRStateAction; transitionVector: array of LRStateAction) ;
begin
self. Index : = index ;
m_actions : = actions;
m_transitionVector : = transitionVector;
end ;
function LRState. ActionCount: integer ;
begin
result : = m_actions. Length ;
end ;
function LRState. GetAction( index : integer ) : LRStateAction;
begin
result : = m_actions[ index ] ;
end ;
function LRState. GetActionBySymbolIndex( symbolIndex: integer ) : LRStateAction;
begin
result : = m_transitionVector[ symbolIndex] ;
end ;
//------------------------------------------------------------------------------
//Rule members
//------------------------------------------------------------------------------
constructor Rule. Create( index : integer ; nonTerminal: Symbol; symbols: array of Symbol) ;
begin
self. Index : = Index ;
self. NonTerminal : = nonTerminal;
m_symbols : = symbols;
ContainsOneNonTerminal : = ( symbols. Length = 1 ) and ( symbols[ 0 ] . SymbolType = SymbolTypeNonTerminal) ;
m_hasEmpty : = symbols. Length = 0 ; // && m_nonTerminal.Name == "empty";
end ;
function Rule. Name : string ;
begin
result : = '<' + NonTerminal. Name + '>' ;
end ;
function Rule. Count: integer ;
begin
result : = m_symbols. Length ;
end ;
function Rule. GetIndex( key: integer ) : Symbol;
begin
result : = m_symbols[ index ] ;
end ;
function Rule. Definition: string ;
var res: StringBuilder;
i: integer ;
begin
res : = new StringBuilder;
for i: = 0 to m_symbols. Length - 1 do begin
res. Append( m_symbols[ i] . ToString) ;
if i < m_symbols. Length - 1 then
res. Append( ' ' ) ;
end ;
result : = res. ToString;
end ;
function Rule. ToString: string ;
begin
result : = Name + ' ::= ' + Definition;
end ;
//------------------------------------------------------------------------------
//Grammar members
//------------------------------------------------------------------------------
constructor Grammar. Create( reader: BinaryReader) ;
begin
if reader = nil then
raise new System. ArgumentNullException( 'reader' ) ;
m_reader : = reader;
Load;
end ;
function Grammar. FileHeader: string ;
begin
result : = 'GOLD Parser Tables/v1.0' ;
end ;
function Grammar. StartSymbol: Symbol;
begin
result : = m_symbolTable[ m_startSymbolIndex] ;
end ;
function Grammar. InitialLRState: LRState;
begin
result : = m_lrStateTable[ m_lrInitialState] ;
end ;
procedure Grammar. Load;
var recordType: integer ;
begin
if FileHeader< > ReadString then
raise new FileLoadException( 'GPBLALRParser.GrammarWrongFileHeader' ) ;
while m_reader. PeekChar < > - 1 do begin
recordType : = ReadNextRecord;
case recordType of
RecordTypeParameters: ReadHeader;
RecordTypeTableCounts: ReadTableCounts;
RecordTypeInitial: ReadInitialStates;
RecordTypeSymbols: ReadSymbols;
RecordTypeCharSets: ReadCharSets;
RecordTypeRules: ReadRules;
RecordTypeDfaStates: ReadDfaStates;
RecordTypeLRStates: ReadLRStates;
else
raise new FileLoadException( 'GPBLALRParser.GrammarInvalidRecordType' ) ;
end ;
end ;
DfaInitialState : = m_dfaStateTable[ m_dfaInitialStateIndex] ;
OptimizeDfaTransitionVectors;
end ;
function Grammar. ReadNextRecord: integer ;
var recordType: char ;
begin
recordType : = char( m_reader. ReadByte) ;
case recordType of
'M' : begin
m_entryCount : = ReadInt16;
result : = ReadByteEntry;
end ;
else
raise new FileLoadException( 'GPBLALRParser.Grammar_InvalidRecordHeader' ) ;
end ;
end ;
procedure Grammar. ReadHeader;
begin
Name : = ReadStringEntry;
Version : = ReadStringEntry;
Author : = ReadStringEntry;
About : = ReadStringEntry;
CaseSensitive : = ReadBoolEntry;
m_startSymbolIndex : = ReadInt16Entry;
end ;
procedure Grammar. ReadTableCounts;
begin
SetLength( m_symbolTable , ReadInt16Entry) ;
SetLength( m_charSetTable , ReadInt16Entry) ;
SetLength( m_ruleTable , ReadInt16Entry) ;
SetLength( m_dfaStateTable , ReadInt16Entry) ;
SetLength( m_lrStateTable , ReadInt16Entry) ;
end ;
procedure Grammar. ReadInitialStates;
begin
m_dfaInitialStateIndex : = ReadInt16Entry;
m_lrInitialState : = ReadInt16Entry;
end ;
procedure Grammar. ReadSymbols;
var index : integer ;
name : string ;
symbolType: integer ;
sym: Symbol;
begin
index : = ReadInt16Entry;
name : = ReadStringEntry;
symbolType : = ReadInt16Entry;
sym : = new Symbol( index , name , symbolType) ;
case symbolType of
SymbolTypeError: m_errorSymbol : = sym;
SymbolTypeEnd: EndSymbol : = sym;
end ;
m_symbolTable[ index ] : = sym;
end ;
procedure Grammar. ReadCharSets;
begin
m_charSetTable[ ReadInt16Entry] : = ReadStringEntry;
end ;
procedure Grammar. ReadRules;
var i, index : integer ;
nonTerminal: Symbol;
symbols: array of Symbol;
begin
index : = ReadInt16Entry;
nonTerminal : = m_symbolTable[ ReadInt16Entry] ;
ReadEmptyEntry;
SetLength( symbols, m_entryCount) ;
for i: = 0 to symbols. Length - 1 do
symbols[ i] : = m_symbolTable[ ReadInt16Entry] ;
m_ruleTable[ index ] : = new Rule( index , nonTerminal, symbols) ;
end ;
procedure Grammar. ReadDfaStates;
var i, index : integer ;
acceptSymbol: Symbol;
acceptState: boolean ;
edges: array of DfaEdge;
transitionVector: ObjectMap;
begin
index : = ReadInt16Entry;
acceptSymbol : = nil ;
acceptState : = ReadBoolEntry;
if acceptState then
acceptSymbol : = m_symbolTable[ ReadInt16Entry]
else
ReadInt16Entry;
ReadEmptyEntry;
// Read DFA edges
SetLength( edges, m_entryCount div 3 ) ;
for i: = 0 to edges. Length - 1 do begin
edges[ i] . CharSetIndex : = ReadInt16Entry;
edges[ i] . TargetIndex : = ReadInt16Entry;
ReadEmptyEntry;
end ;
// Create DFA state and store it in DFA state table
transitionVector : = CreateDfaTransitionVector( edges) ;
m_dfaStateTable[ index ] : = new DfaState( index , acceptSymbol, transitionVector) ;
end ;
procedure Grammar. ReadLRStates;
var targetIndex, i, index : integer ;
stateTable: array of LRStateAction;
transitionVector: array of LRStateAction;
sym: Symbol;
action: integer ;
begin
index : = ReadInt16Entry;
ReadEmptyEntry;
SetLength( stateTable, m_entryCount div 4 ) ;
for i: = 0 to stateTable. Length - 1 do begin
sym : = m_symbolTable[ ReadInt16Entry] ;
action : = ReadInt16Entry;
targetIndex : = ReadInt16Entry;
ReadEmptyEntry( ) ;
stateTable[ i] : = new LRStateAction( i, sym, action, targetIndex) ;
end ;
// Create the transition vector
SetLength( transitionVector, m_symbolTable. Length ) ;
for i: = 0 to transitionVector. Length - 1 do
transitionVector[ i] : = nil ;
for i: = 0 to stateTable. Length - 1 do
transitionVector[ stateTable[ i] . StateSymbol. Index ] : = stateTable[ i] ;
m_lrStateTable[ index ] : = new LRState( index , stateTable, transitionVector) ;
end ;
function Grammar. CreateDfaTransitionVector( edges: array of DfaEdge) : ObjectMap;
var i, j: integer ;
charSet: string ;
begin
result : = new ObjectMap;
i : = edges. Length ;
while i > 0 do begin
i : = i - 1 ;
charSet : = m_charSetTable[ edges[ i] . CharSetIndex] ;
for j: = 0 to charSet. Length - 1 do
result [ integer( charSet[ j] ) ] : = edges[ i] . TargetIndex;
end ;
end ;
procedure Grammar. ReadEmptyEntry;
begin
if ReadEntryType< > EntryTypeEmpty then
raise new FileLoadException( 'GPBLALRParser.GrammarEmptyEntryExpected' ) ;
m_entryCount : = m_entryCount - 1 ;
end ;
function Grammar. ReadStringEntry: string ;
begin
if ReadEntryType< > EntryTypeString then
raise new FileLoadException( 'GPBLALRParser.GrammarStringEntryExpected' ) ;
m_entryCount : = m_entryCount - 1 ;
result : = ReadString;
end ;
function Grammar. ReadInt16Entry: integer ;
begin
if ReadEntryType< > EntryTypeInteger then
raise new FileLoadException( 'GPBLALRParser.GrammarIntegerEntryExpected' ) ;
m_entryCount : = m_entryCount - 1 ;
result : = ReadInt16;
end ;
function Grammar. ReadByteEntry: byte ;
begin
if ReadEntryType< > EntryTypeByte then
raise new FileLoadException( 'GPBLALRParser.GrammarByteEntryExpected' ) ;
m_entryCount : = m_entryCount - 1 ;
result : = ReadByte;
end ;
function Grammar. ReadBoolEntry: boolean ;
begin
if ReadEntryType< > EntryTypeBoolean then
raise new FileLoadException( 'GPBParser.GrammarBooleanEntryExpected' ) ;
m_entryCount : = m_entryCount - 1 ;
result : = ReadBool;
end ;
function Grammar. ReadEntryType: integer ;
begin
if m_entryCount = 0 then
raise new FileLoadException( 'GPBLALRParser.GrammarNoEntry' ) ;
result : = ReadByte;
end ;
function Grammar. ReadString: string ;
var res: StringBuilder;
unicodeChar: char ;
begin
res : = new StringBuilder;
unicodeChar : = char( integer( ReadInt16) ) ;
while unicodeChar < > char( 0 ) do begin
res. Append( unicodeChar) ;
unicodeChar : = char( integer( ReadInt16) ) ;
end ;
result : = res. ToString;
end ;
function Grammar. ReadInt16: integer ;
begin
result : = m_reader. ReadUInt16;
end ;
function Grammar. ReadByte: byte ;
begin
result : = m_reader. ReadByte;
end ;
function Grammar. ReadBool: boolean ;
begin
result : = ReadByte = 1 ;
end ;
procedure Grammar. OptimizeDfaTransitionVectors;
var dfaStates: array of DfaState;
state: DfaState;
transitions: ObjectMap;
transition: object ;
key, i, j, transitionIndex: integer ;
begin
dfaStates : = m_dfaStateTable;
for j: = 0 to dfaStates. Length - 1 do begin
state : = dfaStates[ j] ;
transitions : = state. m_transitionVector;
for i: = transitions. Count- 1 downto 0 do begin
key : = transitions. GetKey( i) ;
transition : = transitions[ key] ;
if transition < > nil then begin
transitionIndex : = integer( transition) ;
if transitionIndex > = 0 then
transitions[ key] : = dfaStates[ transitionIndex]
else
transitions[ key] : = nil ;
end ;
end ;
transitions. ReadOnly : = true ;
end ;
end ;
//------------------------------------------------------------------------------
//Parser members
//------------------------------------------------------------------------------
constructor LALRParser. Create( tr: System. IO. TextReader; grm: Grammar) ;
var start: LRStackItem;
begin
m_lineNumber : = 1 ;
TrimReductions : = true ;
if tr = nil then
raise new ArgumentNullException( 'textReader' ) ;
if grm = nil then
raise new ArgumentNullException( 'grammar' ) ;
m_textReader : = tr;
m_bufferSize : = MinimumBufferSize;
SetLength( m_buffer, m_bufferSize + 1 ) ;
m_lineLength : = Undefined;
ReadBuffer;
SetLength( m_inputTokens, MinimumInputTokenCount) ;
SetLength( m_lrStack, MinimumLRStackSize) ;
m_grammar : = grm;
// Put grammar start symbol into LR parsing stack.
m_lrState : = m_grammar. InitialLRState;
start. m_token. m_symbol : = m_grammar. StartSymbol;
start. m_state : = m_lrState;
m_lrStack[ m_lrStackIndex] : = start;
m_reductionCount : = Undefined; // there are no reductions yet.
end ;
function LALRParser. LanguageGrammar: Grammar;
begin
result : = m_grammar;
end ;
function LALRParser. TextReader: System. IO. TextReader;
begin
result : = m_textReader;
end ;
function LALRParser. CharPosition: integer ;
begin
result : = m_charIndex + m_bufferStartIndex;
end ;
function LALRParser. LineNumber: integer ; // Gets current line number. It is 1-based.
begin
result : = m_lineNumber;
end ;
function LALRParser. LinePosition: integer ; // Gets current char position in the current source line. It is 1-based.
begin
result : = CharPosition - m_lineStart + 1 ;
end ;
function LALRParser. LineText: string ; // Gets current source line text. It can be truncated if line is longer than 2048 characters.
var lineStart, lineLength: integer ;
begin
lineStart : = Math. Max( m_lineStart, 0 ) ;
if m_lineLength = Undefined then
// Line was requested outside of SourceLineReadCallback call
lineLength : = m_charIndex - lineStart
else
lineLength : = m_lineLength - ( lineStart - m_lineStart) ;
if lineLength > 0 then
result : = new String( m_buffer, lineStart, lineLength)
else
result : = string . Empty;
end ;
function LALRParser. ReadBuffer: integer ; // Reads next characters to the buffer.
var lineStart, lineCharCount, moveIndex, moveCount, count: integer ;
newBuffer: array of char ;
begin
// Find out how many bytes to preserve.
// We truncate long lines.
lineStart : = m_lineStart;
if m_lineStart < 0 then
lineStart : = 0 ;
lineCharCount : = m_charIndex - lineStart;
if lineCharCount > m_bufferSize div 2 then
lineCharCount : = m_bufferSize div 2 ;
moveIndex : = m_charIndex - lineCharCount;
moveCount : = lineCharCount + m_preserveChars;
if moveCount > 0 then
// We need to keep current token characters.
if m_bufferSize - moveCount < 2 0 then begin
// Grow the buffer
m_bufferSize : = m_bufferSize * 2 ;
SetLength( newBuffer, m_bufferSize + 1 ) ;
System. Array . Copy( m_buffer, moveIndex, newBuffer, 0 , moveCount) ;
m_buffer : = newBuffer;
end else begin
System. Array . Copy( m_buffer, moveIndex, m_buffer, 0 , moveCount) ;
end ;
// Read as many characters as possible.
count : = m_bufferSize - moveCount;
result : = m_textReader. Read( m_buffer, moveCount, count) ;
// Mark character after last read one as End-Of-String
m_buffer[ moveCount + result ] : = EndOfString;
// Adjust buffer variables.
m_bufferStartIndex : = m_bufferStartIndex + moveIndex;
m_charIndex : = m_charIndex - moveIndex;
m_lineStart : = m_lineStart - moveIndex;
end ;
procedure LALRParser. MoveBy( delta: integer ) ; // Increments current char index by delta character positions.
var i, lastIndex: integer ;
begin
for i: = delta- 1 downto 0 do begin
m_charIndex : = m_charIndex + 1 ;
if m_buffer[ m_charIndex- 1 ] = charEnter then begin// '\n'
if SourceLineReadWenLineRead < > nil then begin
m_lineLength : = m_charIndex - m_lineStart - 1 ; // Exclude '\n'
lastIndex : = m_lineStart + m_lineLength - 1 ;
if ( lastIndex > = 0 ) and ( m_buffer[ lastIndex] = charReset) then //'\r'
m_lineLength : = m_lineLength - 1 ;
if m_lineLength < 0 then
m_lineLength : = 0 ;
SourceLineReadWenLineRead( self, m_lineStart + m_bufferStartIndex, m_lineLength) ;
end ;
m_lineNumber : = m_lineNumber + 1 ;
m_lineStart : = m_charIndex;
m_lineLength : = Undefined;
end ;
if m_buffer[ m_charIndex] = charEndOfFile then
if SourceLineReadWenLineRead < > nil then begin
m_lineLength : = m_charIndex - m_lineStart;
if m_lineLength > 0 then
SourceLineReadWenLineRead( self, m_lineStart + m_bufferStartIndex, m_lineLength) ;
m_lineLength : = Undefined;
end ;
end ;
end ;
procedure LALRParser. MoveToLineEnd; // Moves current char pointer to the end of source line.
var ch: char ;
begin
while true do begin
ch : = m_buffer[ m_charIndex] ;
case ch of
charEnter, charReset:
break;
charEndOfFile:
if ReadBuffer = 0 then
break;
else
if m_commentText < > nil then
m_commentText. Append( ch) ;
end ;
m_charIndex : = m_charIndex + 1 ;
end ;
end ;
procedure LALRParser. SetTokenSymbol( value: Symbol) ;
begin
m_token. m_symbol : = value;
end ;
function LALRParser. GetTokenSymbol: Symbol;
begin
result : = m_token. m_symbol;
end ;
function LALRParser. GetTokenText: string ;
begin
if m_token. m_text = nil then begin
if m_token. m_length > 0 then
m_token. m_text : = new string( m_buffer, m_token. m_start - m_bufferStartIndex, m_token. m_length)
else
m_token. m_text : = string . Empty;
end ;
result : = m_token. m_text;
end ;
procedure LALRParser. SetTokenText( text : string ) ;
begin
m_token. m_text : = text ;
end ;
function LALRParser. GetTokenSyntaxNode: object ;
begin
if m_reductionCount = Undefined then
result : = m_token. m_syntaxNode
else
result : = m_lrStack[ m_lrStackIndex] . m_token. m_syntaxNode;
end ;
procedure LALRParser. SetTokenSyntaxNode( text : object ) ;
begin
if m_reductionCount = Undefined then
m_token. m_syntaxNode : = text
else
m_lrStack[ m_lrStackIndex] . m_token. m_syntaxNode : = text ;
end ;
function LALRParser. TokenString: string ; // Returns string representation of the token.
var sb: StringBuilder;
i: integer ;
ch: char ;
begin
if m_token. m_symbol. SymbolType < > SymbolTypeTerminal then begin
result : = m_token. m_symbol. ToString;
exit;
end ;
sb : = new StringBuilder( m_token. m_length) ;
for i : = 0 to m_token. m_length- 1 do begin
ch : = m_buffer[ m_token. m_start - m_bufferStartIndex + i] ;
if ch < ' ' then
case ch of
charEnter: sb. Append( '{LF}' ) ;
charReset: sb. Append( '{CR}' ) ;
charTab: sb. Append( '{HT}' ) ;
end
else
sb. Append( ch) ;
end ;
result : = sb. ToString; {}
end ;
procedure LALRParser. PushInputToken( sym: Symbol; text : string ; syntaxNode: object ) ; // Pushes a token to the input token stack.
var newTokenArray: array of Token;
begin
if m_token. m_symbol < > nil then begin
if m_inputTokenCount = m_inputTokens. Length then begin
SetLength( newTokenArray, m_inputTokenCount* 2 ) ;
System. Array . Copy( m_inputTokens, newTokenArray, m_inputTokenCount) ;
m_inputTokens : = newTokenArray;
end ;
m_inputTokens[ m_inputTokenCount] : = m_token;
m_inputTokenCount : = m_inputTokenCount + 1 ;
end ;
// m_token := new Token;
m_token. m_symbol : = sym;
m_token. m_text : = text ;
m_token. m_length : = 0 ;
if text < > nil then
m_token. m_length : = text . Length ;
m_token. m_syntaxNode : = syntaxNode; {}
end ;
function LALRParser. PopInputToken: Symbol; // Pops token from the input token stack.
begin
result : = m_token. m_symbol;
if m_inputTokenCount > 0 then begin
m_inputTokenCount : = m_inputTokenCount - 1 ;
m_token : = m_inputTokens[ m_inputTokenCount] ;
end else begin
m_token. m_symbol : = nil ;
m_token. m_text : = nil ;
end ; {}
end ;
function LALRParser. ReadToken: Symbol; // Reads next token from the input stream.
var tokenSymbol: Symbol;
dfaStateTable: array of DfaState;
ch: char ;
curDFAState: DfaState;
lookahead, tokenLength: integer ;
begin
m_token. m_text : = nil ;
m_token. m_start : = m_charIndex + m_bufferStartIndex;
m_token. m_lineNumber : = m_lineNumber;
m_token. m_linePosition : = m_charIndex - m_lineStart + 1 ;
lookahead : = m_charIndex; // Next look ahead char in the input
tokenLength : = 0 ;
tokenSymbol : = nil ;
dfaStateTable : = m_grammar. m_dfaStateTable;
ch : = m_buffer[ lookahead] ;
if ch = EndOfString then begin
if ReadBuffer = 0 then begin
m_token. m_symbol : = m_grammar. EndSymbol;
m_token. m_length : = 0 ;
result : = m_token. m_symbol;
exit;
end ;
lookahead : = m_charIndex;
ch : = m_buffer[ lookahead] ;
end ;
curDFAState : = m_grammar. DfaInitialState;
while true do begin
curDFAState : = curDFAState. m_transitionVector[ integer( ch) ] as DfaState;
// This block-if statement checks whether an edge was found from the current state.
// If so, the state and current position advance. Otherwise it is time to exit the main loop
// and report the token found (if there was it fact one). If the LastAcceptState is -1,
// then we never found a match and the Error Token is created. Otherwise, a new token
// is created using the Symbol in the Accept State and all the characters that
// comprise it.
if curDFAState < > nil then begin
// This code checks whether the target state accepts a token. If so, it sets the
// appropiate variables so when the algorithm in done, it can return the proper
// token and number of characters.
lookahead : = lookahead + 1 ;
if curDFAState. AcceptSymbol < > nil then begin
tokenSymbol : = curDFAState. AcceptSymbol;
tokenLength : = lookahead - m_charIndex;
end ;
ch : = m_buffer[ lookahead] ;
if ch = EndOfString then begin
m_preserveChars : = lookahead - m_charIndex;
if ReadBuffer = 0 then
lookahead : = m_charIndex + m_preserveChars
else begin
lookahead : = m_charIndex + m_preserveChars;
ch : = m_buffer[ lookahead] ;
end ;
m_preserveChars : = 0 ;
end ;
end else begin
if tokenSymbol < > nil then begin
m_token. m_symbol : = tokenSymbol;
m_token. m_length : = tokenLength;
MoveBy( tokenLength) ;
end else begin
//Tokenizer cannot recognize symbol
m_token. m_symbol : = m_grammar. m_errorSymbol;
m_token. m_length : = 1 ;
MoveBy( 1 ) ;
end ;
break;
end ;
end ;
result : = m_token. m_symbol; {}
end ;
procedure LALRParser. DiscardInputToken; // Removes current token and pops next token from the input stack.
begin
if m_inputTokenCount > 0 then begin
m_inputTokenCount : = m_inputTokenCount - 1 ;
m_token : = m_inputTokens[ m_inputTokenCount] ;
end else begin
m_token. m_symbol : = nil ;
m_token. m_text : = nil ;
end ; {}
end ;
function LALRParser. CurrentLRState: LRState;
begin
result : = m_lrState;
end ;
function LALRParser. ReductionRule: Rule;
begin
result : = m_lrStack[ m_lrStackIndex] . m_rule;
end ;
function LALRParser. ReductionCount: integer ;
begin
result : = m_reductionCount;
end ;
function LALRParser. GetReductionSyntaxNode( index : integer ) : object ;
begin
//DarkStar Changed for Speed!
//if (index < 0 || index >= m_reductionCount)
// throw new IndexOutOfRangeException();
result : = m_lrStack[ m_lrStackIndex - m_reductionCount + index ] . m_token. m_syntaxNode; {}
end ;
function LALRParser. GetExpectedTokens: array of Symbol;
begin
result : = m_expectedTokens; {}
end ;
function LALRParser. Parse: ParseMessage; // Executes next step of parser and returns parser state.
var parseResult: TokenParseResult;
readTokenSymbol: Symbol;
symType: integer ;
begin
if m_token. m_symbol < > nil then
case m_token. m_symbol. SymbolType of
SymbolTypeCommentLine: begin
DiscardInputToken; //Remove it
MoveToLineEnd;
end ;
SymbolTypeCommentStart:
ProcessBlockComment;
end ;
while true do begin
if m_token. m_symbol = nil then begin
//We must read a token
readTokenSymbol : = ReadToken;
symType : = readTokenSymbol. SymbolType;
if ( m_commentLevel = 0 ) and ( symType < > SymbolTypeCommentLine) and ( symType < > SymbolTypeCommentStart) and ( symType < > SymbolTypeWhiteSpace) then begin
result : = ParseMessageTokenRead;
exit;
end ;
end else begin
//==== Normal parse mode - we have a token and we are not in comment mode
case m_token. m_symbol. SymbolType of
SymbolTypeWhiteSpace:
DiscardInputToken; // Discard Whitespace
SymbolTypeCommentStart: begin
m_commentLevel : = 1 ; // Switch to block comment mode.
result : = ParseMessageCommentBlockRead;
exit;
end ;
SymbolTypeCommentLine: begin
result : = ParseMessageCommentLineRead;
exit;
end ;
SymbolTypeError: begin
result : = ParseMessageLexicalError;
exit;
end ;
else begin
//Finally, we can parse the token
parseResult : = ParseToken;
case parseResult of
TokenParseResultAccept: begin
result : = ParseMessageAccept;
exit;
end ;
TokenParseResultInternalError: begin
result : = ParseMessageInternalError;
exit;
end ;
TokenParseResultReduceNormal: begin
if not m_lrStack[ m_lrStackIndex] . m_rule. m_hasEmpty then begin
result : = ParseMessageReduction;
exit;
end ;
end ;
TokenParseResultShift:
//A simple shift, we must continue
DiscardInputToken; // Okay, remove the top token, it is on the stack
TokenParseResultSyntaxError: begin
result : = ParseMessageSyntaxError;
exit;
end ;
end ;
end ;
end ;
end ;
end ;
end ;
procedure LALRParser. ProcessBlockComment;
var symType: integer ;
begin
if m_commentLevel > 0 then begin
if m_commentText < > nil then
m_commentText. Append( TokenText) ;
DiscardInputToken( ) ;
while true do begin
symType : = ReadToken. SymbolType;
if m_commentText < > nil then
m_commentText. Append( TokenText) ;
DiscardInputToken( ) ;
case symType of
SymbolTypeCommentStart:
m_commentLevel : = m_commentLevel + 1 ;
SymbolTypeCommentEnd: begin
m_commentLevel : = m_commentLevel - 1 ;
if m_commentLevel = 0 then
exit;
end ;
SymbolTypeEnd:
raise new Exception( 'CommentError' ) ;
end ;
end ;
end ; {}
end ;
function LALRParser. CommentText: string ; // Gets current comment text.
var lineComment, blockComment: string ;
begin
result : = string . Empty;
if m_token. m_symbol < > nil then
case m_token. m_symbol. SymbolType of
SymbolTypeCommentLine: begin
m_commentText : = new StringBuilder;
m_commentText. Append( TokenText) ;
DiscardInputToken; //Remove token
MoveToLineEnd;
lineComment : = m_commentText. ToString;
m_commentText : = nil ;
result : = lineComment;
end ;
SymbolTypeCommentStart: begin
m_commentText : = new StringBuilder;
ProcessBlockComment;
blockComment : = m_commentText. ToString;
m_commentText : = nil ;
result : = blockComment;
end ;
end ; {}
end ;
function LALRParser. ParseToken: TokenParseResult;
var stateAction: LRStateAction;
length , i, newIndex: integer ;
newArray: array of Symbol;
nextToken: LRStackItem;
currentRule: Rule;
head: LRStackItem;
nextState: LRState;
begin
stateAction : = m_lrState. m_transitionVector[ m_token. m_symbol. Index ] ;
if stateAction < > nil then begin
//Work - shift or reduce
if m_reductionCount > 0 then begin
newIndex : = m_lrStackIndex - m_reductionCount;
m_lrStack[ newIndex] : = m_lrStack[ m_lrStackIndex] ;
m_lrStackIndex : = newIndex;
end ;
m_reductionCount : = Undefined;
case stateAction. Action of
LRActionAccept: begin
m_reductionCount : = 0 ;
result : = TokenParseResultAccept;
exit;
end ;
LRActionShift: begin
m_lrState : = m_grammar. m_lrStateTable[ stateAction. Value] ;
//nextToken := new LRStackItem;
nextToken. m_token : = m_token;
nextToken. m_state : = m_lrState;
m_lrStackIndex : = m_lrStackIndex + 1 ;
m_lrStack[ m_lrStackIndex] : = nextToken;
result : = TokenParseResultShift;
exit;
end ;
LRActionReduce: begin
//Produce a reduction - remove as many tokens as members in the rule & push a nonterminal token
currentRule : = m_grammar. m_ruleTable[ stateAction. Value] ;
if TrimReductions and currentRule. ContainsOneNonTerminal then begin
head : = m_lrStack[ m_lrStackIndex] ;
head. m_token. m_symbol : = currentRule. NonTerminal;
head. m_token. m_text : = nil ;
nextState : = m_lrStack[ m_lrStackIndex - 1 ] . m_state;
m_lrState : = m_grammar. m_lrStateTable[ nextState. m_transitionVector[ currentRule. NonTerminal. Index ] . Value] ;
head. m_state : = m_lrState;
m_lrStack[ m_lrStackIndex] : = head;
result : = TokenParseResultReduceEliminated;
exit;
end else begin
//head := new LRStackItem;
head. m_rule : = currentRule;
head. m_token. m_symbol : = currentRule. NonTerminal;
head. m_token. m_text : = nil ;
m_reductionCount : = currentRule. m_symbols. Length ;
nextState : = m_lrStack[ m_lrStackIndex - m_reductionCount] . m_state;
m_lrState : = m_grammar. m_lrStateTable[ nextState. m_transitionVector[ currentRule. NonTerminal. Index ] . Value] ;
head. m_state : = m_lrState;
m_lrStackIndex : = m_lrStackIndex + 1 ;
m_lrStack[ m_lrStackIndex] : = head;
result : = TokenParseResultReduceNormal;
exit;
end ;
end ;
end ;
end ;
//=== Syntax Error! Fill Expected Tokens
SetLength( m_expectedTokens, m_lrState. ActionCount) ;
length : = 0 ;
for i : = 0 to m_lrState. ActionCount- 1 do
case m_lrState. GetAction( i) . StateSymbol. SymbolType of
SymbolTypeTerminal, SymbolTypeEnd: begin
m_expectedTokens[ length ] : = m_lrState. GetAction( i) . StateSymbol;
length : = length + 1 ;
end ;
end ;
if length < m_expectedTokens. Length then begin
SetLength( newArray, length ) ;
System. Array . Copy( m_expectedTokens, newArray, length ) ;
m_expectedTokens : = newArray;
end ;
result : = TokenParseResultSyntaxError; {}
end ;
{}
initialization
UnassignedValue : = new Unassigned;
finalization
end .