mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-21 21:51:42 +02:00
[PATCH 041/188] refactoring the parser to use exceptions
From 23625dd8e080cf3bdd8f49934b755e0d3d45e1cd Mon Sep 17 00:00:00 2001 From: Dmitry Boyarintsev <skalogryz.lists@gmail.com> Date: Wed, 20 Nov 2019 12:28:43 -0500 git-svn-id: branches/wasm@46037 -
This commit is contained in:
parent
18c78e1465
commit
fddbd834df
@ -5,23 +5,79 @@ unit watparser;
|
||||
interface
|
||||
|
||||
uses
|
||||
SysUtils, Classes, parseutils, wasmtext, wasmmodule, wasmbin, watscanner;
|
||||
SysUtils, Classes, wasmtext, wasmmodule, wasmbin, watscanner;
|
||||
|
||||
type
|
||||
TParseResult = record
|
||||
error : string;
|
||||
error : string;
|
||||
line : integer;
|
||||
pos : integer;
|
||||
offset : integer;
|
||||
end;
|
||||
|
||||
const
|
||||
TokenStr : array[TWatToken] of string = (
|
||||
'uknown', 'end of file', 'error',
|
||||
'index',
|
||||
'string', 'number', '(', ')',
|
||||
'linksymbol',
|
||||
|
||||
'instruction',
|
||||
'func',
|
||||
'param', 'result',
|
||||
'module', 'mut', 'funcref',
|
||||
'i32', 'i64',
|
||||
'f32', 'f64',
|
||||
'type',
|
||||
'import', 'global', 'table', 'memory', 'local', 'export',
|
||||
'elem', 'data', 'offset'
|
||||
);
|
||||
|
||||
//function ConsumeToken(sc: TWatScanner; tk: TWatToken): Boolean;
|
||||
function ParseModule(sc: TWatScanner; dst: TWasmModule; var res: TParseResult): Boolean;
|
||||
procedure ErrorUnexpected(var res: TParseResult; const tokenstr: string = '');
|
||||
procedure ErrorExpectButFound(var res: TParseResult; const expected: string; const butfound: string = '');
|
||||
procedure ErrorUnexpectedEof(var res: TParseResult);
|
||||
function ParseModule(sc: TWatScanner; dst: TWasmModule; var errMsg: string): Boolean; overload;
|
||||
function ParseModule(sc: TWatScanner; dst: TWasmModule; out err: TParseResult): Boolean; overload;
|
||||
|
||||
type
|
||||
// used to stop the recursive parsing
|
||||
|
||||
{ EParserError }
|
||||
|
||||
EParserError = class(Exception)
|
||||
offset : integer;
|
||||
constructor Create(const amsg: string; aofs: integer);
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
const
|
||||
WAT_DEFTYPES='iN or fN';
|
||||
|
||||
procedure ParseError(sc: TWatScanner; const errMsg: string);
|
||||
begin
|
||||
raise EParserError.Create(errMsg, sc.ofs);
|
||||
end;
|
||||
|
||||
procedure ErrorUnexpected(sc: TWatScanner; const tokenstr: string = '');
|
||||
begin
|
||||
ParseError(sc, 'unexpected '+tokenstr);
|
||||
end;
|
||||
|
||||
procedure ErrorExpectButFound(sc: TWatScanner; const expected: string; const butfound: string =''); overload;
|
||||
var
|
||||
r : string;
|
||||
begin
|
||||
if butfound = '' then r := sc.resText
|
||||
else r := butfound;
|
||||
ParseError(sc, 'expected "'+expected+'", but "'+r+'" found');
|
||||
end;
|
||||
|
||||
procedure ErrorUnexpectedEof(sc: TWatScanner);
|
||||
begin
|
||||
ParseError(sc, 'unexpected end of file');
|
||||
end;
|
||||
|
||||
procedure ConsumeAnyOpenToken(sc: TWatScanner; out tk: TWatToken;
|
||||
out hadOpenBrace: Boolean);
|
||||
out hadOpenBrace: Boolean); overload;
|
||||
begin
|
||||
sc.Next;
|
||||
hadOpenBrace := sc.token = weOpenBrace;
|
||||
@ -29,6 +85,15 @@ begin
|
||||
tk:=sc.token;
|
||||
end;
|
||||
|
||||
|
||||
procedure ConsumeAnyOpenToken(sc: TWatScanner; out tk: TWatToken); overload;
|
||||
var
|
||||
op: Boolean;
|
||||
begin
|
||||
ConsumeAnyOpenToken(sc, tk, op);
|
||||
end;
|
||||
|
||||
|
||||
function ConsumeOpenToken(sc: TWatScanner; tk: TWatToken): Boolean;
|
||||
begin
|
||||
sc.Next;
|
||||
@ -39,22 +104,22 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function ConsumeToken(sc: TWatScanner; tk: TWatToken; var res: TParseResult): Boolean;
|
||||
function ConsumeToken(sc: TWatScanner; tk: TWatToken): Boolean;
|
||||
begin
|
||||
Result:=sc.token =tk;
|
||||
if not Result then
|
||||
ErrorExpectButFound(res, 'some token','?')
|
||||
ErrorExpectButFound(sc,TokenStr[tk])
|
||||
else
|
||||
sc.Next;
|
||||
end;
|
||||
|
||||
function ParseNumOfId(sc: TWatScanner; out num: integer; out id: string; var res: TParseResult): Boolean;
|
||||
function ParseNumOfId(sc: TWatScanner; out num: integer; out id: string): Boolean;
|
||||
begin
|
||||
num:=-1;
|
||||
id:='';
|
||||
Result := sc.Next;
|
||||
if not Result then begin
|
||||
ErrorUnexpectedEof(res);
|
||||
ErrorUnexpectedEof(sc);
|
||||
Exit;
|
||||
end;
|
||||
|
||||
@ -62,7 +127,7 @@ begin
|
||||
weNumber: num:=sc.GetInt32;
|
||||
weIdent: id:=sc.resText;
|
||||
else
|
||||
ErrorExpectButFound(res, 'index');
|
||||
ErrorExpectButFound(sc, 'index', TokenStr[sc.token]);
|
||||
Result := false;
|
||||
end;
|
||||
Result := true;
|
||||
@ -83,34 +148,31 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function ParseParam(sc: TWatScanner; out id: string; out tp: byte; var res: TParseResult): Boolean;
|
||||
procedure ParseParam(sc: TWatScanner; out id: string; out tp: byte; allowIdent: Boolean = true; consumeClose: Boolean = true);
|
||||
begin
|
||||
tp:=0;
|
||||
id:='';
|
||||
if sc.token=weParam then sc.Next;
|
||||
|
||||
if sc.token=weIdent then begin
|
||||
if allowIdent and (sc.token=weIdent) then begin
|
||||
id:=sc.resText;
|
||||
sc.Next;
|
||||
end;
|
||||
|
||||
if not TokenTypeToValType(sc.token, tp) then begin
|
||||
ErrorExpectButFound(res, 'type');
|
||||
Result:=false;
|
||||
Exit;
|
||||
end else
|
||||
Result:=true;
|
||||
if not TokenTypeToValType(sc.token, tp) then
|
||||
ErrorExpectButFound(sc, WAT_DEFTYPES, TokenStr[sc.token]);
|
||||
|
||||
sc.Next;
|
||||
Result := sc.token=weCloseBrace;
|
||||
if Result then sc.Next
|
||||
else ErrorExpectButFound(res, ')');
|
||||
|
||||
if consumeClose then
|
||||
ConsumeToken(sc, weCloseBrace);
|
||||
end;
|
||||
|
||||
function ParseFunc(sc: TWatScanner; dst: TWasmFunc; var res: TParseResult): Boolean;
|
||||
procedure ParseFunc(sc: TWatScanner; dst: TWasmFunc);
|
||||
var
|
||||
nm : integer;
|
||||
id : string;
|
||||
p : TWasmParam;
|
||||
tk : TWatToken;
|
||||
begin
|
||||
if sc.token=weFunc then sc.Next;
|
||||
repeat
|
||||
@ -119,45 +181,51 @@ begin
|
||||
sc.Next;
|
||||
end;
|
||||
|
||||
Result:=false;
|
||||
if sc.token=weOpenBrace then begin
|
||||
ConsumeAnyOpenToken(sc, tk);
|
||||
|
||||
if tk = weType then begin
|
||||
if not ParseNumOfId(sc, nm, id) then Exit;
|
||||
if nm>=0 then dst.typeIdx:=nm
|
||||
else dst.typeId:=id;
|
||||
ConsumeAnyOpenToken(sc, tk);
|
||||
end;
|
||||
|
||||
while tk = weParam do begin
|
||||
p:=dst.GetInlineType.AddParam;
|
||||
sc.Next;
|
||||
case sc.token of
|
||||
weType: begin
|
||||
if not ParseNumOfId(sc, nm, id, res) then Exit;
|
||||
if nm>=0 then dst.typeIdx:=nm
|
||||
else dst.typeId:=id;
|
||||
end;
|
||||
weParam: begin
|
||||
sc.Next;
|
||||
p:=dst.GetInlineType.AddParam;
|
||||
if not ParseParam(sc, p.id, p.tp, res) then Exit;
|
||||
end;
|
||||
weResult: begin
|
||||
sc.Next;
|
||||
p:=dst.GetInlineType.AddResult;
|
||||
if not ParseParam(sc, p.id, p.tp, res) then Exit;
|
||||
end;
|
||||
weLocal: begin
|
||||
sc.Next;
|
||||
p:=dst.AddLocal;
|
||||
if not ParseParam(sc, p.id, p.tp, res) then Exit;
|
||||
end;
|
||||
else
|
||||
ErrorUnexpected(res, 'booh');
|
||||
Exit;
|
||||
end;
|
||||
if not ConsumeToken(sc, weCloseBrace, res) then Exit;
|
||||
ParseParam(sc, p.id, p.tp);
|
||||
ConsumeAnyOpenToken(sc, tk);
|
||||
end;
|
||||
|
||||
while tk = weResult do begin
|
||||
p:=dst.GetInlineType.AddResult;
|
||||
sc.Next;
|
||||
ParseParam(sc, p.id, p.tp, false);
|
||||
ConsumeAnyOpenToken(sc, tk);
|
||||
end;
|
||||
|
||||
while tk = weLocal do begin
|
||||
p:=dst.AddLocal;
|
||||
sc.Next;
|
||||
ParseParam(sc, p.id, p.tp);
|
||||
ConsumeAnyOpenToken(sc, tk);
|
||||
end;
|
||||
|
||||
if not (tk in [weInstr, weCloseBrace]) then
|
||||
ErrorExpectButFound(sc, 'identifier');
|
||||
|
||||
while tk<>weCloseBrace do begin
|
||||
ConsumeToken(sc, weInstr);
|
||||
end;
|
||||
|
||||
until sc.token=weCloseBrace;
|
||||
sc.Next;
|
||||
end;
|
||||
|
||||
function ParseModule(sc: TWatScanner; dst: TWasmModule; var res: TParseResult): Boolean;
|
||||
function ParseModuleInt(sc: TWatScanner; dst: TWasmModule): Boolean;
|
||||
begin
|
||||
if not ConsumeOpenToken(sc, weModule) then begin
|
||||
Result := false;
|
||||
ErrorExpectButFound(sc, 'module');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
@ -167,12 +235,11 @@ begin
|
||||
sc.Next;
|
||||
|
||||
if sc.token = weFunc then begin
|
||||
Result := ParseFunc(sc, dst.AddFunc, res);
|
||||
if not Result then Exit;
|
||||
ParseFunc(sc, dst.AddFunc);
|
||||
end;
|
||||
|
||||
end else if sc.token<>weCloseBrace then begin
|
||||
ErrorUnexpected(res);
|
||||
ErrorUnexpected(sc, TokenStr[sc.token]);
|
||||
Result := false;
|
||||
exit;
|
||||
end;
|
||||
@ -181,21 +248,62 @@ begin
|
||||
Result := true;
|
||||
end;
|
||||
|
||||
procedure ErrorUnexpected(var res: TParseResult; const tokenstr: string);
|
||||
function ParseModule(sc: TWatScanner; dst: TWasmModule; var errMsg: string): Boolean;
|
||||
var
|
||||
res : TParseResult;
|
||||
begin
|
||||
res.error:='unexpected token '+tokenstr;
|
||||
Result := ParseModule(sc, dst, res);
|
||||
if not Result then begin
|
||||
errMsg:=Format('line: %d, pos: %d, %s', [res.line, res.pos, res.error]);
|
||||
end else
|
||||
errMsg:='';
|
||||
end;
|
||||
|
||||
procedure ErrorUnexpectedEof(var res: TParseResult);
|
||||
procedure GetLineAndPos(const buf: string; ofs: integer; out line, pos: integer);
|
||||
var
|
||||
i: integer;
|
||||
ll: integer;
|
||||
begin
|
||||
res.error:='unexpected end of file';
|
||||
i:=1;
|
||||
line:=1;
|
||||
ll:=1;
|
||||
while (i<=length(buf)) and (i<ofs) do begin
|
||||
if (buf[i]=#13) or (buf[i]=#10) then begin
|
||||
inc(line);
|
||||
if (i<=length(buf)) and (i<ofs) and ((buf[i]=#13) or (buf[i]=#10)) and (buf[i] <> buf[i-1]) then
|
||||
inc(i);
|
||||
ll:=i;
|
||||
end;
|
||||
inc(i);
|
||||
end;
|
||||
pos:=ofs - ll;
|
||||
end;
|
||||
|
||||
procedure ErrorExpectButFound(var res: TParseResult; const expected, butfound: string);
|
||||
function ParseModule(sc: TWatScanner; dst: TWasmModule; out err: TParseResult): Boolean;
|
||||
begin
|
||||
res.error:=expected +' is expected';
|
||||
if butfound<>'' then
|
||||
res.error:=res.error+', but '+butfound+ ' found';
|
||||
try
|
||||
err.error:='';
|
||||
err.pos:=0;
|
||||
err.line:=0;
|
||||
err.offset:=0;
|
||||
ParseModuleInt(sc, dst);
|
||||
Result:=true;
|
||||
except
|
||||
on x: EParserError do begin
|
||||
err.error := x.Message;
|
||||
err.offset := x.offset;
|
||||
GetLineAndPos(sc.buf, x.offset, err.line, err.pos);
|
||||
Result:=false;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ EParserError }
|
||||
|
||||
constructor EParserError.Create(const amsg: string; aofs: integer);
|
||||
begin
|
||||
inherited Create(amsg);
|
||||
offset:=aofs;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user