|
- unit uengShaderFileParser;
-
- {$mode objfpc}{$H+}
- {$I uengShaderFile.inc}
-
- interface
-
- uses
- Classes, SysUtils,
- uengShaderFileTypes
-
- {$IFDEF SHADER_FILE_USE_BITSPACE_UTILS}
- , uutlGenerics
- {$ELSE}
- , uengShaderFileGenerics
- {$ENDIF}
- ;
-
- type
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- TengTokenParameter = packed record
- Name: String;
- Quoted: Boolean;
- Line: Integer;
- Col: Integer;
- end;
- TengTokenParameterList = class(specialize TutlSimpleList<TengTokenParameter>)
- private
- fFilename: String;
- public
- property Filename: String read fFilename;
- constructor Create(const aFilename: String);
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- TengParseArgs = class
- private
- fFilename: String;
- fCode: TStringList;
- fLineLength: Integer;
- fLineCount: Integer;
- fCurrentLine: String;
- fCurrentChar: Char;
- fCol: Integer;
- fLine: Integer;
-
- procedure SetCol(const aValue: Integer);
- procedure SetLine(const aValue: Integer);
-
- function GetEndOfLine: Boolean;
- function GetEndOfFile: Boolean;
- function GetCode: TStrings;
- public
- property Code: TStrings read GetCode;
- property LineLength: Integer read fLineLength;
- property LineCount: Integer read fLineCount;
- property CurrentLine: String read fCurrentLine;
- property CurrentChar: Char read fCurrentChar;
- property EndOfLine: Boolean read GetEndOfLine;
- property EndOfFile: Boolean read GetEndOfFile;
- property Filename: String read fFilename;
- property Col: Integer read fCol write SetCol;
- property Line: Integer read fLine write SetLine;
-
- procedure NextCol;
- procedure NextLine;
- function ExtractToken(const aSender: TObject; const aParameters: TengTokenParameterList): Boolean;
- function GetTokenPreview(const aSender: TObject; var aToken: String): Boolean;
-
- constructor Create(const aStream: TStream; const aFilename: String);
- destructor Destroy; override;
- end;
-
- implementation
-
- uses
- uengShaderFileConstants;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //TengTokenParameterList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- constructor TengTokenParameterList.Create(const aFilename: String);
- begin
- inherited Create(true);
- fFilename := aFilename;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //TengParseArgs/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- procedure TengParseArgs.SetCol(const aValue: Integer);
- begin
- fCol := aValue;
- if not EndOfLine
- then fCurrentChar := fCurrentLine[fCol]
- else fCurrentChar := #0;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- procedure TengParseArgs.SetLine(const aValue: Integer);
- begin
- fLine := aValue;
- if not EndOfFile then begin
- fCurrentLine := fCode[fLine];
- fLineLength := Length(fCurrentLine);
- end else begin
- fCurrentLine := '';
- fLineLength := 0;
- end;
- Col := 1;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- function TengParseArgs.GetEndOfLine: Boolean;
- begin
- result := (fCol > fLineLength)
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- function TengParseArgs.GetEndOfFile: Boolean;
- begin
- result := (fLine >= fLineCount);
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- procedure TengParseArgs.NextCol;
- begin
- Col := Col + 1;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- procedure TengParseArgs.NextLine;
- begin
- Line := Line + 1;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- function TengParseArgs.ExtractToken(const aSender: TObject; const aParameters: TengTokenParameterList): Boolean;
- type
- TCharType = (
- ctUnknown,
- ctValidTokenChar,
- ctInvalidTokenChar
- );
- TParseFlag = (
- pfQuote,
- pfInToken,
- pfIsComment,
- pfCommentTokenAdded
- );
- TParseFlags = set of TParseFlag;
-
- var
- pf: TParseFlags;
- ct: TCharType;
- s: String;
- pLine, pCol, oldLine, oldCol: Integer;
-
- procedure AddPart(const aTrimAndCheck: Boolean = true);
- var
- len: Integer;
- p: TengTokenParameter;
- begin
- if aTrimAndCheck then
- s := Trim(s);
- if not aTrimAndCheck or (s <> '') then begin
- len := Length(s);
- if aTrimAndCheck and
- ( (s[1] = TOKEN_CHAR_QUOTE) and
- (s[len] = TOKEN_CHAR_QUOTE)) then
- begin
- if not (s[1] = TOKEN_CHAR_QUOTE) then
- raise EengShaderPart.Create('missing leading quote char', Line, Col, Filename, aSender);
- if not (s[len] = TOKEN_CHAR_QUOTE) then
- raise EengShaderPart.Create('missing trailing quote char', Line, Col, Filename, aSender);
- delete(s, len, 1);
- delete(s, 1, 1);
- p.Quoted := true;
- end else
- p.Quoted := false;
- p.Name := s;
- p.Line := pLine;
- p.Col := pCol;
- aParameters.Add(p);
- end;
- s := '';
- pLine := Line;
- pCol := Col;
- ct := ctUnknown;
- end;
-
- begin
- result := false;
- aParameters.Clear;
- if (CurrentChar <> TOKEN_CHAR_BEGIN) or
- (Col + 1 > LineLength) or
- ( (CurrentLine[Col+1] <> TOKEN_CHAR_IDENT) and
- (CurrentLine[Col+1] <> TOKEN_CHAR_COMMENT))
- then
- exit;
-
- result := true;
- s := '';
- ct := ctUnknown;
- oldLine := Line;
- oldCol := Col;
- pf := [];
- if (CurrentLine[Col+1] = TOKEN_CHAR_COMMENT) then
- Include(pf, pfIsComment);
- AddPart; // initialize
-
- while not EndOfFile do begin
- while not EndOfLine do begin
- case CurrentChar of
- TOKEN_CHAR_BEGIN: begin
- if (pfQuote in pf) then
- s := s + CurrentChar
- else if not (pfInToken in pf) then
- Include(pf, pfInToken)
- else
- EengShaderPart.Create('invalid char in token', Line, Col, Filename, aSender);
- end;
-
- TOKEN_CHAR_END: begin
- if not (pfQuote in pf) then begin
- AddPart(not (pfIsComment in pf));
- NextCol;
- if (aParameters.Count <= 0) or (aParameters[0].Name = TOKEN_CHAR_IDENT) then
- raise EengShaderPart.Create('empty token', Line, Col, Filename, aSender);
- exit;
- end else
- s := s + CurrentChar;
- end;
-
- TOKEN_CHAR_QUOTE: begin
- if not (pfQuote in pf) and not (pfIsComment in pf) then
- AddPart;
- s := s + CurrentChar;
- if (pfQuote in pf)
- then exclude(pf, pfQuote)
- else include(pf, pfQuote);
- if not (pfQuote in pf) and not (pfIsComment in pf) then
- AddPart;
- end;
-
- TOKEN_CHAR_COMMENT: begin
- s := s + CurrentChar;
- if (pfIsComment in pf) and not (pfCommentTokenAdded in pf) then begin
- include(pf, pfCommentTokenAdded);
- AddPart(false);
- end;
- end;
- else
- if not (pfQuote in pf) and not (pfIsComment in pf) then begin
- if (CurrentChar in TOKEN_SPLIT_CHARS) then begin
- AddPart;
- end else if (CurrentChar in VALID_TOKEN_CHARS) then begin
- if (ct <> ctValidTokenChar) then
- AddPart;
- ct := ctValidTokenChar;
- end else begin
- if (ct <> ctInvalidTokenChar) then
- AddPart;
- ct := ctInvalidTokenChar;
- end;
- end;
- s := s + CurrentChar;
- end;
- NextCol;
- end;
- s := s + sLineBreak;
- NextLine;
- end;
- raise EengShaderPart.Create('incomplete token', oldLine, oldCol, Filename, aSender);
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- function TengParseArgs.GetCode: TStrings;
- begin
- result := fCode;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- function TengParseArgs.GetTokenPreview(const aSender: TObject; var aToken: String): Boolean;
- var
- c: Integer;
- begin
- result := false;
- if (CurrentChar <> TOKEN_CHAR_BEGIN) or
- (Col >= LineLength) or
- not (CurrentLine[Col + 1] in [TOKEN_CHAR_IDENT, TOKEN_CHAR_COMMENT])
- then exit;
- result := true;
- aToken := CurrentChar;
- if (aToken = TOKEN_CHAR_COMMANT_END) then
- exit;
- c := Col + 1;
- case CurrentLine[c] of
- TOKEN_CHAR_IDENT: begin
- aToken := '';
- repeat
- aToken := aToken + CurrentLine[c];
- inc(c);
- until (c > LineLength) or not (CurrentLine[c] in VALID_TOKEN_CHARS);
- aToken := Trim(aToken);
- if (aToken = TOKEN_CHAR_IDENT) then
- raise EengInvalidToken.Create('empty token', Line, Col, Filename, aSender);
- end;
-
- TOKEN_CHAR_COMMENT:
- aToken := TOKEN_CHAR_COMMENT;
- end;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- constructor TengParseArgs.Create(const aStream: TStream; const aFilename: String);
- begin
- inherited Create;
- fFilename := aFilename;
- fCode := TStringList.Create;
- fCode.LoadFromStream(aStream);
- fLineCount := fCode.Count;
- Line := 0;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- destructor TengParseArgs.Destroy;
- begin
- FreeAndNil(fCode);
- inherited Destroy;
- end;
-
- end.
|