From 4c787b4b9f79a958991f248ec2db7a8e6497492e Mon Sep 17 00:00:00 2001 From: Nikolay Nikolov Date: Fri, 12 Jul 2024 15:29:29 +0300 Subject: [PATCH] + started working on a WebAssembly inline assembler reader. Not ready, yet, just includes a basic tokenizer for now. --- compiler/wasm32/cputarg.pas | 1 + compiler/wasm32/rawasm.pas | 43 +++ compiler/wasm32/rawasmtext.pas | 503 +++++++++++++++++++++++++++++++++ 3 files changed, 547 insertions(+) create mode 100644 compiler/wasm32/rawasm.pas create mode 100644 compiler/wasm32/rawasmtext.pas diff --git a/compiler/wasm32/cputarg.pas b/compiler/wasm32/cputarg.pas index 8692268a13..1213f808e4 100644 --- a/compiler/wasm32/cputarg.pas +++ b/compiler/wasm32/cputarg.pas @@ -53,6 +53,7 @@ implementation {************************************** Assembler Readers **************************************} + ,rawasmtext {************************************** Debuginfo diff --git a/compiler/wasm32/rawasm.pas b/compiler/wasm32/rawasm.pas new file mode 100644 index 0000000000..993d3bca16 --- /dev/null +++ b/compiler/wasm32/rawasm.pas @@ -0,0 +1,43 @@ +{ + Copyright (c) 1998-2003 by Carl Eric Codere and Peter Vreman + Copyright (c) 2024 by Nikolay Nikolov + + Handles the common WebAssembly assembler reader routines + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + **************************************************************************** +} +unit rawasm; + +{$i fpcdefs.inc} + + interface + + uses + cpubase, + aasmtai,aasmdata, + rautils; + + type + TWasmOperand=class(TOperand) + end; + + TWasmInstruction=class(TInstruction) + end; + + implementation + +end. diff --git a/compiler/wasm32/rawasmtext.pas b/compiler/wasm32/rawasmtext.pas new file mode 100644 index 0000000000..84e666612d --- /dev/null +++ b/compiler/wasm32/rawasmtext.pas @@ -0,0 +1,503 @@ +{ + Copyright (c) 1998-2008 by Carl Eric Codere and Peter Vreman + Copyright (c) 2024 by Nikolay Nikolov + + Does the parsing for the WebAssembly styled inline assembler. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + **************************************************************************** +} +Unit rawasmtext; + +{$i fpcdefs.inc} + + Interface + + uses + cclasses, + globtype, + rasm,rawasm, + aasmbase,cpubase; + + type + tasmtoken = ( + AS_NONE,AS_LPAREN,AS_RPAREN,AS_ID,AS_END,AS_OPCODE,AS_INTNUM, + AS_REALNUM,AS_STRING + ); + tasmkeyword = string[10]; + + const + token2str : array[tasmtoken] of tasmkeyword=( + '','(',')','identifier','end','opcode','integer','float','string'); + + type + + { twasmreader } + + twasmreader = class(tasmreader) + private + actasmpattern_origcase: string; + actasmtoken : tasmtoken; + prevasmtoken : tasmtoken; + procedure SetupTables; + procedure GetToken; + function consume(t : tasmtoken):boolean; + function is_asmopcode(const s: string):boolean; + public + function Assemble: tlinkedlist;override; + end; + + + Implementation + + uses + { helpers } + cutils, + { global } + globals,verbose, + systems, + { aasm } + cpuinfo,aasmtai,aasmdata,aasmcpu, + { symtable } + symconst,symbase,symtype,symsym,symtable,symdef,symutil, + { parser } + scanner,pbase, + procinfo, + rabase,rautils, + cgbase,cgutils,cgobj, + { wasm } + itcpuwasm + ; + + +{***************************************************************************** + twasmreader +*****************************************************************************} + + procedure twasmreader.SetupTables; + var + i: TAsmOp; + begin + iasmops:=TFPHashList.create; + for i:=firstop to lastop do + if wasm_op2str[i]<>'end' then + iasmops.Add(wasm_op2str[i],Pointer(PtrInt(i))); + end; + + + procedure twasmreader.GetToken; + var + len: Integer; + has_sign, is_hex, is_float: Boolean; + tmpS: string; + tmpI, tmpCode: Integer; + begin + c:=scanner.c; + { save old token and reset new token } + prevasmtoken:=actasmtoken; + actasmtoken:=AS_NONE; + { reset } + actasmpattern:=''; + { while space, tab, new line or comment, continue scan... } + while c in [' ',#9,#13,#10] do + begin + c:=current_scanner.asmgetchar; + case c of + ';': + begin + c:=current_scanner.asmgetchar; + case c of + { ;; comment until end of line } + ';': + begin + { skip until end of line } + repeat + c:=current_scanner.asmgetchar; + until c in [#13,#10]; + end; + else + current_scanner.illegal_char(c); + end; + end; + '(': + begin + current_scanner.gettokenpos; + c:=current_scanner.asmgetchar; + case c of + { (; block comment ;) } + ';': + begin + { skip until ;) } + repeat + c:=current_scanner.asmgetchar; + if c=';' then + begin + c:=current_scanner.asmgetchar; + if c=')' then + begin + c:=current_scanner.asmgetchar; + break; + end; + end; + until false; + end; + else + begin + actasmtoken:=AS_LPAREN; + exit; + end; + end; + end; + end; + end; + current_scanner.gettokenpos; + case c of + ')': + begin + c:=current_scanner.asmgetchar; + actasmtoken:=AS_RPAREN; + end; + '$','a'..'z','A'..'Z': + begin + len:=0; + while c in ['A'..'Z','a'..'z','0'..'9', + '!','#','$','%','&','''','*','+','-','.','/', + ':','<','=','>','?','@','\','^','_','`','|','~'] do + begin + inc(len); + actasmpattern[len]:=c; + c:=current_scanner.asmgetchar; + end; + actasmpattern[0]:=chr(len); + actasmpattern_origcase:=actasmpattern; + if actasmpattern[1]='$' then + actasmtoken:=AS_ID + else if is_asmopcode(actasmpattern) then + begin + exit; + end + else if upper(actasmpattern) = 'END' then + begin + uppervar(actasmpattern); + actasmtoken:=AS_END; + exit; + end + else + begin + message1(asmr_e_unknown_opcode,actasmpattern); + actasmtoken:=AS_NONE; + end; + end; + '0'..'9','+','-': + begin + len:=0; + has_sign:=false; + is_hex:=false; + is_float:=false; + if c in ['+','-'] then + begin + has_sign:=true; + inc(len); + actasmpattern[len]:=c; + c:=current_scanner.asmgetchar; + end; + if c='0' then + begin + inc(len); + actasmpattern[len]:=c; + c:=current_scanner.asmgetchar; + if c='x' then + begin + is_hex:=true; + inc(len); + actasmpattern[len]:=c; + c:=current_scanner.asmgetchar; + end; + end; + if is_hex then + begin + while c in ['0'..'9','a'..'f','A'..'F'] do + begin + inc(len); + actasmpattern[len]:=c; + c:=current_scanner.asmgetchar; + end; + end + else + begin + while c in ['0'..'9'] do + begin + inc(len); + actasmpattern[len]:=c; + c:=current_scanner.asmgetchar; + end; + end; + if c='.' then + begin + is_float:=true; + inc(len); + actasmpattern[len]:=c; + c:=current_scanner.asmgetchar; + { parse the fractional part } + if is_hex then + begin + while c in ['0'..'9','a'..'f','A'..'F'] do + begin + inc(len); + actasmpattern[len]:=c; + c:=current_scanner.asmgetchar; + end; + end + else + begin + while c in ['0'..'9'] do + begin + inc(len); + actasmpattern[len]:=c; + c:=current_scanner.asmgetchar; + end; + end; + end; + if (is_hex and (c in ['p','P'])) or + ((not is_hex) and (c in ['e','E'])) then + begin + inc(len); + actasmpattern[len]:=c; + c:=current_scanner.asmgetchar; + if c in ['+','-'] then + begin + inc(len); + actasmpattern[len]:=c; + c:=current_scanner.asmgetchar; + end; + while c in ['0'..'9'] do + begin + inc(len); + actasmpattern[len]:=c; + c:=current_scanner.asmgetchar; + end; + end; + actasmpattern[0]:=chr(len); + if is_float then + actasmtoken:=AS_REALNUM + else + actasmtoken:=AS_INTNUM; + end; + '"': + begin + actasmpattern:=''; + repeat + c:=current_scanner.asmgetchar; + case c of + '\' : + begin + c:=current_scanner.asmgetchar; + case c of + 't': + begin + actasmpattern:=actasmpattern+#9; + c:=current_scanner.asmgetchar; + end; + 'n': + begin + actasmpattern:=actasmpattern+#10; + c:=current_scanner.asmgetchar; + end; + 'r': + begin + actasmpattern:=actasmpattern+#13; + c:=current_scanner.asmgetchar; + end; + '"': + begin + actasmpattern:=actasmpattern+'"'; + c:=current_scanner.asmgetchar; + end; + '''': + begin + actasmpattern:=actasmpattern+''''; + c:=current_scanner.asmgetchar; + end; + '\': + begin + actasmpattern:=actasmpattern+'\'; + c:=current_scanner.asmgetchar; + end; + 'u': + begin + tmpS:=''; + c:=current_scanner.asmgetchar; + while c in ['0'..'9','a'..'f','A'..'F'] do + begin + tmpS:=tmpS+c; + c:=current_scanner.asmgetchar; + end; + if tmpS<>'' then + begin + Val('$'+tmpS,tmpI,tmpCode); + if (tmpI<$D800) or ((tmpI>=$E000) and (tmpI<$110000)) then + begin + if tmpI<=$7F then + actasmpattern:=actasmpattern+Chr(tmpI) + else if tmpI<=$7FF then + actasmpattern:=actasmpattern+ + Chr(%11000000 or (tmpI shr 6))+ + Chr(%10000000 or (tmpI and $3F)) + else if tmpI<=$FFFF then + actasmpattern:=actasmpattern+ + Chr(%11100000 or (tmpI shr 12))+ + Chr(%10000000 or ((tmpI shr 6) and $3F))+ + Chr(%10000000 or (tmpI and $3F)) + else + actasmpattern:=actasmpattern+ + Chr(%11110000 or (tmpI shr 18))+ + Chr(%10000000 or ((tmpI shr 12) and $3F))+ + Chr(%10000000 or ((tmpI shr 6) and $3F))+ + Chr(%10000000 or (tmpI and $3F)) + end + else + Message1(asmr_e_escape_seq_ignored,'u'+tmpS); + end + else + Message1(asmr_e_escape_seq_ignored,'u'); + end; + '0'..'9','a'..'f','A'..'F': + begin + tmpS:=c; + c:=current_scanner.asmgetchar; + if c in ['0'..'9','a'..'f','A'..'F'] then + begin + tmpS:=tmpS+c; + c:=current_scanner.asmgetchar; + Val('$'+tmpS,tmpI,tmpCode); + actasmpattern:=actasmpattern+Chr(tmpI); + end + else + begin + Message1(asmr_e_escape_seq_ignored,tmpS+c); + c:=current_scanner.asmgetchar; + end; + end; + else + begin + Message1(asmr_e_escape_seq_ignored,c); + c:=current_scanner.asmgetchar; + end; + end; + end; + '"' : + begin + c:=current_scanner.asmgetchar; + break; + end; + #10,#13: + Message(scan_f_string_exceeds_line); + #0..#9,#11,#12,#14..#31,#127: + current_scanner.illegal_char(c); + else + actasmpattern:=actasmpattern+c; + end; + until false; + actasmtoken:=AS_STRING; + exit; + end; + else + current_scanner.illegal_char(c); + end; + end; + + + function twasmreader.consume(t: tasmtoken): boolean; + begin + Consume:=true; + if t<>actasmtoken then + begin + Message2(scan_f_syn_expected,token2str[t],token2str[actasmtoken]); + Consume:=false; + end; + repeat + gettoken; + until actasmtoken<>AS_NONE; + end; + + + function twasmreader.is_asmopcode(const s: string): boolean; + begin + actopcode:=tasmop(PtrUInt(iasmops.Find(s))); + if actopcode<>A_NONE then + begin + actasmtoken:=AS_OPCODE; + is_asmopcode:=true; + end + else + is_asmopcode:=false; + end; + + + function twasmreader.Assemble: tlinkedlist; + begin + Message1(asmr_d_start_reading,'WebAssembly'); + firsttoken:=TRUE; + { sets up all opcode and register tables in uppercase } + if not _asmsorted then + begin + SetupTables; + _asmsorted:=TRUE; + end; + curlist:=TAsmList.Create; + + { we might need to know which parameters are passed in registers } + if not parse_generic then + current_procinfo.generate_parameter_info; + + { start tokenizer } + gettoken; + { main loop } + repeat + Writeln(actasmtoken); + case actasmtoken of + AS_END: + break; { end assembly block } + else + begin + Consume(actasmtoken); + //Message(asmr_e_syntax_error); + //RecoverConsume(false); + end; + end; + until false; + + { Return the list in an asmnode } + assemble:=curlist; + Message1(asmr_d_finish_reading,'WebAssembly'); + end; + + +{***************************************************************************** + Initialize +*****************************************************************************} + +const + asmmode_wasm_standard_info : tasmmodeinfo = + ( + id : asmmode_standard; + idtxt : 'STANDARD'; + casmreader : twasmreader; + ); + +initialization + RegisterAsmMode(asmmode_wasm_standard_info); +end.