Fast Web Script

edited 7:26AM in FastScript
unit fs_WebScriptParse;

interface

uses
SysUtils, Classes;

type
TLanguage = (fsPascal, fsBasic);

procedure ParseWebScript(AInStream: TStream; AOutCode: TStrings;var ALanguage: TLanguage; var AOptionExplicit: Boolean);

implementation

const
PS_START = 0;
PS_READLANG = 1;
PS_READ = 2;
PS_READCODE = 3;
PS_READDIR = 4;
PS_READDIRVB = 5;
PS_READEVAL = 6;
PS_END = 7;

procedure ParseWebScript(AInStream: TStream; AOutCode: TStrings;var ALanguage: TatLanguage; var AOptionExplicit: Boolean);
const
CAQuote: array[TatLanguage] of string = ('''', '"');
CAConCat: array[TatLanguage] of string = (' + ', ' & ');
CALnStart: array[TatLanguage] of string = ('WriteLn(', 'WriteLn(');
CALnEnd: array[TatLanguage] of string = (');', ')');
CAVarToStrStart: array[TatLanguage] of string = (' VarToStr(', ' VarToStr(');
CAVarToStrEnd: array[TatLanguage] of string = (') ', ' )');
var
EndOfStream: Boolean;
iPState, iPrevState: integer;
Buf: array[0..20] of Char; // The buffer size = 10 -> PeekString has a max. of 10 !!
CPrev, CCur, CNext, CLast: ^Char;
SCurLang, SCurData, SCurEval, SCurCode, SCurDir, SDirRepl: string;

function ScrQuote: string;
begin
Result := CAQuote[ALanguage];
end;

function ScrConCat: string;
begin
Result := CAConCat[ALanguage];
end;

function ScrLnStart: string;
begin
Result := CALnStart[ALanguage];
end;

function ScrLnEnd: string;
begin
Result := CALnEnd[ALanguage];
end;

function ScrEvalStart: string;
begin
Result := CAVarToStrStart[ALanguage];
end;

function ScrEvalEnd: string;
begin
Result := CAVarToStrEnd[ALanguage];
end;

procedure SetParserState(ANewState: integer);
begin
if ANewState <> iPState then
begin
iPrevState := iPState;
iPState := ANewState;
end;
end;

function GetNextChar: Char;
var
i: integer;
begin
// Shift the buffer
for i := Low(Buf) + 1 to High(Buf) do Buf[i-1] := Buf;

if AInStream.Position < AInStream.Size then
AInStream.Read(CLast^, 1)
else begin
EndOfStream := True;
CLast^ := #0;
end;
Result := CCur^;
end;

function PeekString(ACount: integer): string;
begin
SetString(Result, PChar(CNext), ACount);
end;

function CompareBuf(ACompare: string; SkipIfTrue: Boolean): Boolean;
var
S: string;
i: integer;
begin
// The first char will be deleted since this is checked in the main-loop.
// The reason for this is to make the keywords in the loop a little more
// readable.
Delete(ACompare, 1, 1);
SetString(S, PChar(CNext), Length(ACompare));
Result := SameText(S, ACompare);
if Result and SkipIfTrue then
for i := 1 to Length(S) do GetNextChar;
end;

procedure ProcessChar;
begin
case iPState of
PS_READLANG:
SCurLang := SCurLang + CCur^;
PS_READ:
begin
if Length(SCurCode) > 0 then
begin
AOutCode.Add(SCurCode);
SCurCode := '';
end;
if Length(SCurEval) > 0 then
begin
//SCurData := SCurData + ''' + ' + SCurEval + ' + '''; or
//SCurData := SCurData + '" & ' + SCurEval + ' & "';
SCurData := SCurData + ScrQuote + ScrConCat + ScrEvalStart + SCurEval + ScrEvalEnd + ScrConCat + ScrQuote;
SCurEval := '';
end;
if CCur^ = ScrQuote then
SCurData := sCurData + CCur^ + CCur^ // Add double ' or "
else
SCurData := sCurData + CCur^;
end;
PS_READDIR, PS_READDIRVB:
SCurDir := SCurDir + CCur^;
PS_READCODE:
begin
if Length(SCurData) > 0 then
begin
AOutCode.Add(SCurData);
SCurData := '';
end;
SCurCode := SCurCode + CCur^;
end;
PS_READEVAL:
SCurEval := SCurEval + CCur^;
end;
end;

procedure AddLineToOutput;
begin
case iPState of
PS_READ, PS_END:
if (Length(SCurData) > 0) then
begin
if Length(SCurEval) > 0 then
AOutCode.Add(ScrLnStart + ScrQuote + SCurData + ScrQuote + ScrConCat + ScrEvalStart + SCurEval + ScrEvalEnd + ScrLnEnd)
else
AOutCode.Add(ScrLnStart + ScrQuote + SCurData + ScrQuote + ScrLnEnd) //WriteLn('<SCurData>');
end;
PS_READCODE:
AOutCode.Add(SCurCode);
PS_READEVAL:
AOutCode.Add(ScrLnStart + ScrEvalStart + SCurEval + ScrEvalEnd + ScrLnEnd); //WriteLn(VarToStr(<SCurEval>));
end;
SCurData := '';
SCurCode := '';
SCurEval := '';
end;

procedure HandleDirectiveCode;
var
SStrm: TStringStream;
begin
SDirRepl := '';
SStrm := TStringStream.Create(SDirRepl);
try
ParseWebScript(SStrm, AOutCode, ALanguage, AOptionExplicit);
finally
SStrm.Free;
end;
end;
SCurDir := '';
end;

begin
if AInStream.Size = 0 then Exit;

iPState := PS_START;
iPrevState := PS_START;

SCurLang := '';
SCurData := '';
SCurEval := '';
SCurCode := '';
SCurDir := '';

// init the buffer and pointers pointer reference
FillChar(Buf, SizeOf(Buf), 0);
CPrev := @Buf[0];
CCur := @Buf[1];
CNext := @Buf[2];
CLast := @Buf[High(Buf)];
EndOfStream := (AInStream.Read(Buf[2], High(Buf)-1) <> (High(Buf) - 1));
{
<%@Language=VBScript%>;
<%@Language=Pascal%>;
}

while (iPState <> PS_END) do
begin
case GetNextChar of
'<':
begin
if (iPState = PS_START) and CompareBuf('<%@Language=', True) and (SCurLang = '') then
begin
SetParserState(PS_READLANG) //This is only allowed when ParserState = PS_Start
end
else if (CNext^ = '%') and (iPState <= PS_READ) then
begin
GetNextChar; // Skip the '%'
SetParserState(PS_READCODE);
end
else if (iPState = PS_READ) and CompareBuf('<!--#', True) then
begin // check for ASP <!--# directive -->
AddLineToOutput; //Flush pending data
SetParserState(PS_READDIRVB);
end
else begin
if iPState = PS_START then iPState := PS_READ;
ProcessChar;
end;
end;
'%':
if (CNext^ = '>') and (iPState >= PS_READCODE) then
begin
if (iPState = PS_READCODE) then
AddLineToOutput;

GetNextChar;
SetParserState(PS_READ);
end
else if (CNext^ = '>') and (iPState = PS_READLANG) then
begin
if SameText(SCurLang, 'VBScript') then
ALanguage := alBasic
else
ALanguage := alPascal;

GetNextChar;
SetParserState(PS_READ);
//iPrevState := PS_START;
end
else if not ((CPrev^ = '<') and (iPState = PS_READCODE) and (iPrevState = PS_READ)) then
ProcessChar;
'=':
begin
if (CPrev^ = '%') and (iPState = PS_READCODE) then
SetParserState(PS_READEVAL)
else
ProcessChar;
end;
'{':
begin
if (iPState < PS_READDIR) and (CNext^ = '$') then
begin
GetNextChar; // Skip the '$'
AddLineToOutput; //Flush pending data
SetParserState(PS_READDIR);
end
else
ProcessChar;
end;
'}':
begin
if (iPState = PS_READDIR) then
begin
HandleDirectiveCode;
SetParserState(iPrevState); // PS_READ)
end
else
ProcessChar;
end;
'-':
begin
if (iPState = PS_READDIRVB) and CompareBuf('-->', True) then
begin
HandleDirectiveCode;
SetParserState(iPrevState);
end
else
ProcessChar;
end;
'o', 'O': // Check for Option Explicit
begin
if (iPState = PS_READCODE) and CompareBuf('option explicit', True) then
AOptionExplicit := True
else
ProcessChar;
end;
#10:;
#13:
begin
if (iPState <= PS_READCODE) then
AddLineToOutput
else
ProcessChar;
end;
#0:
if (CNext^ = #0) then SetParserState(PS_END);
else
ProcessChar;
end;
if (iPState = PS_END) and EndOfStream then Break;
end;
AddLineToOutput;
end;

end.


Leave a Comment

Rich Text Editor. To edit a paragraph's style, hit tab to get to the paragraph menu. From there you will be able to pick one style. Nothing defaults to paragraph. An inline formatting menu will show up when you select text. Hit tab to get into that menu. Some elements, such as rich link embeds, images, loading indicators, and error messages may get inserted into the editor. You may navigate to these using the arrow keys inside of the editor and delete them with the delete or backspace key.