unit Pas2JavaSc; { TAnsiCalculateに#Pas2JavaScを追加する #P2Js の行以後に対して 機械的な置換を行う ,begin , { ,end , } 対応していない事 ・Type JavaScriptがそもそも変数に型が無いから ・ポインタや参照演算子の類 ・関数内関数 動作の安定の為にある程度処理はしてるが ・for文の変数には毎回letを付けてしまう 等 let付けの怪しさ やってくれる事 ・exit javaにはない pascalは関数の終了なので returnか return Resultに置換 ・関数の先頭で let Result; 最後に return Result追加 ・'文字列'#13のような文字列を "文字列\r" と置換 ・inc(a)を++aに置換 inc(a,3)をa+=3に置換 ・setlength(a,3)をa.length=3に置換 length(a)をa.lengthに置換 ・piをMath.PI 他Mathにありそうな関数は Math.を付け小文字にする ・ln()をMath.log()に置換 (他にも名前が違う場合もあるだろうけど調査不足) ・sqr(x)を2乗sqr(x)に置換するので自分で2乗に修正すること例 (x)**2 のように ・変数名を最初に使った名前に大文字小文字を固定する ・$abcのような数を 0xabcと置換 ・if while for 文を置換 ・procedure をfunctionに置換 ・var const の型名を削除 ・関数内のvar定義を消して 利用時にletを付けまくる(無駄な分は自分で修正して下さい) ・AND OR XOR NOT 等の & | ^ 置換(ビット演算子としてるので論理型なら自分で修正) ・:=を= =を== <>を!= ・コメント"{〜}"を/*〜*/に置換 } //,"{.J}hoge{bom}", bom ,最初に見つけた{}コメントと入れ変える.hogeもbomも何も解釈しない //,"{.J}hoge{} ", ,JavaScriptには出力しない //,"{.J{hoge} ", hoge ,JavaScriptにだけ出力する //,"{.o}foo(hoge,", hoge.foo( ,オブジェクト用で 第一引数のメソッドにする //,"{.r}'hoge' ", hoge ,正規表現用でブラケットを外す(''''には対応していない\x27 を使う事 ) //,"{.E}〜{.e} ", ,出力禁止{.e}が無ければ終端まで#P2Jsの5文字も{.e}と同様の効果がある //,"{.a} ", ,直後の変数 Object.assign({},変数)と置換 //,"{.V} ", ,以後let constをvarとして出力する //,"{.v} ", ,直後のローカル変数定義をvarで出力する //,"{.L} ", ,直後の not and or を ! && || //,"{.B} ", ,直後の not and or を ^ & | /////ファイルモード // ファイルモードでは#P2Jsの5文字がファイル中にある場合に処理し、次の行より処理を始める // ファイルモードでは{#P2Js} や//#P2Jsのように行頭から始まらなくてもよいが大文字小文字は区別する interface uses Windows, SysUtils , CalcAnsiScript , uAnsiCharTools ; type TLabelD = record s: string; t: Integer end; AString = array of TLabelD; TOnTextOut = procedure(s: AnsiString) of object; TOnCMD = procedure(var p: PChar) of object; const //labelMdの内容 lbUse = 1; lbConst = 2; lbInFunc = 4; //ローカル変数 lbBool = 8; //論理型 lbFunc = 16; //メソッドメンバ lbCntM = 128; //この値をネストが深くなると加算し、浅くなると減じる lbLet = 1 shl 30; //ローカル変数 の宣言未だ type TPasRec = record name: string; //record/class名 labels: AString; //定義されるラベル end; TAPasRec = array of TPasRec; TpasMode = //関数宣言は関数内で処理するので (pasExt //初期状態 , pasVar //Var 宣言中 , pasConst //Const宣言中 , pasInFunc //関数内ブロック , pasType //Type宣言中 //そのまま出力する ); TuPas2JavaSc = class(TObject) //一つの関数にしても良いけど private tagConst: string; tagLET: string; endp: PChar; //処理する文字列の終端のアドレス fDebug: boolean; consOutDebug: boolean; isProc: boolean; //関数内かprocedure内か isLogic: boolean; // ロジックモード and or not を&& || !に finFunc: Boolean; pasMode: TpasMode; LabelCnt: Integer; ResultCnt: Integer; //関数内で何度Resultに代入したか ResultValue: string; //その1回だけの帰り値 RecDatas: TAPasRec; RecData: TPasRec; //メソッドのメンバー類が入っている nestc: Integer; isVarOut: boolean; //関数内変数の直後のラベルを書きだす LabelName: AString; //大文字小文字の間違いを減らすために LastSt: string; msgBufstr: string; inCase: boolean; //case中 CaseInBlock: boolean; //case中にbegin endがあった usedBreak: boolean; //case中でbreakを使った labelBrake: string; //ブレークラベル labelBrakeCnt: Integer; //for while repeatの番目 function isMember(var lab: string): boolean; procedure copyC(var p: PChar); //1文字の src->dst copy function isLet(var s: string): boolean; procedure NestLevel(updn: Integer); //ブロックの深さ function SetLabel(s: string; typ: integer; ref: boolean = false): string; procedure msgBuf(s: string); virtual; //dstへの出力 procedure msgNorm(s: string); virtual; //dstへの出力 procedure SwapMsgBufMd(var MsgFunc: TOnTextOut; var dtMsg: string); //バッファモード切替用 procedure outBreak(); procedure CallLp(cmd: TOnCMD; var p: PChar); //for repeat whileを呼ぶ protected msg: TOnTextOut; function prjCall(var p: PChar; c: TSysCharSet; call: string): string; //msgBufに切り替えて結果を返す function prjBool(var p: PChar; c: TSysCharSet; call: string): string; //論理値を必要とする場面 function LabelSet(lab: string; var p: PChar): boolean; procedure mVar(var p: PChar); procedure mIF(var p: PChar); procedure mFor(var p: PChar); procedure mWhile(var p: PChar); procedure mWith(var p: PChar); procedure mRepeat(var p: PChar); procedure mType(var p: PChar); procedure mFunc(var p: PChar); procedure mBlock(var p: PChar; inCase1: boolean); //begin end block procedure mTry(var p: PChar); procedure mCase(var p: PChar); procedure CmtSkip(var p: PChar; swOut: boolean = true); procedure mCmt(var p: PChar; swOut: boolean = true); //{}コメントと置換タグ procedure moji(var p: PChar); procedure kazu(var p: PChar); procedure mOrd(var p: PChar); function mathFunc(const lab: string; var p: PChar): boolean; function kakko(var p: PChar; tojiru: boolean = true): boolean; procedure Hairetu(var p: PChar); public OnTextOut: TOnTextOut; procedure Exec(var p: PChar); procedure prj(var p: PChar; c: TSysCharSet; call: string); end; TPas2JavaScCalc = class(TCalcuAddition) private OutMsgStr: AnsiString; procedure MsgOut(msg: AnsiString); public // function CallFunc(const lab: AnsiString; Labels: TAMyCalLabel): boolean ;override; // function ExeLabel(const lab: AnsiString; var ret: Extended; cmd: TGetLabelCmd): boolean; override; procedure StartEndScript(n: Integer); override; //0:start 1:end; function LineCmd(const lab: AnsiString; var p: PChar): boolean; override; //#で始まる行コマンド function FileExec(const fname: AnsiString; p: PChar): boolean; override; //ファイルモードで特別な処理がある場合 end; implementation function LabelD(nm: string; typ: Integer): TLabelD; begin Result.s := nm; Result.t := typ or lbUse; end; procedure AddStrArray(var d: AString; add: TLabelD); var n: Integer; begin n := length(d); setlength(d, n + 1); d[n] := add; end; procedure labelIsBool(var d, se: AString); var //dにsの名前のラベルを探してlbBoolを付ける i, j: Integer; begin for j := 0 to High(se) do for i := 0 to High(d) do if SameText(d[i].s, se[j].s) then begin d[i].t := d[i].t or lbBool; end; end; procedure AddRecDatas(var d: TAPasRec; add: TPasRec); var n: Integer; begin n := length(d); setlength(d, n + 1); d[n] := add; end; function SwapFlag(var localf, savef: boolean): boolean; begin Result := savef; savef := localf; localf := Result; end; function startsWith(d, s: string): boolean; begin Result := copy(d, 1, length(s)) = s; end; function startsSame(d, s: string): boolean; begin d := copy(d, 1, length(s)); Result := SameText(s, d); end; { TuPas2JavaSc } procedure TuPas2JavaSc.copyC(var p: PChar); begin if p^ = #0 then begin p := p; exit; end; msg(p^); inc(p); end; function TuPas2JavaSc.prjBool(var p: PChar; c: TSysCharSet; call: string): string; //論理値を必要とする場面 begin isLogic := True; Result := prjCall(p, c, call); end; //cは'C'以外は終了条件 procedure TuPas2JavaSc.prj(var p: PChar; c: TSysCharSet; call: string); var s: string; begin inc(Nestc); if consOutDebug then write('/*<' + call + ',' + IntToStr(Nestc) + '>*/'); if fdebug then msg('/*<' + call + ',' + IntToStr(Nestc) + '>*/'); try while p^ <> #0 do begin if not ('p' in c) then if endp <= p then break; CmtSkip(p); LastSt := p^; case p^ of #0: exit; '<': if p[1] = '>' then begin inc(p, 2); msg('!='); end else if p[1] = '=' then begin inc(p, 2); msg('<='); end else copyC(p); '>': if p[1] = '=' then begin inc(p, 2); msg('>='); end else copyC(p); ':': if p[1] = '=' then begin inc(p, 2); msg('='); end else if ':' in c then exit else copyC(p); '=': begin inc(p); msg('=='); end; '(': kakko(p); ')': if ')' in c then exit else copyC(p); '[': Hairetu(p); ']': if ']' in c then exit else copyC(p); ';': if ';' in c then exit else copyC(p); ',': if ',' in c then exit else copyC(p); '#', '''': if 'a' in c then exit else begin moji(p); if 'A' in c then exit; end; '&', //8進数 '%', //2進数 '$', '0'..'9': if '9' in c then exit else begin kazu(p); if '0' in c then exit; end; '_', 'A'..'Z', 'a'..'z': begin s := CAnsiGetAccordChars(p, LabelCharSet); LastSt := lowercase(s); //to とdowntoの区別の為に if SameText(s, 'procedure') or SameText(s, 'function') then if 'f' in c then exit else begin mFunc(p); if 'F' in c then exit; end else if SameText(s, 'type') then mType(p) else if SameText(s, 'var') then mVar(p) else if SameText(s, 'const') then pasMode := pasConst else if SameText(s, 'begin') then if '{' in c then exit else mBlock(p, 'C' in c) else if SameText(s, 'end') then if '}' in c then exit else begin msg('}'); end else if SameText(s, 'then') then if #255 in c then exit else begin msg('then'); end else if SameText(s, 'else') then if #254 in c then exit else begin msg('else'); end else if SameText(s, 'do') then if #253 in c then exit else begin msg('do'); end else if SameText(s, 'to') then if #252 in c then exit else begin msg('to'); end else if SameText(s, 'downto') then if #252 in c then exit else begin msg('downto'); end else if SameText(s, 'try') then mTry(p) else if SameText(s, 'except') then if #251 in c then exit else begin msg('except'); end else if SameText(s, 'finally') then if #251 in c then exit else begin msg('finally'); end else if SameText(s, 'on') then if #250 in c then exit else begin msg('on'); end else if SameText(s, 'repeat') then CallLp(mRepeat, p) else if SameText(s, 'until') then if #249 in c then exit else begin msg('until'); end else if SameText(s, 'case') then mCase(p) else if SameText(s, 'of') then if #248 in c then exit else begin msg('of'); end else if SameText(s, 'raise') then begin msg('throw'); end else if SameText(s, 'if') then mIF(p) else if SameText(s, 'for') then CallLp(mFor, p) else if SameText(s, 'while') then CallLp(mWhile, p) else if SameText(s, 'with') then mWith(p) else if SameText(s, 'break') then outBreak() else if SameText(s, 'continue') then msg('continue') else if SameText(s, 'exit') then if isProc then msg('return') else begin msg('return Result'); ResultCnt := -2; end else if SameText(s, 'and') then if isLogic then msg('&&') else msg('&') else if SameText(s, 'or') then if isLogic then msg('||') else msg('|') else if SameText(s, 'XOR') then msg('^') else if SameText(s, 'SHL') then msg('<<') else if SameText(s, 'NOT') then if isLogic then msg('!') else msg('~') else if SameText(s, 'DIV') then msg('/') else if SameText(s, 'MOD') then msg('%') else if SameText(s, 'self') then msg('this') else if SameText(s, 'True') then msg('true') else if SameText(s, 'False') then msg('false') else if SameText(s, 'ord') then mOrd(p) else if mathFunc(s, p) then else if LabelSet(s, p) then else ; end; else copyC(p); end; end; finally dec(nestc); end; end; procedure TuPas2JavaSc.Hairetu(var p: PChar); begin if p[0] = '[' then copyC(p); prj(p, [#0, ']'], 'Hairetu'); if p[0] = ']' then copyC(p); end; function TuPas2JavaSc.kakko(var p: PChar; tojiru: boolean): boolean; begin Result := p^ = '('; if Result then begin if tojiru then msg('('); inc(p); end; prj(p, [#0, ')'], 'Kakko'); if p^ = ')' then inc(p); if tojiru then msg(')'); end; function TuPas2JavaSc.isMember(var lab: string): boolean; var i: Integer; begin Result := false; for i := 0 to High(RecData.labels) do if SameText(RecData.labels[i].s, lab) then begin Result := True; lab := RecData.labels[i].s; isLogic := (RecData.labels[i].t and lbBool) <> 0; end; end; procedure TuPas2JavaSc.mVar(var p: PChar); begin pasMode := pasVar; if finFunc then CAnsiSkipBlank(p, true); //関数内の変数設定の改行等を削除する end; function TuPas2JavaSc.LabelSet(lab: string; var p: PChar): boolean; type TAChar2 = array[0..1] of AnsiChar; pA2 = ^TAChar2; var sp: PChar; s, Member, ext: string; buf: AString; begin Result := True; s := lab; sp := p; CAnsiSkipBlank(sp); Member := lab; ext := ''; if sp^ = '.' then begin ext := CAnsiGetAccordChars(sp, LabelCharSet + ['.']); lab := lab + ext; p := sp; CAnsiSkipBlank(sp); end; if pasMode = pasConst then begin if finFunc then SetLabel(lab, lbInFunc or lbConst) else SetLabel(lab, lbConst); msg(tagConst); msg(' '); msg(lab); CAnsiGetNextStr(p, [#0, '=']); //型定義部を外す if p^ = '=' then begin msg(p^); inc(p); end; prj(p, [#0, ';'], 'LabelSet.Const'); exit; end; SetLength(buf, 0); if pasMode = pasVar then begin if finFunc then begin //ローカル変数--------------------- CmtSkip(p, false); if isVarOut then begin msg('var ' + lab + ';'); SetLabel(s, lbInFunc); end else SetLabel(s, lbInFunc or lbLet); AddStrArray(buf, LabelD(s, 0)); isVarOut := false; CmtSkip(p, false); while p^ = ',' do begin inc(p); CmtSkip(p, false); s := CAnsiGetAccordChars(p, LabelCharSet); if isVarOut then begin msg('var ' + lab + ';'); SetLabel(s, lbInFunc); end else SetLabel(s, lbInFunc or lbLet); AddStrArray(buf, LabelD(s, 0)); CmtSkip(p, false); end; if p^ = ':' then begin inc(p); CmtSkip(p); s := CAnsiGetNextStr(p, [#0, ';']); //型定義部を外す if startsSame(s, 'bool') then labelIsBool(LabelName, buf); end; isVarOut := false; if p^ = ';' then inc(p); CAnsiSkipBlank(p, true); exit; end else begin //グローバル変数 --------------------- SetLabel(lab, 0); AddStrArray(buf, LabelD(lab, 0)); msg('var ' + lab); msg(CAnsiGetAccordChars(p, cSpace)); while p^ = ',' do begin inc(p); CmtSkip(p); s := CAnsiGetAccordChars(p, LabelCharSet); SetLabel(s, 0); AddStrArray(buf, LabelD(s, 0)); msg('; var ' + s); CmtSkip(p); end; if p^ = ':' then begin inc(p); CmtSkip(p); s := CAnsiGetNextStr(p, [#0, ';']); //型定義部を外す if startsSame(s, 'bool') then labelIsBool(LabelName, buf); end; if p^ = '=' then begin copyC(p); prj(p, [#0, ';'], 'LabelSet.var'); end; exit; end; end; if (pasMode = pasInFunc) and isMember(Member) then begin msg('this.'); msg(lab); msg(ext); exit; end; if pA2(sp)^ <> ':=' then begin msg(SetLabel(lab, 0, true)); exit; end; p := sp; inc(p, 2); if (ResultCnt >= 0) and SameText(lab, 'Result') then begin inc(ResultCnt); //Resultへの代入が複数あるなら諦める if ResultCnt = 1 then begin ResultValue := prjCall(p, [#0, ';'], 'Result'); if p[0] = ';' then inc(p); exit; end; end; if isLet(lab) then s := tagLET + ' ' else s := ''; s := s + lab + ' ='; msg(s); exit; end; function TuPas2JavaSc.isLet(var s: string): boolean; var i: Integer; begin Result := false; for i := 0 to LabelCnt - 1 do if SameText(s, LabelName[i].s) then begin Result := (LabelName[i].t and lbLet) = lbLet; if Result then begin LabelName[i].t := LabelName[i].t and (lbCntM - 1); // lbCntMより上のビットをクリアする end; s := LabelName[i].s; exit; end; end; function TuPas2JavaSc.SetLabel(s: string; typ: integer; ref: boolean): string; var i: Integer; begin //ToDo:これではローカル変数でグローバル変数が上書きされてしまうぞ for i := 0 to LabelCnt - 1 do if SameText(s, LabelName[i].s) then begin Result := LabelName[i].s; LabelName[i].t := typ or lbUse; if ref then isLogic := (LabelName[i].t and lbBool) <> 0; exit; end; LabelName[LabelCnt].s := s; LabelName[LabelCnt].t := typ or lbUse; inc(LabelCnt); if LabelCnt >= length(LabelName) then begin SetLength(LabelName, length(LabelName) * 2); end; Result := s; end; procedure TuPas2JavaSc.NestLevel(updn: Integer); var i: Integer; begin for i := 0 to LabelCnt - 1 do begin if ((LabelName[i].t and lbInFunc) <> 0) and ((LabelName[i].t and lblet) = 0) then begin LabelName[i].t := LabelName[i].t + updn * lbCntM; end; end; end; procedure TuPas2JavaSc.mOrd(var p: PChar); var pSave: PChar; begin pSave := p; CAnsiSkipBlank(p); if p^ = '(' then begin inc(p); CAnsiSkipBlank(p); if (p[0] = '''') and (p[0] = p[2]) then begin msg(format('/*%s*/0x%2.2x', [p[1], ord(p[1])])); if (p[0] = p[1]) and (p[0] = p[3]) then inc(p, 4) else inc(p, 4); CAnsiSkipBlank(p); if p^ = '(' then inc(p); end else begin kakko(p, false); msg('.codePointAt(0)'); end; exit; end; p := pSave; end; //java mathクラスの処理と間違えそうなsqrの処理 //inc/decを++/-- に置換する function TuPas2JavaSc.mathFunc(const lab: AnsiString; var p: PChar): boolean; const math = 'PI,power,ln,sqr,abs,acos,acosh,asin,atan,atan2,atanh,cbrt,ceil,cos,cosh,exp,floor,hypot,log,log10,log2,max,min,pow,random,round,sign,sin,sinh,sqrt,tan,trunc,'; var s, v: string; n: Integer; sp: PChar; begin sp := p; CAnsiSkipBlank(sp); s := LowerCase(lab); if s = 'pi' then begin Result := True; msg('Math.PI'); exit; end; Result := false; if (s = 'char') then begin if sp^ <> '(' then exit; msg('String.fromCharCode'); Result := true; exit; end; if (s = 'inc') or (s = 'dec') then begin CAnsiSkipBlank(p); if sp^ <> '(' then exit; p := sp + 1; v := CAnsiGetNextStr(p, [#0, ',', ')']); Result := True; v := SetLabel(v, 0); if p^ = ',' then begin inc(p); if s = 'inc' then msg(v + '+=') else msg(v + '-='); prj(p, [#0, ')'], 'f.inc'); if p^ = ')' then inc(p); end else begin if s = 'inc' then msg('++' + v) else msg('--' + v); end; if p^ = ')' then inc(p); exit; end; if (s = 'length') then begin // length ----------------- CAnsiSkipBlank(p); if p^ <> '(' then exit; inc(p); v := CAnsiGetNextStr(p, [#0, ')']); Result := True; v := SetLabel(v, 0); msg(v + '.length'); if p^ = ')' then inc(p); exit; end; if (s = 'setlength') then begin // SetLength ----------------- CAnsiSkipBlank(p); if p^ <> '(' then exit; inc(p); v := CAnsiGetNextStr(p, [#0, ',']); Result := True; if isLet(v) then msg(tagLET + ' ' + v + ';'); msg(v + '.length = '); if p^ = ',' then inc(p); prj(p, [#0, ')'], 'f.Length'); if p^ = ')' then inc(p); exit; end; if (s = 'inttostr') or (s = 'floattostr') then begin if p^ <> '(' then exit; msg('String'); kakko(p); Result := True; exit; end; n := Pos(',' + s + ',', math); Result := false; if n < 1 then begin if sp = '(' then begin Result := True; p := sp; msg(lab); kakko(p); end; exit; end; CAnsiSkipBlank(p); if p^ <> '(' then exit; Result := True; if s = 'power' then msg('Math.pow') else if s = 'ln' then msg('Math.log') else if s = 'sqr' then msg('2乗sqr') else begin s := copy(math, n + 1, 10); n := Pos(',', s); s := copy(s, 1, n - 1); msg('Math.' + s); end; kakko(p); end; //複数行コメントの処理 procedure TuPas2JavaSc.CmtSkip(var p: PChar; swOut: boolean); procedure m(s: AnsiString); begin if swOut then msg(s); end; begin repeat m(CAnsiGetAccordChars(p, cSpace)); case p^ of '/': if p[1] = '/' then begin m(CAnsiGetNextStr(p, [#0, #13, #10])); continue; end; '{': begin mCmt(p); continue; end; '(': if p[1] = '*' then begin mCmt(p); continue; end; else break; end; break; until false; end; procedure TuPas2JavaSc.mCmt(var p: PChar; swOut: boolean); procedure m(s: AnsiString); begin if swOut then msg(s); end; var s: string; ps: PChar; opsiz: Integer; begin opsiz := 4; ps := p; if CAnsiCmpStrs(p, ['(*']) then begin inc(p); opsiz := 5; end; if (p[1] = '.') then //ちょっと手抜き if (((ps[0] = '{') and (p[3] = '}')) or CAnsiCmpStrs(p + 3, ['*)'])) then case p[2] of 'J': begin inc(p, opsiz); if ps[0] = '{' then begin CAnsiGetSplitStr(p, '{'); msg(CAnsiGetSplitStr(p, '}')); end else begin CAnsiGetSplitStr(p, '(*'); msg(CAnsiGetSplitStr(p, '*)')); end; exit; end; 'o': begin inc(p, opsiz); s := CAnsiGetSplitStr(p, '('); msg(prjCall(p, [#0, ','], '{.o}')); if p[0] = ',' then inc(p); msg('.'); msg(s); msg('('); kakko(p); exit; end; 'a': begin inc(p, opsiz); s := CAnsiGetAccordChars(p, LabelCharSet); msg('Object.assign({},'); msg(s); msg(')'); exit; end; 'r': begin inc(p, opsiz); s := p[0]; inc(p); msg(CAnsiGetSplitStr(p, s)); exit; end; 'E': begin inc(p, opsiz); CAnsiFindStrs(p, ['{.e}', '(*.e*)', '']); exit; end; 'V': begin inc(p, opsiz); tagConst := 'var'; tagLET := 'var'; exit; end; 'v': begin inc(p, opsiz); isVarOut := true; exit; end; 'L': begin inc(p, opsiz); isLogic := true; exit; end; 'B': begin inc(p, opsiz); isLogic := false; exit; end; end; m('/*'); inc(p); if ps[0] = '{' then begin m(CAnsiGetNextStr(p, [#0, '}']) + '*/'); if p^ = '}' then inc(p); end else begin m(CAnsiGetSplitStr(p, '*)') + '*/'); end; end; // Typeの処理方法が思いつかないのでそのまま出力 procedure TuPas2JavaSc.mType(var p: PChar); var s, lab, typeName: string; RecData: TPasRec; no: Integer; fEnum: boolean; begin pasMode := pasType; msg('/*type*/'); while not (p^ in [#0]) do begin CmtSkip(p); case p^ of '_', 'A'..'Z', 'a'..'z': begin s := CAnsiGetAccordChars(p, LabelCharSet); if SameText(s, 'procedure') or SameText(s, 'function') then begin pasMode := pasExt; LastSt := lowercase(s); mFunc(p); exit; end else if SameText(s, 'var') then begin pasMode := pasVar; exit; end else if SameText(s, 'type') then msg('type') else if SameText(s, 'const') then begin pasMode := pasConst; exit; end ; msg(CAnsiGetAccordChars(p, cSpace)); if p[0] = '=' then begin typeName := s; inc(p); msg(CAnsiGetAccordChars(p, cSpace)); s := CAnsiGetAccordChars(p, LabelCharSet); if SameText(s, 'procedure') or SameText(s, 'function') then begin msg('/*'); msg(typeName); msg('='); msg(s); msg(CAnsiGetNextStr(p, [#0, #13, #10])); msg('*/'); continue; end; if SameText(s, 'record') or SameText(s, 'class') then begin CAnsiSkip(p, [' ', #9, #13, #10]); if p[0] = '(' then begin inc(p); msg('/*' + CAnsiGetSplitStr(p, ')') + '*/'); end; if p[0] = ';' then begin //事前定義 msg('/*'); msg(typeName); msg('='); msg(s); msg('*/'); inc(p); continue; end; RecData.name := typeName; SetLength(RecData.labels, 0); msg('function ' + typeName + '(){'); while not (p^ in [#0]) do begin CmtSkip(p); case p^ of '_', 'A'..'Z', 'a'..'z': begin s := CAnsiGetAccordChars(p, LabelCharSet); if SameText(s, 'procedure') or SameText(s, 'function') then begin msg(cvU('/*◆function')); msg(CAnsiGetAccordChars(p, cSpace)); s := CAnsiGetAccordChars(p, LabelCharSet); AddStrArray(RecData.labels, LabelD(s, lbFunc)); msg(s); msg(CAnsiGetNextStr(p, [#0, #13, #10])); msg(cvU('◆*/')); continue; end else if SameText(s, 'end') then begin msg(' return this;}'); AddRecDatas(RecDatas, RecData); break; end else if SameText(s, 'private') then msg('/*private*/') else if SameText(s, 'protected') then msg('/*protected*/') else if SameText(s, 'public') then msg('/*public*/') else begin lab := s; msg('this.' + lab); if p^ = ':' then begin //型名は読み飛ばす inc(p); CmtSkip(p); s := CAnsiGetNextStr(p, [#0, ',', ';']); //型定義部を外す if startsSame(s, 'bool') then AddStrArray(RecData.labels, LabelD(lab, lbBool)) else AddStrArray(RecData.labels, LabelD(lab, 0)); if startsSame(s, 'double') or startsSame(s, 'Int') then msg('=0 /*' + s + '*/') else if startsSame(s, 'string') then msg('="" /*' + s + '*/') else if startsSame(s, 'array') then msg('=[] /*' + s + '*/') else msg('/*' + s + '*/') end else if p[0] in [',', ';'] then copyC(p); end; end; else copyC(p); end; end; end else begin // class or record end fEnum := true; if SameText(s, 'set') then begin //set of はコメントアウト msg('/* '); msg(s); msg(CAnsiGetAccordChars(p, cSpace)); s := CAnsiGetAccordChars(p, LabelCharSet); msg(s); //of msg('*/ '); fEnum := false; end else begin msg('/*'); msg(typeName); msg('='); msg(s); msg(CAnsiGetNextStr(p, [#0, ';'])); msg('*/'); if p[0] = ';' then inc(p); continue; end; msg(CAnsiGetAccordChars(p, cSpace)); if p[0] = '(' then begin //列挙型 msg(tagConst); msg(' '); msg(typeName); msg('='); msg('{'); inc(p); no := 0; repeat msg(CAnsiGetAccordChars(p, cSpace)); CmtSkip(p); case p^ of ',': begin msg(','); inc(p); continue; end; ')': begin msg('}'); inc(p); break; ; end; //列挙型終わり '_', 'A'..'Z', 'a'..'z': begin msg(CAnsiGetAccordChars(p, LabelCharSet)); if fEnum then begin msg(':'); msg(IntToStr(no)); inc(no); end else msg(':false'); msg(CAnsiGetAccordChars(p, cSpace)); end; else begin copyC(p); msg(cvU('<◆?')); end; end; until p^ = #0; end; end; end; end; else copyC(p); end; end; end; //関数宣言 引数の型名を外してゆく procedure TuPas2JavaSc.mFunc(var p: PChar); var i, j, n, m, resultBool: Integer; ps: PChar; s, fncName, clsName: string; svIsProc, thisInFunc, thisIsProc, thisIsMe: boolean; SaveLabelName: AString; begin inCase := false; //case中 labelBrakeCnt := 0; //for while repeatの番目 svIsProc := isProc; ResultCnt := -1; thisInFunc := finFunc; thisIsProc := LastSt = 'procedure'; isProc := thisIsProc; finFunc := True; pasMode := pasInFunc; CAnsiSkipBlank(p); s := CAnsiGetAccordChars(p, LabelCharSet); fncName := s; thisIsMe := p^ = '.'; if thisIsMe then begin //メソッドの場合 clsName := s; inc(p); CAnsiSkipBlank(p); fncName := CAnsiGetAccordChars(p, LabelCharSet); n := -1; m := -1; for i := 0 to High(RecDatas) do if SameText(RecDatas[i].name, clsName) then begin n := i; clsName := RecDatas[n].name; //大文字小文字ゆらぎ対策 for j := 0 to High(RecDatas[i].labels) do if SameText(RecDatas[i].labels[j].s, fncName) then m := j; if m < 0 then AddStrArray(RecDatas[i].labels, LabelD(fncName, lbFunc)) else fncName := RecDatas[n].labels[m].s; //大文字小文字ゆらぎ対策 resultBool := RecDatas[n].labels[m].t; //帰り値が論理型か RecData := RecDatas[n]; break; end; if n < 0 then begin RecData.name := clsName; SetLength(RecData.labels, 1); RecData.labels[0] := LabelD(fncName, lbFunc); end; ps := p; if p^ = '(' then inc(p); msg(clsName); msg('.prototype.'); msg(fncName); msg('=function ('); end else begin CAnsiSkipBlank(p); ps := p; if p^ = '(' then inc(p); msg('function '); msg(s); msg('('); end; CAnsiSkipBlank(p); repeat //ループではなくbreakで抜ける為に if ps^ <> '(' then begin msg(') {'#13#10); CAnsiSkipBlank(p); if p^ = ':' then begin //型名は読み飛ばす inc(p); if startsSame(CAnsiGetNextStr(p, [#0, ';']), 'bool') then begin resultBool := resultBool or lbBool; RecDatas[n].labels[m].t := resultBool; end; end; if p^ = ';' then begin // ;は()のないprocedure/functionの終わり inc(p); CAnsiSkipBlank(p, true); end; break; end; while true do begin CmtSkip(p); if p^ = #0 then exit; msg(CAnsiGetAccordChars(p, cSpace)); s := CAnsiGetAccordChars(p, LabelCharSet); CmtSkip(p); if SameText(s, 'var') //これらは読み飛ばす or SameText(s, 'out') or SameText(s, 'const') then begin msg(CAnsiGetAccordChars(p, cSpace)); CmtSkip(p); s := CAnsiGetAccordChars(p, LabelCharSet); CmtSkip(p); end; msg(s); //引数名 SetLabel(s, lbInFunc); if p^ = ':' then begin //型名は読み飛ばす inc(p); CAnsiGetNextStr(p, [#0, ',', ';', ')']); CmtSkip(p); end; if p^ in [',', ';'] then begin msg(','); inc(p); end; if p^ = ')' then begin inc(p); msg(') {'#13#10); CAnsiSkipBlank(p, true); CmtSkip(p); if p^ = ':' then begin //型名は読み飛ばす inc(p); CAnsiSkipBlank(p, true); s := CAnsiGetNextStr(p, [#0, ' ', #9, ';']); CAnsiSkipBlank(p, true); end; if p^ = ';' then inc(p); //;は読み飛ばす CAnsiSkipBlank(p, true); break; end; end; break; until true; repeat finFunc := True; ps := p; s := prjCall(p, [#0, 'f', '{'], 'mFunc.def'); if (LastSt = 'procedure') or (LastSt = 'function') then begin //関数内関数なので p := ps; //巻き戻して finFunc := false; //変数宣言にVAR宣言をさせる prj(p, [#0, '}', 'F'], 'mFunc.In.' + fncName); CAnsiSkipBlank(p, true); if p[0] = ';' then copyC(p); end else begin msg(s); break; end; until false; if (LastSt = 'begin') then begin NestLevel(+1); isProc := thisIsProc; if not thisIsProc then begin ResultCnt := 0; finFunc := false; pasMode := pasInFunc; ps := p; SaveLabelName := LabelName; SetLength(SaveLabelName, length(LabelName)); s := prjCall(p, [#0, '}'], 'function.Code.' + fncName); if ResultCnt = 1 then begin msg(s); msg('return '); msg(ResultValue); msg(';'#13#10'}'); if fDebug then msg(format('/*end %s #(%d)*/', [fncName, nestc])); NestLevel(-1); if thisIsMe then SetLength(RecData.labels, 0); pasMode := pasExt; //関数内ブロックの終了 isProc := svIsProc; exit; end; LabelName := SaveLabelName; p := ps; end; ResultCnt := -1; if not thisIsProc then msg(tagLET + ' Result;'#13#10); //Resultをローカル変数として登録する CAnsiSkipBlank(p, true); if not thisIsProc then SetLabel('Result', lbInFunc or resultBool); finFunc := false; pasMode := pasInFunc; prj(p, [#0, '}'], 'mFunc.Code.' + fncName); if not thisIsProc then msg('return Result;//'#13#10); //Resultを返すのを追加 msg('}'); if fDebug then msg(format('/*end %s #(%d)*/', [fncName, nestc])); NestLevel(-1); if thisIsMe then SetLength(RecData.labels, 0); isProc := svIsProc; pasMode := pasExt; //関数内ブロックの終了 exit; end; isProc := svIsProc; end; procedure TuPas2JavaSc.mBlock(var p: PChar; inCase1: boolean); begin if not inCase1 then begin msg('{'); NestLevel(+1); end; CmtSkip(p); //caseの中のブロックだけ外す prj(p, [#0, '}'], 'mBlock'); if not inCase1 then begin msg('}'); NestLevel(-1); end else begin CmtSkip(p); //case 中のブロックは外せるので外す その場合;が重なるので CaseInBlock := True; end; end; procedure TuPas2JavaSc.SwapMsgBufMd(var MsgFunc: TOnTextOut; var dtMsg: string); var buf: string; svMsgFunc: TOnTextOut; begin buf := dtMsg; SetLength(buf, length(buf)); dtMsg := MsgBufstr; SetLength(dtMsg, length(dtMsg)); MsgBufstr := buf; svMsgFunc := msg; msg := MsgFunc; MsgFunc := svMsgFunc; end; function TuPas2JavaSc.prjCall(var p: PChar; c: TSysCharSet; call: string): string; var MsgFunc: TOnTextOut; saves: string; savedbg: boolean; begin savedbg := fDebug; fDebug := false; MsgFunc := msgBuf; saves := ''; SwapMsgBufMd(MsgFunc, saves); prj(p, c, call); SwapMsgBufMd(MsgFunc, saves); Result := saves; fDebug := savedbg; end; procedure TuPas2JavaSc.CallLp(cmd: TOnCMD; var p: PChar); //for repeat whileを呼ぶ var MsgFunc: TOnTextOut; saves: string; usedBreakSv: boolean; labelBrakeSv: string; begin usedBreakSv := usedBreak; labelBrakeSv := labelBrake; usedBreak := false; //case中でbreakを使った inc(labelBrakeCnt); labelBrake := 'L' + IntToStr(labelBrakeCnt); MsgFunc := msgBuf; saves := ''; SwapMsgBufMd(MsgFunc, saves); cmd(p); SwapMsgBufMd(MsgFunc, saves); if usedBreak then begin msg(labelBrake); msg(':'); end; msg(saves); usedBreak := usedBreakSv; labelBrake := labelBrakeSv; end; procedure TuPas2JavaSc.outBreak(); begin msg('break'); if inCase then begin //case中にあるbreakはbreak labelに変換 msg(' '); msg(labelBrake); usedBreak := true; end; end; procedure TuPas2JavaSc.mCase(var p: PChar); var s: string; q: PChar; inCaseSv: boolean; CaseInBlockSv: boolean; begin inCaseSv := inCase; CaseInBlockSv := CaseInBlock; msg('switch('); CmtSkip(p); prj(p, [#248, '}', #0], 'mCase.of'); // of=#248 msg('){/* case */'); CmtSkip(p); //コメント+空白系の文字をそのまま渡す repeat inCase := false; if p^ = #0 then exit; repeat CmtSkip(p); //コメント+空白系の文字をそのまま渡す s := prjCall(p, [':', ',', #254, '}', #0], 'mCase.tag'); // else=#254 end=} if LastSt = 'end' then begin msg('}/*switch(case) end*/ '); inCase := inCaseSv; CaseInBlock := CaseInBlockSv; exit; end else if LastSt = 'else' then begin msg('default:'); break; end else begin msg('case '); msg(s); msg(':'); end; q := p; if p^ in [',', ':'] then inc(p); until not (q[0] = ','); inCase := True; CaseInBlock := false; prj(p, [#0, ';', 'b', 'C'], 'mCase.code'); //'b'break 'C'begin〜endのブロック解除 inCase := false; if CaseInBlock then if p[0] = ';' then inc(p); if p^ in [';'] then copyC(p); msg('break; '); until p[0] = #0; end; procedure TuPas2JavaSc.mTry(var p: PChar); var m, s: string; begin NestLevel(+1); msg('try {/* */'); prj(p, [#251, #0], 'mTry.In'); //finally か except m := LastSt; if LastSt = 'except' then begin msg('} catch(e){'); // s := prjCall(p, [#0, #254, #250, '}'], 'mTry.catch'); //Else=#54 ON=#250 end=} if (LastSt = 'end') or (p^ = #0) then begin //ONがない msg(s); msg('}'); //end まで NestLevel(-1); exit; end; msg(cvU('/* on は自前で修正してね */)')); msg(s); repeat if (LastSt = 'on') then begin msg(' if (e instanceof /*'); prj(p, [#0, ':'], 'mTry.on'); msg(cvU(' :★要修正*/)')); prj(p, [#0, #253, ';'], 'mTry.do'); //Do=#253 msg(') {'); prj(p, [#0, ';'], 'mTry.doCode'); // end else break; prj(p, [#0, #254, #250, '}'], 'mTry.else'); //Else=#54 ON=#250 end=} if (LastSt = 'on') then begin msg('} else '); // end else if (LastSt = 'else') then begin msg('} else { '); // prj(p, [#0, #254, #250, ';'], 'mTry.elseCode'); //Else=#54 ON=#250 end=} msg('} ; '); // break; end else if (LastSt = 'end') then begin msg('} ; '); // msg('/* ******' + m + ' End********* */}'); //end まで NestLevel(-1); exit; end; until LastSt <> 'on'; end else begin msg('} finally {'); end; prj(p, [#0, '}'], 'mTry.finally'); msg('/*' + m + ' End */}'); //end まで NestLevel(-1); end; procedure TuPas2JavaSc.mIF(var p: PChar); begin msg('if('); msg(prjBool(p, [#0, #255], 'mIF')); //thenまでを返す msg(')'); prj(p, [#0, #254, ';'], 'mIF.then'); //;か #254=else end直前まで if (LastSt = 'else') then begin msg('else'); prj(p, [';', #0], 'mIF.else'); end; end; procedure TuPas2JavaSc.mRepeat(var p: PChar); var ps: PChar; s: string; begin msg('do{ /*repeat*/ '); msg(CAnsiGetAccordChars(p, cSpace)); //空白系の文字をそのまま渡す NestLevel(+1); prj(p, [#0, #249], 'repeat'); //untilまで NestLevel(-1); CAnsiSkipBlank(p, true); s := prjBool(p, [#0, ';'], 'until'); //;までを返す ps := PChar(s); CmtSkipC(ps, cSpace); s := ps; s := trim(s); if SameText(s, 'true') then s := '!false'; if SameText(s, 'false') then s := '!true'; ps := PChar(s); if ps[0] = '!' then begin inc(ps); msg('}while ('); msg(ps); msg(')'); end else begin msg('}while (!('); //論理が逆なので msg(s); msg(cvU('))/*untilはtrueで終了*/')); end; end; procedure TuPas2JavaSc.mWith(var p: PChar); begin msg('with('); prj(p, [#0, #253], 'with'); //doまでを返す msg(')'); prj(p, [#0, ';'], 'with.code'); //end直前まで end; procedure TuPas2JavaSc.mWhile(var p: PChar); //var sp: PChar; begin msg('while('); msg(prjBool(p, [#0, #253], 'while')); //doまでを返す msg(')'); prj(p, [#0, ';'], 'while.code'); //end直前まで // sp := p; // msg(CAnsiGetAccordChars(p, cSpace)); //空白系の文字をそのまま渡す // if sameText(CAnsiGetAccordChars(sp, LabelCharSet), 'begin') then begin // msg('{'); // p := sp; // NestLevel(+1); // prj(p, [#0, '}'], 'while.code'); //end直前まで // msg('}'); // NestLevel(-1); // end; end; {pascal for i=0 to n do for i=n downto m do javaSC for(let i=0;i<=n;i++) for(let i=n;i>=n;i--) } procedure TuPas2JavaSc.mFor(var p: PChar); var isInc: boolean; lab: string; begin msg('for('); CAnsiSkipBlank(p); if p^ in ['_', 'A'..'Z', 'a'..'z'] then begin lab := CAnsiGetAccordChars(p, LabelCharSet); lab := setLabel(lab, lbInFunc); if isLet(lab) then msg(tagLET + ' '); msg(lab); end; prj(p, [#0, #252], 'for.to'); //to/downtoまでを返す isInc := LastSt = 'to'; if isInc then msg(';' + lab + '<=') else msg(';' + lab + '>='); prj(p, [#0, #253], 'for.do'); //doまでを返す if isInc then msg(';' + lab + '++ )') else msg(';' + lab + '-- )'); NestLevel(+1); prj(p, [#0, ';'], 'for.code'); //;までを返す NestLevel(-1); end; { 数値表現の違い , ,Pascal,javaSc , 2進数,%0101 ,0b0101 , 8進数,&0123 ,0o0123 ,16進数,$01aB ,0x01aB 他はほぼ同じなのでそのまま渡せばよい +-符号もそのまま渡せばよいので無視 ただ数値列の範囲を確認する必要がある  数.数E±数 } procedure TuPas2JavaSc.kazu(var p: PChar); var s: string; sp: PChar; begin sp := p; inc(p); case sp^ of '&': s := '0o' + CAnsiGetAccordChars(p, ['0'..'7']); //8進数 '%': s := '0b' + CAnsiGetAccordChars(p, ['0', '1']); //2進数 '$': s := '0X' + CAnsiGetAccordChars(p, ['0'..'9', 'a'..'z', 'A'..'Z']); //16進数 '0'..'9': begin s := sp^ + CAnsiGetAccordChars(p, ['0'..'9']); if p^ = '.' then begin //小数点の後に数字 inc(p); s := s + '.' + CAnsiGetAccordChars(p, ['0'..'9']); end; if p^ in ['e', 'E'] then begin //Eの後に符号 s := s + p^; inc(p); if p^ in ['+', '-'] then begin //Eの後に符号 s := s + p^; inc(p); end; s := s + CAnsiGetAccordChars(p, ['0'..'9']); end; end; end; msg(s); end; { 文字表現の違い Pascal '文字'と(#の後に数字)の連続 ''''で'1文字 javaSc '文字'か"文字"で\\は1文字\ , ,Pascal,javaSc , CR ,#13 ,\r \x0d , LF ,#10 ,\n \x0a ,TAB ,#9 ,\t \x09 ,FEED,#12 ,\f \x0c , ,'' ,\' , ," ,\" , ,\ ,\\ } procedure TuPas2JavaSc.moji(var p: PChar); var s, n: string; c: Integer; begin s := ''; while true do begin if p^ = '#' then begin inc(p); n := CAnsiGetAccordChars(p, ['0'..'9']); if n <> '' then c := StrToInt(n) else c := 0; case c of 9: s := s + '\t'; 10: s := s + '\n'; 13: s := s + '\r'; 12: s := s + '\f'; else s := s + format('\x%2.2x', [c]); end; end else if p^ = '''' then begin inc(p); while not (p^ in [#0, #10..#13]) do if (p[0] = '''') then begin if (p[1] = p[0]) then begin inc(p, 2); s := s + '\'''; end else begin inc(p); break; end; end else if (p[0] = '"') then begin inc(p); s := s + '\"'; end else begin s := s + p[0]; inc(p); end; end else break; end; msg('"'); msg(s); msg('"'); end; procedure TuPas2JavaSc.msgNorm(s: string); begin if Assigned(OnTextOut) then OnTextOut(s); if consOutDebug then write(s); end; procedure TuPas2JavaSc.msgBuf(s: string); begin msgBufStr := addS([msgBufStr, s]); if consOutDebug then write(s); end; procedure TuPas2JavaSc.Exec(var p: PChar); begin if consOutDebug then allocConsole; tagConst := 'const'; tagLET := 'let'; msg := msgNorm; finFunc := False; pasMode := pasExt; LabelCnt := 0; nestc := 0; ResultCnt := -1; SetLength(LabelName, 4096); prj(p, [#0], 'Exec'); end; procedure writeFileStr(fname, s: ansistring); var hin: THandle; rsize: DWORD; begin rsize := 0; hin := CreateFile(pansichar(fname), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if hin <> INVALID_HANDLE_VALUE then try windows.Writefile(hin, pansichar(s)^, Length(s), rsize, nil); finally CloseHandle(hin); end; end; procedure TPas2JavaScCalc.MsgOut(msg: AnsiString); var w, sz: integer; begin w := length(OutMsgStr); sz := length(msg); SetLength(OutMsgStr, w + sz); move(msg[1], OutMsgStr[w + 1], sz); end; function TPas2JavaScCalc.FileExec(const fname: AnsiString; p: PChar): boolean; var s, fil: string; begin Result := CAnsiFindStrs(p, ['#P2Js']); if Result then begin CAnsiSkipBlank(p); fil := ''; if p[0] = '''' then begin inc(p); fil := CAnsiGetSplitStr(p, ''''); CAnsiSkipBlank(p); end; s := CAnsiGetAccordChars(p, LabelCharSet); CAnsiGetNextStr(p, [#0, #13, #10]); // 文字セットのどれか迄の文字列 CAnsiSkip(p, [#13, #10]); with TuPas2JavaSc.Create do try fDebug := SameText(s, 'debug'); consOutDebug := s = 'Debug'; endp := PChar(owner.MyCmd) + length(owner.MyCmd); OnTextOut := MsgOut; Exec(p); finally free end; if fil <> '' then begin writeFileStr(fil, OutMsgStr); end else begin owner.MsgOut(OutMsgStr); end; end; end; function TPas2JavaScCalc.LineCmd(const lab: AnsiString; var p: PChar): boolean; var s: string; begin Result := False; if SameText(lab, 'h') or (lab = '') then //helpの時は処理してもfalseを返す begin owner.MsgOutLn(cvU( '#P2Js の行以後に対して 機械的な置換を行う'#13#10 + '# コンソールモードでは1行単位に解釈されるので動作しない'#13#10 + '')); end; if not SameText(lab, 'P2Js') then exit; CAnsiSkipBlank(p); s := CAnsiGetAccordChars(p, LabelCharSet); CAnsiGetNextStr(p, [#0, #13, #10]); // 文字セットのどれか迄の文字列 CAnsiSkip(p, [#13, #10]); with TuPas2JavaSc.Create do try fDebug := SameText(s, 'debug'); endp := PChar(owner.MyCmd) + length(owner.MyCmd); OnTextOut := owner.MsgOut; Exec(p); finally free end; end; procedure TPas2JavaScCalc.StartEndScript(n: Integer); begin case n of //0:start 1:end; 0: begin end; 1: begin end; end; end; initialization CalcAddTCalcuAddition(TPas2JavaScCalc); end.