├── TokyoScript.png ├── lib ├── TokyoScript.BuiltIn.pas ├── TokyoScript.Chars.pas ├── TokyoScript.Compiler.pas ├── TokyoScript.Keywords.pas ├── TokyoScript.Parser.pas └── TokyoScript.Runtime.pas ├── readme.md └── src ├── Demo1.pas ├── Demo2.pas ├── Demo3.pas ├── Demos.rc ├── TokyoScript.Main.dfm ├── TokyoScript.Main.pas ├── TokyoScript.dpr └── TokyoScript.dproj /TokyoScript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/TokyoScript/41c3b657bc5adf058de8ff3132f0b9513dcd3b12/TokyoScript.png -------------------------------------------------------------------------------- /lib/TokyoScript.BuiltIn.pas: -------------------------------------------------------------------------------- 1 | unit TokyoScript.BuiltIn; 2 | { 3 | 4 | TokyoScript (c)2018 Execute SARL 5 | http://www.execute.Fr 6 | 7 | } 8 | 9 | interface 10 | 11 | uses 12 | System.SysUtils; 13 | 14 | type 15 | TBuiltIn = ( 16 | bi_None, 17 | biWrite, 18 | biWriteLn, 19 | biInc 20 | ); 21 | 22 | const 23 | BUILTINS : array[TBuiltIn] of string = ( 24 | '', 25 | 'WRITE', 26 | 'WRITELN', 27 | 'INC' 28 | ); 29 | 30 | function GetBuiltIn(Str: string): TBuiltIn; 31 | 32 | implementation 33 | 34 | function GetBuiltIn(Str: string): TBuiltIn; 35 | begin 36 | Str := UpperCase(Str); 37 | Result := High(TBuiltIn); 38 | while Result > bi_None do 39 | begin 40 | if BUILTINS[Result] = Str then 41 | Exit; 42 | Dec(Result); 43 | end; 44 | end; 45 | 46 | end. 47 | -------------------------------------------------------------------------------- /lib/TokyoScript.Chars.pas: -------------------------------------------------------------------------------- 1 | unit TokyoScript.Chars; 2 | { 3 | 4 | TokyoScript (c)2018 Execute SARL 5 | http://www.execute.Fr 6 | 7 | } 8 | interface 9 | 10 | type 11 | TCharType = ( 12 | // Char to CharType 13 | ctNull, // 0 14 | ctBinary, // 1..8, 11..12, 14..31 15 | ctPadding, // 9, ' ' 16 | ctLineFeed, // 10 17 | ctReturn, // 13 18 | ctDigit, // '0'..'9' 19 | ctAlpha, // 'a'..'z', 'A'..'Z', '_' 20 | ctExclamat, // '!' 21 | ctDoubleQuote, // '"' 22 | ctSharp, // '#' 23 | ctDollar, // '$' 24 | ctPercent, // '%' 25 | ctAmpersand, // '&' 26 | ctSimpleQuote, // ' 27 | ctLParent, // '(' 28 | ctRParent, // ')' 29 | ctStar, // '*' 30 | ctPlus, // '+' 31 | ctComma, // ',' 32 | ctMinus, // '-' 33 | ctDot, // '.' 34 | ctSlash, // '/' 35 | ctColon, // ':' 36 | ctSemiColon, // ';' 37 | ctLT, // '<' 38 | ctEQ, // '=' 39 | ctGT, // '>' 40 | ctQuestion, // '?' 41 | ctAt, // '@' 42 | ctLBracket, // '[' 43 | ctBackSlash, // '\' 44 | ctRBracket, // ']' 45 | ctPower, // '^' 46 | ctGrave, // '`' 47 | ctLBrace, // '{' 48 | ctPipe, // '|' 49 | ctRBrace, // '}' 50 | ctTilde, // '~' 51 | 52 | ctAnsi, // > 127 53 | ctUnicode, // > 255 54 | 55 | // more types 56 | ctNone, 57 | ctAssign, // ':=' 58 | ctGE, // '>=' 59 | ctLE, // '<=' 60 | ctNE, // '<>' 61 | ctRange, // '..' 62 | ctIdent, // ctApha + [ctAlpha|dtDigits]* 63 | ctKeyword, 64 | ctChar, // #[$]123 65 | ctHexa, // $xxx 66 | ctNumber, // 123 67 | ctReal, // 1.23 68 | ctString // 'hello' 69 | ); 70 | 71 | TCharTypes = set of TCharType; 72 | 73 | function GetCharType(c: Char): TCharType; 74 | 75 | implementation 76 | 77 | const 78 | CHARTYPES : array[#0..#126] of TCharType = ( 79 | ctNull, // 0 80 | ctBinary, ctBinary, ctBinary, ctBinary, // 1..8 81 | ctBinary, ctBinary, ctBinary, ctBinary, 82 | ctPadding, // 9 83 | ctLineFeed, // 10 84 | ctBinary, ctBinary, // 11, 12 85 | ctReturn, // 13 86 | ctBinary, ctBinary, ctBinary, ctBinary, ctBinary, ctBinary, // 14..31 87 | ctBinary, ctBinary, ctBinary, ctBinary, ctBinary, ctBinary, 88 | ctBinary, ctBinary, ctBinary, ctBinary, ctBinary, ctBinary, 89 | ctPadding, // 32 90 | ctExclamat, // ! 91 | ctDoubleQuote, // " 92 | ctSharp, // # 93 | ctDollar, // $ 94 | ctPercent, // % 95 | ctAmpersand, // & 96 | ctSimpleQuote, // ' 97 | ctLParent, // ( 98 | ctRParent, // ) 99 | ctStar, // * 100 | ctPlus, // + 101 | ctComma, // , 102 | ctMinus, // - 103 | ctDot, // . 104 | ctSlash, // / 105 | ctDigit, ctDigit, ctDigit, ctDigit, ctDigit, // 0..9 106 | ctDigit, ctDigit, ctDigit, ctDigit, ctDigit, 107 | ctColon, // : 108 | ctSemiColon, // ; 109 | ctLT, // < 110 | ctEQ, // = 111 | ctGT, // > 112 | ctQuestion, // ? 113 | ctAt, // @ 114 | ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, // A .. Z 115 | ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, 116 | ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, 117 | ctLBracket, // [ 118 | ctBackSlash, // \ 119 | ctRBracket, // ] 120 | ctPower, // ^ 121 | ctAlpha, // _ 122 | ctGrave, // ` = Chr(96) 123 | ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, // a .. z 124 | ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, 125 | ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, ctAlpha, 126 | ctLBrace, // { 127 | ctPipe, // | 128 | ctRBrace, // } 129 | ctTilde // ~ 130 | // 127 = DEL 131 | ); 132 | 133 | function GetCharType(c: Char): TCharType; 134 | begin 135 | if Ord(c) > 255 then 136 | Exit(ctUnicode); 137 | if Ord(c) > 126 then 138 | Exit(ctAnsi); 139 | Result := CHARTYPES[c]; 140 | end; 141 | 142 | end. 143 | -------------------------------------------------------------------------------- /lib/TokyoScript.Compiler.pas: -------------------------------------------------------------------------------- 1 | unit TokyoScript.Compiler; 2 | { 3 | 4 | TokyoScript (c)2018 Execute SARL 5 | http://www.execute.Fr 6 | 7 | } 8 | 9 | interface 10 | 11 | uses 12 | System.Classes, 13 | System.SysUtils, 14 | TokyoScript.Runtime, 15 | TokyoScript.Chars, 16 | TokyoScript.Parser, 17 | TokyoScript.Keywords, 18 | TokyoScript.BuiltIn; 19 | 20 | type 21 | TSymbolKind = ( 22 | // const 23 | skString, 24 | skNumber, 25 | // ident 26 | skProgramName, 27 | skVariableName, 28 | skTypeName 29 | ); 30 | 31 | TSystemType = ( 32 | stInteger, 33 | stString 34 | ); 35 | 36 | TSymbol = class; 37 | 38 | TTypeDef = class 39 | Base: TSystemType; 40 | end; 41 | 42 | TTypeRef = class 43 | Symbol : TSymbol; // can be null 44 | TypeDef: TTypeDef; 45 | end; 46 | 47 | TSymbol = class 48 | Name : string; 49 | Kind : TSymbolKind; 50 | TypeRef : TTypeRef; // TypeRef.Symbol = Self 51 | end; 52 | 53 | TStatementKind = ( 54 | skNop, 55 | skLoadInt, 56 | skLoadStr, 57 | skLabel, 58 | skGoto, 59 | skJumpiEQ, 60 | skJumpTrue, 61 | skAssign, 62 | skiIncr, 63 | skIMul, 64 | skiLT, 65 | skConcat, 66 | skWriteInt, 67 | skWriteStr 68 | ); 69 | 70 | TRegister = class 71 | Symbol : TSymbol; 72 | TypeDef : TTypeDef; 73 | end; 74 | 75 | TStatement = class 76 | Kind : TStatementKind; 77 | Param1: TRegister; 78 | Param2: TRegister; 79 | Param3: TRegister; 80 | Addr : TStatement; 81 | Ofs : Integer; 82 | Symbol: TSymbol; 83 | end; 84 | 85 | TCodeSection = class 86 | // parent/child for Scope resolution 87 | Parent : TCodeSection; 88 | Childs : TList; 89 | // local symbols 90 | Symbols : TList; 91 | // required symbols 92 | Needs : TList; 93 | // params & vars 94 | Registers : TList; 95 | // code 96 | Labels : TList; 97 | CodeSize : Integer; 98 | Statements: TList; 99 | constructor Create(AParent: TCodeSection); 100 | destructor Destroy; override; 101 | function NewSymbol: TSymbol; 102 | function NewRegister: TRegister; 103 | function NewStatement(Size: Integer): TStatement; 104 | function LoadSymbol(Symbol: TSymbol): TRegister; 105 | procedure LoadRegSymbol(Load: TStatementKind; Reg: TRegister); 106 | function GetLabel: TStatement; 107 | procedure IncReg(Reg: TRegister); 108 | procedure Clear; 109 | end; 110 | 111 | TLogEvent = procedure(Sender: TObject; const Msg: string) of object; 112 | 113 | TOperation = function(Reg1, Reg2: TRegister): TRegister of object; 114 | 115 | TCompiler = class 116 | private 117 | FOnLog : TLogEvent; 118 | FParser : TParser; 119 | FMain : TCodeSection; 120 | FCode : TCodeSection; 121 | FInteger : TSymbol; 122 | FString : TSymbol; 123 | FValues : TList; 124 | // Gabarge Collector 125 | FGarbage : TList; 126 | // todo 127 | FByteCode: TByteCode; 128 | procedure Log(const Msg: string); 129 | function Expression: TRegister; 130 | function Expression1: TRegister; 131 | function Expression2: TRegister; 132 | function Expression3: TRegister; 133 | function IdentExpression: TRegister; 134 | function GetLiteral: TSymbol; 135 | function GetString(const Value: string): TSymbol; 136 | function GetNumber: TSymbol; 137 | function OpAdd(R1, R2: TRegister): TRegister; 138 | function OpMult(R1, R2: TRegister): TRegister; 139 | function OpLT(R1, R2: TRegister): TRegister; 140 | procedure SetReg(Target, Value: TRegister); 141 | procedure FreeReg(R: TRegister); 142 | function GoLabel(L: TStatement): TStatement; 143 | function WriteStr(R: TRegister): TStatement; 144 | function WriteInt(R: TRegister): TStatement; 145 | function GetJumpiEQ(R1, R2: TRegister): TStatement; 146 | function GetJumpTrue(R: TRegister): TStatement; 147 | function AddSymbol(const AName: string): TSymbol; 148 | function AddTypeDef(BaseType: TSystemType): TTypeDef; 149 | function AddTypeRef(TypeDef: TTypeDef): TTypeRef; 150 | function SystemType(const AName: string; BaseType: TSystemType): TSymbol; 151 | procedure Variables; 152 | function Variable: TSymbol; 153 | function GetSymbol: TSymbol; 154 | function GetLocalVar: TSymbol; 155 | function GetLocalVarReg: TRegister; 156 | function GetTypeRef: TTypeRef; 157 | procedure WriteStatement(Ln: Boolean); 158 | procedure IncStatement(); 159 | procedure Statement; 160 | procedure Statements; 161 | procedure IdentStatement; 162 | procedure VariableStatement(Variable: TSymbol); 163 | procedure KeywordStatement; 164 | procedure ForStatement; 165 | procedure WhileStatement; 166 | procedure Clear; 167 | procedure WriteCodeB(var Ofs: Integer; Value: Byte); 168 | procedure WriteCodeW(var Ofs: Integer; Value: Word); 169 | procedure WriteCodeL(var Ofs: Integer; Value: Integer); 170 | procedure WriteCodeV(var Ofs: Integer; Value: Integer); 171 | procedure WriteCodeR(var Ofs: Integer; Reg: TRegister); 172 | procedure WriteCodeOpV(var Ofs: Integer; OpCode: TOpCode; Value: Integer); 173 | procedure WriteCodeOpR(var Ofs: Integer; OpCode: TOpCode; Reg: TRegister); 174 | procedure WriteCodeOpRV(var Ofs: Integer; OpCode: TOpCode; Reg: TRegister; Value: Integer); 175 | procedure WriteCodeOpRR(var Ofs: Integer; OpCode: TOpCode; Reg1, Reg2: TRegister); 176 | procedure WriteCodeOpRRV(var Ofs: Integer; OpCode: TOpCode; Reg1, Reg2: TRegister; Value: Integer); 177 | procedure WriteCodeOpRRR(var Ofs: Integer; OpCode: TOpCode; Reg1, Reg2, Reg3: TRegister); 178 | procedure GenCode(Code: TCodeSection); 179 | procedure GenByteCode; 180 | public 181 | constructor Create; 182 | destructor Destroy; override; 183 | procedure Compile(Lines: TStrings); 184 | property ByteCode: TByteCode read FByteCode; 185 | property OnLog: TLogEvent read FOnLog write FOnLog; 186 | end; 187 | 188 | implementation 189 | 190 | procedure ClearList(List: TList); 191 | var 192 | Index: Integer; 193 | begin 194 | for Index := 0 to List.Count - 1 do 195 | TObject(List[Index]).Free; 196 | List.Clear; 197 | end; 198 | 199 | const 200 | OP_R = 1 + 4; 201 | OP_V = 1 + 4; 202 | OP_RR = 1 + 4 + 4; 203 | OP_RV = 1 + 4 + 4; 204 | OP_RRV = 1 + 4 + 4 + 4; 205 | OP_RRR = 1 + 4 + 4 + 4; 206 | 207 | { TCodeSection } 208 | 209 | constructor TCodeSection.Create(AParent: TCodeSection); 210 | begin 211 | inherited Create; 212 | Parent := AParent; 213 | Childs := TList.Create; 214 | Symbols := TList.Create; 215 | Needs := TList.Create; 216 | Labels := TList.Create; 217 | Statements := TList.Create; 218 | Registers := TList.Create; 219 | if Parent <> nil then 220 | Parent.Childs.Add(Self); 221 | end; 222 | 223 | destructor TCodeSection.Destroy; 224 | begin 225 | Clear; 226 | Labels.Free; 227 | Registers.Free; 228 | Statements.Free; 229 | Needs.Free; 230 | Childs.Free; 231 | Symbols.Free; 232 | inherited; 233 | end; 234 | 235 | function TCodeSection.GetLabel: TStatement; 236 | begin 237 | Result := NewStatement(0); 238 | Result.Kind := skLabel; 239 | Labels.Add(Result); 240 | end; 241 | 242 | procedure TCodeSection.IncReg(Reg: TRegister); 243 | var 244 | S: TStatement; 245 | begin 246 | S := NewStatement(OP_R); 247 | S.Kind := skiIncr; 248 | S.Param1 := Reg; 249 | end; 250 | 251 | function TCodeSection.LoadSymbol(Symbol: TSymbol): TRegister; 252 | var 253 | Index: Integer; 254 | begin 255 | for Index := 0 to Registers.Count - 1 do 256 | begin 257 | Result := Registers[Index]; 258 | if Result.Symbol = Symbol then 259 | Exit; 260 | end; 261 | Result := NewRegister; 262 | Result.Symbol := Symbol; 263 | Result.TypeDef := Symbol.TypeRef.TypeDef; 264 | end; 265 | 266 | procedure TCodeSection.LoadRegSymbol(Load: TStatementKind; Reg: TRegister); 267 | var 268 | S: TStatement; 269 | begin 270 | S := NewStatement(OP_RV); 271 | S.Kind := Load; 272 | S.Param1 := Reg; 273 | S.Symbol := Reg.Symbol; 274 | end; 275 | 276 | function TCodeSection.NewRegister: TRegister; 277 | begin 278 | Result := TRegister.Create; 279 | Registers.Add(Result); 280 | end; 281 | 282 | function TCodeSection.NewStatement(Size: Integer): TStatement; 283 | begin 284 | Result := TStatement.Create; 285 | Result.Ofs := CodeSize; 286 | Inc(CodeSize, Size); 287 | Statements.Add(Result); 288 | end; 289 | 290 | function TCodeSection.NewSymbol: TSymbol; 291 | begin 292 | Result := TSymbol.Create; 293 | Symbols.Add(Result); 294 | end; 295 | 296 | procedure TCodeSection.Clear; 297 | begin 298 | ClearList(Childs); 299 | ClearList(Statements); 300 | ClearList(Symbols); 301 | ClearList(Registers); 302 | Labels.Clear; 303 | end; 304 | 305 | { TCompiler } 306 | 307 | constructor TCompiler.Create; 308 | begin 309 | inherited; 310 | FByteCode := TByteCode.Create; 311 | FValues := TList.Create; 312 | FMain := TCodeSection.Create(nil); 313 | FGarbage := TList.Create; 314 | end; 315 | 316 | destructor TCompiler.Destroy; 317 | begin 318 | Clear; 319 | FMain.Free; 320 | FValues.Free; 321 | FByteCode.Free; 322 | FGarbage.Free; 323 | inherited; 324 | end; 325 | 326 | function TCompiler.Expression: TRegister; 327 | var 328 | op: TOperation; 329 | begin 330 | Result := Expression1; 331 | case FParser.CharType of 332 | ctLT: op := OpLT; 333 | // ctEQ: ; 334 | // ctGT: ; 335 | // ctGE: ; 336 | // ctLE: ; 337 | // ctNE: ; 338 | else 339 | Exit; 340 | end; 341 | FParser.Next(); 342 | Result := op(Result, Expression1); 343 | end; 344 | 345 | function TCompiler.Expression1: TRegister; 346 | var 347 | op: TOperation; 348 | begin 349 | Result := Expression2; 350 | case FParser.CharType of 351 | ctStar : op := OpMult; 352 | else 353 | Exit; 354 | end; 355 | FParser.Next(); 356 | Result := op(Result, Expression2); 357 | end; 358 | 359 | function TCompiler.Expression2: TRegister; 360 | var 361 | op: TOperation; 362 | begin 363 | Result := Expression3; 364 | case FParser.CharType of 365 | ctPlus: op := OpAdd; 366 | else 367 | Exit; 368 | end; 369 | FParser.Next(); 370 | Result := op(Result, Expression3); 371 | end; 372 | 373 | function TCompiler.Expression3: TRegister; 374 | begin 375 | case FParser.CharType of 376 | ctString: 377 | begin 378 | Result := FCode.LoadSymbol(GetLiteral); 379 | FCode.LoadRegSymbol(skLoadStr, Result); 380 | end; 381 | ctNumber: 382 | begin 383 | Result := FCode.NewRegister; 384 | Result.Symbol := GetNumber; 385 | Result.TypeDef := Result.Symbol.TypeRef.TypeDef; 386 | FCode.LoadRegSymbol(skLoadInt, Result); 387 | end; 388 | ctIdent: Result := IdentExpression; 389 | else 390 | Result := nil; 391 | FParser.Error('Unknown expression'); 392 | end; 393 | end; 394 | 395 | function TCompiler.IdentExpression: TRegister; 396 | var 397 | Symbol: TSymbol; 398 | begin 399 | Symbol := GetSymbol; 400 | case Symbol.Kind of 401 | // skString: ; 402 | // skNumber: ; 403 | // skProgramName: ; 404 | skVariableName: Result := FCode.LoadSymbol(Symbol); 405 | // skTypeName: ; 406 | else 407 | Result := nil; 408 | FParser.Error('Unexpected symbol'); 409 | end; 410 | end; 411 | 412 | function TCompiler.GetLiteral: TSymbol; 413 | begin 414 | Result := GetString(FParser.Literal); 415 | FParser.Next(); 416 | end; 417 | 418 | function TCompiler.GetString(const Value: string): TSymbol; 419 | var 420 | Index: Integer; 421 | begin 422 | for Index := 0 to FValues.Count - 1 do 423 | begin 424 | Result := FValues[Index]; 425 | if (Result.Kind = skString) and (Result.Name = Value) then 426 | Exit; 427 | end; 428 | Result := TSymbol.Create; 429 | FValues.Add(Result); 430 | Result.Name := Value; 431 | Result.Kind := skString; 432 | Result.TypeRef := FString.TypeRef; 433 | end; 434 | 435 | function TCompiler.GetSymbol: TSymbol; 436 | var 437 | Name : string; 438 | Code : TCodeSection; 439 | Index : Integer; 440 | begin 441 | Name := FParser.Token; 442 | Code := FCode; 443 | for Index := Code.Symbols.Count - 1 downto 0 do 444 | begin 445 | Result := Code.Symbols[Index]; 446 | if SameText(Result.Name, Name) then 447 | begin 448 | FParser.Next(); 449 | Exit; 450 | end; 451 | end; 452 | Result := nil; 453 | FParser.Error('Unknown ident "' + Name + '"'); 454 | end; 455 | 456 | function TCompiler.GetNumber: TSymbol; 457 | var 458 | Value: string; 459 | Index: Integer; 460 | begin 461 | Value := FParser.Token; 462 | FParser.Next(); 463 | for Index := 0 to FValues.Count - 1 do 464 | begin 465 | Result := FValues[Index]; 466 | if (Result.Kind = skNumber) and (Result.Name = Value) then 467 | Exit; 468 | end; 469 | Result := TSymbol.Create; 470 | FValues.Add(Result); 471 | Result.Name := Value; 472 | Result.Kind := skNumber; 473 | Result.TypeRef := FInteger.TypeRef; 474 | end; 475 | 476 | procedure TCompiler.ForStatement; 477 | var 478 | R : TRegister; 479 | T : TRegister; 480 | J : TStatement; 481 | L : TStatement; 482 | begin 483 | R := GetLocalVarReg; 484 | Log('for ' + R.Symbol.Name); 485 | FParser.DropCharType(ctAssign); 486 | SetReg(R, Expression); 487 | FParser.DropKeyword(kwTo); 488 | T := Expression; 489 | FParser.DropKeyword(kwDo); 490 | L := FCode.GetLabel; 491 | J := GetJumpiEQ(R, T); 492 | Statement; 493 | FCode.IncReg(R); 494 | GoLabel(L); 495 | J.Addr := FCode.GetLabel; 496 | FreeReg(T); 497 | FreeReg(R); 498 | end; 499 | 500 | procedure TCompiler.WhileStatement; 501 | var 502 | L: TStatement; 503 | J: TStatement; 504 | E: TStatement; 505 | begin 506 | L := FCode.GetLabel; 507 | J := GetJumpTrue(Expression); 508 | E := GoLabel(nil); 509 | J.Addr := FCode.GetLabel; 510 | FParser.DropKeyword(kwDo); 511 | Statement; 512 | GoLabel(L); 513 | E.Addr := FCode.GetLabel; 514 | end; 515 | 516 | procedure TCompiler.FreeReg(R: TRegister); 517 | begin 518 | // todo 519 | end; 520 | 521 | procedure TCompiler.GenByteCode; 522 | var 523 | Index : Integer; 524 | Count : Integer; 525 | Symbol: TSymbol; 526 | begin 527 | // Strings 528 | Count := 0; 529 | for Index := 0 to FValues.Count - 1 do 530 | begin 531 | Symbol := FValues[Index]; 532 | if Symbol.TypeRef = FString.TypeRef then 533 | begin 534 | if Index > Count then 535 | begin 536 | FValues[Index] := FValues[Count]; 537 | FValues[Count] := Symbol; 538 | end; 539 | Inc(Count); 540 | end; 541 | end; 542 | if FParser.AppType = APPTYPE_CONSOLE then 543 | FByteCode.Flags := FLAG_CONSOLE; 544 | SetLength(FByteCode.Strings, Count); 545 | for Index := 0 to Count - 1 do 546 | begin 547 | Symbol := FValues[Index]; 548 | FByteCode.Strings[Index] := Symbol.Name; 549 | end; 550 | SetLength(FByteCode.Values, FValues.Count - Count); 551 | for Index := Count to FValues.Count - 1 do 552 | begin 553 | Symbol := FValues[Index]; 554 | FByteCode.Values[Index - Count] := StrToInt(Symbol.Name); 555 | end; 556 | // Code 557 | GenCode(FMain); 558 | end; 559 | 560 | procedure TCompiler.WriteCodeB(var Ofs: Integer; Value: Byte); 561 | begin 562 | Move(Value, FByteCode.Code[Ofs], 1); 563 | Inc(Ofs, 1); 564 | end; 565 | 566 | procedure TCompiler.WriteCodeW(var Ofs: Integer; Value: Word); 567 | begin 568 | Move(Value, FByteCode.Code[Ofs], 2); 569 | Inc(Ofs, 2); 570 | end; 571 | 572 | procedure TCompiler.WriteCodeL(var Ofs: Integer; Value: Integer); 573 | begin 574 | Move(Value, FByteCode.Code[Ofs], 4); 575 | Inc(Ofs, 4); 576 | end; 577 | 578 | procedure TCompiler.WriteCodeR(var Ofs: Integer; Reg: TRegister); 579 | begin 580 | WriteCodeV(Ofs, FCode.Registers.IndexOf(Reg)); 581 | end; 582 | 583 | procedure TCompiler.WriteCodeV(var Ofs: Integer; Value: Integer); 584 | begin 585 | Assert(Value >= 0); 586 | if Value < 254 then 587 | WriteCodeB(Ofs, Value) 588 | else 589 | if Value <= $FFFF then 590 | begin 591 | WriteCodeB(Ofs, 254); 592 | WriteCodeW(Ofs, Value); 593 | end else begin 594 | WriteCodeB(Ofs, 255); 595 | WriteCodeL(Ofs, Value); 596 | end; 597 | end; 598 | 599 | procedure TCompiler.WriteCodeOpV(var Ofs: Integer; OpCode: TOpCode; Value: Integer); 600 | begin 601 | WriteCodeB(Ofs, Ord(OpCode)); 602 | WriteCodeV(Ofs, Value); 603 | end; 604 | 605 | procedure TCompiler.WriteCodeOpR(var Ofs: Integer; OpCode: TOpCode; Reg: TRegister); 606 | begin 607 | WriteCodeB(Ofs, Ord(OpCode)); 608 | WriteCodeR(Ofs, Reg); 609 | end; 610 | 611 | procedure TCompiler.WriteCodeOpRV(var Ofs: Integer; OpCode: TOpCode; Reg: TRegister; Value: Integer); 612 | begin 613 | WriteCodeOpR(Ofs, OpCode, Reg); 614 | WriteCodeV(Ofs, Value); 615 | end; 616 | 617 | procedure TCompiler.WriteCodeOpRR(var Ofs: Integer; OpCode: TOpCode; Reg1, Reg2: TRegister); 618 | begin 619 | WriteCodeOpR(Ofs, OpCode, Reg1); 620 | WriteCodeR(Ofs, Reg2); 621 | end; 622 | 623 | procedure TCompiler.WriteCodeOpRRV(var Ofs: Integer; OpCode: TOpCode; Reg1, Reg2: TRegister; Value: Integer); 624 | begin 625 | WriteCodeOpRR(Ofs, OpCode, Reg1, Reg2); 626 | WriteCodeV(Ofs, Value); 627 | end; 628 | 629 | procedure TCompiler.WriteCodeOpRRR(var Ofs: Integer; OpCode: TOpCode; Reg1, Reg2, Reg3: TRegister); 630 | begin 631 | WriteCodeOpRR(Ofs, OpCode, Reg1, Reg2); 632 | WriteCodeR(Ofs, Reg3); 633 | end; 634 | 635 | procedure TCompiler.GenCode(Code: TCodeSection); 636 | var 637 | Index: Integer; 638 | CodeLen: Integer; 639 | CodePos: Integer; 640 | SizePos: Integer; 641 | Statement: TStatement; 642 | begin 643 | for Index := 0 to Code.Childs.Count - 1 do 644 | GenCode(TCodeSection(Code.Childs[Index])); 645 | 646 | CodePos := Length(FByteCode.Code); 647 | 648 | if Code = FMain then 649 | FByteCode.Start := CodePos; 650 | 651 | CodeLen := 1 // Code Format 652 | + 4 // RegCount 653 | + 4 // LabelCount 654 | + 4 // CodeLen 655 | + Code.CodeSize 656 | + 1 // opReturn 657 | + Code.Labels.Count * 4; 658 | 659 | SetLength(FByteCode.Code, CodePos + CodeLen); 660 | 661 | // CodeFormat 662 | WriteCodeB(CodePos, 1); 663 | 664 | // RegCount 665 | WriteCodeV(CodePos, Code.Registers.Count); 666 | 667 | // Labels 668 | WriteCodeV(CodePos, Code.Labels.Count); 669 | 670 | // Code 671 | SizePos := CodePos; 672 | WriteCodeL(CodePos, Code.CodeSize + 1); // + opReturn 673 | 674 | FCode := Code; 675 | CodeLen := CodePos; 676 | for Index := 0 to Code.Statements.Count - 1 do 677 | begin 678 | Statement := Code.Statements[Index]; 679 | Assert(CodePos <= Statement.Ofs + CodeLen); 680 | Statement.Ofs := CodePos; 681 | case Statement.Kind of 682 | skNop : ; 683 | skLoadInt : WriteCodeOpRV(CodePos, opLoadInt, Statement.Param1, FValues.IndexOf(Statement.Symbol) - Length(FByteCode.Strings)); 684 | skLoadStr : WriteCodeOpRV(CodePos, opLoadStr, Statement.Param1, FValues.IndexOf(Statement.Symbol)); 685 | skLabel : ; 686 | skGoto : WriteCodeOpV(CodePos, opGotoLabel, Code.Labels.IndexOf(Statement.Addr)); 687 | skJumpiEQ : WriteCodeOpRRV(CodePos, opJumpiEQ, Statement.Param1, Statement.Param2, Code.Labels.IndexOf(Statement.Addr)); 688 | skJumpTrue: WriteCodeOpRV(CodePos, opJumpTrue, Statement.Param1, Code.Labels.IndexOf(Statement.Addr)); 689 | skAssign : WriteCodeOpRR(CodePos, opAssign, Statement.Param1, Statement.Param2); 690 | skiIncr : WriteCodeOpR(CodePos, opiIncr, Statement.Param1); 691 | skiLT : WriteCodeOpRRR(CodePos, opiLT, Statement.Param1, Statement.Param2, Statement.Param3); 692 | skIMul : WriteCodeOpRR(CodePos, opIMul, Statement.Param1, Statement.Param2); 693 | skConcat : WriteCodeOpRR(CodePos, opConcat, Statement.Param1, Statement.Param2); 694 | skWriteInt: WriteCodeOpV(CodePos, opWriteInt, Code.Registers.IndexOf(Statement.Param1)); 695 | skWriteStr: WriteCodeOpV(CodePos, opWriteStr, Code.Registers.IndexOf(Statement.Param1)); 696 | else 697 | raise Exception.Create('Unsupported statement'); 698 | end; 699 | end; 700 | WriteCodeB(CodePos, Ord(opReturn)); 701 | 702 | WriteCodeL(SizePos, CodePos); 703 | for Index := 0 to Code.Labels.Count - 1 do 704 | begin 705 | WriteCodeV(CodePos, TStatement(Code.Labels[Index]).Ofs); 706 | end; 707 | 708 | SetLength(FByteCode.Code, CodePos); 709 | end; 710 | 711 | function TCompiler.GetJumpiEQ(R1, R2: TRegister): TStatement; 712 | begin 713 | Result := FCode.NewStatement(OP_RRV); 714 | Result.Kind := skJumpiEQ; 715 | Result.Param1 := R1; 716 | Result.Param2 := R2; 717 | end; 718 | 719 | function TCompiler.GetJumpTrue(R: TRegister): TStatement; 720 | begin 721 | Result := FCode.NewStatement(OP_RV); 722 | Result.Kind := skJumpTrue; 723 | Result.Param1 := R; 724 | end; 725 | 726 | function TCompiler.GetLocalVar: TSymbol; 727 | var 728 | Name : string; 729 | Index : Integer; 730 | Symbol: TSymbol; 731 | begin 732 | Name := FParser.GetIdent; 733 | for Index := FCode.Symbols.Count - 1 downto 0 do 734 | begin 735 | Symbol := FCode.Symbols[Index]; 736 | if SameText(Symbol.Name, Name) then 737 | begin 738 | if Symbol.Kind <> TSymbolKind.skVariableName then 739 | Break; 740 | FCode.Needs.Add(Symbol); 741 | Exit(Symbol); 742 | end; 743 | end; 744 | Result := nil; 745 | FParser.Error('Not a local variable'); 746 | end; 747 | 748 | function TCompiler.GetLocalVarReg: TRegister; 749 | var 750 | V: TSymbol; 751 | I: Integer; 752 | begin 753 | V := GetLocalVar; 754 | for I := 0 to FCode.Registers.Count - 1 do 755 | begin 756 | Result := FCode.Registers[I]; 757 | if Result.Symbol = V then 758 | Exit; 759 | end; 760 | Result := FCode.NewRegister; 761 | Result.Symbol := V; 762 | Result.TypeDef := V.TypeRef.TypeDef; 763 | end; 764 | 765 | function TCompiler.GetTypeRef: TTypeRef; 766 | var 767 | Symbol: TSymbol; 768 | begin 769 | Symbol := GetSymbol; 770 | if Symbol.Kind <> TSymbolKind.skTypeName then 771 | FParser.Error('Not a type name'); 772 | Result := Symbol.TypeRef; 773 | end; 774 | 775 | function TCompiler.GoLabel(L: TStatement): TStatement; 776 | begin 777 | Result := FCode.NewStatement(OP_V); 778 | Result.Kind := skGoto; 779 | Result.Addr := L; 780 | end; 781 | 782 | procedure TCompiler.IdentStatement; 783 | var 784 | Symbol: TSymbol; 785 | begin 786 | case GetBuiltIn(FParser.Token) of 787 | biWrite : WriteStatement(False); 788 | biWriteLn: WriteStatement(True); 789 | biInc : IncStatement(); 790 | else 791 | Symbol := GetSymbol; 792 | case Symbol.Kind of 793 | skString : FParser.Error('Unexpected string'); 794 | skNumber : FParser.Error('Unexpected number'); 795 | skProgramName : FParser.Error('Unsupported syntax'); 796 | skVariableName: VariableStatement(Symbol); 797 | skTypeName : FParser.Error('Unsupported syntax'); 798 | end; 799 | end; 800 | end; 801 | 802 | procedure TCompiler.IncStatement; 803 | begin 804 | FParser.Next(); 805 | FParser.DropChar('('); 806 | FCode.IncReg(Expression); 807 | FParser.DropChar(')'); 808 | end; 809 | 810 | procedure TCompiler.Statements; 811 | begin 812 | while not FParser.SkipKeyword(kwEnd) do 813 | begin 814 | Statement; 815 | if FParser.Keyword <> kwEnd then 816 | FParser.SemiColon; 817 | end; 818 | end; 819 | 820 | procedure TCompiler.KeywordStatement; 821 | begin 822 | case FParser.SkipKeywords([kwBegin, kwFor, kwWhile]) of 823 | kwBegin: Statements; 824 | kwFor : ForStatement; 825 | kwWhile: WhileStatement; 826 | else 827 | FParser.Error('Unexpected keyword "' + FParser.Token + '"'); 828 | end; 829 | end; 830 | 831 | procedure TCompiler.Log(const Msg: string); 832 | begin 833 | if Assigned(FOnLog) then 834 | FOnLog(Self, Msg); 835 | end; 836 | 837 | function TCompiler.OpAdd(R1, R2: TRegister): TRegister; 838 | var 839 | S: TStatement; 840 | begin 841 | S := FCode.NewStatement(OP_RR); 842 | S.Kind := skConcat; 843 | S.Param1 := R1; 844 | S.Param2 := R2; 845 | Result := R1; 846 | end; 847 | 848 | function TCompiler.OpMult(R1, R2: TRegister): TRegister; 849 | var 850 | S: TStatement; 851 | begin 852 | S := FCode.NewStatement(OP_RR); 853 | S.Kind := skIMul; 854 | S.Param1 := R1; 855 | S.Param2 := R2; 856 | Result := R1; 857 | end; 858 | 859 | function TCompiler.OpLT(R1, R2: TRegister): TRegister; 860 | var 861 | S: TStatement; 862 | begin 863 | Result := FCode.NewRegister; 864 | S := FCode.NewStatement(OP_RRR); 865 | S.Kind := skiLT; 866 | S.Param1 := R1; 867 | S.Param2 := R2; 868 | S.Param3 := Result; 869 | end; 870 | 871 | procedure TCompiler.SetReg(Target, Value: TRegister); 872 | var 873 | S: TStatement; 874 | begin 875 | S := FCode.NewStatement(OP_RR); 876 | S.Kind := skAssign; 877 | S.Param1 := Target; 878 | S.Param2 := Value; 879 | end; 880 | 881 | procedure TCompiler.Statement; 882 | begin 883 | case FParser.CharType of 884 | ctIdent : IdentStatement; 885 | ctKeyword: KeywordStatement; 886 | else 887 | FParser.Error('Unknow statement'); 888 | end; 889 | end; 890 | 891 | function TCompiler.SystemType(const AName: string; BaseType: TSystemType): TSymbol; 892 | begin 893 | Result := AddSymbol(AName); 894 | Result.Kind := skTypeName; 895 | Result.TypeRef := AddTypeRef(AddTypeDef(BaseType)); 896 | Result.TypeRef.Symbol := Result; 897 | end; 898 | 899 | function TCompiler.Variable: TSymbol; 900 | var 901 | Next : TSymbol; 902 | begin 903 | Result := AddSymbol(FParser.GetIdent); 904 | Log('var ' + Result.Name); 905 | Result.Kind := TSymbolKind.skVariableName; 906 | if FParser.SkipChar(',') then 907 | begin 908 | Next := Variable(); 909 | Result.TypeRef := Next.TypeRef; 910 | end else begin 911 | FParser.DropChar(':'); 912 | Result.TypeRef := GetTypeRef; 913 | end; 914 | end; 915 | 916 | procedure TCompiler.Variables; 917 | begin 918 | repeat 919 | Variable(); 920 | until FParser.CharType <> ctIdent; 921 | FParser.SemiColon; 922 | end; 923 | 924 | procedure TCompiler.VariableStatement(Variable: TSymbol); 925 | var 926 | V: TRegister; 927 | begin 928 | FParser.DropCharType(ctAssign); 929 | V := FCode.LoadSymbol(Variable); 930 | SetReg(V, Expression); 931 | end; 932 | 933 | procedure TCompiler.WriteStatement(Ln: Boolean); 934 | var 935 | e: TRegister; 936 | begin 937 | FParser.Next(); 938 | if FParser.SkipChar('(') then 939 | begin 940 | while not FParser.SkipChar(')') do 941 | begin 942 | e := Expression; 943 | if e.TypeDef = FString.TypeRef.TypeDef then 944 | WriteStr(e) 945 | else 946 | if e.TypeDef = FInteger.TypeRef.TypeDef then 947 | WriteInt(e) 948 | else 949 | FParser.Error('Can''t write this expression'); 950 | if FParser.CharType <> ctRParent then 951 | FParser.DropChar(','); 952 | end; 953 | end; 954 | if Ln then 955 | begin 956 | e := FCode.LoadSymbol(GetString(#13#10)); 957 | FCode.LoadRegSymbol(skLoadStr, e); 958 | WriteStr(e); 959 | end; 960 | end; 961 | 962 | function TCompiler.WriteStr(R: TRegister): TStatement; 963 | begin 964 | Result := FCode.NewStatement(OP_R); 965 | Result.Kind := skWriteStr; 966 | Result.Param1 := R; 967 | end; 968 | 969 | function TCompiler.WriteInt(R: TRegister): TStatement; 970 | begin 971 | Result := FCode.NewStatement(OP_R); 972 | Result.Kind := skWriteInt; 973 | Result.Param1 := R; 974 | end; 975 | 976 | function TCompiler.AddSymbol(const AName: string): TSymbol; 977 | begin 978 | Result := TSymbol.Create; 979 | Result.Name := AName; 980 | FCode.Symbols.Add(Result); 981 | end; 982 | 983 | function TCompiler.AddTypeDef(BaseType: TSystemType): TTypeDef; 984 | begin 985 | Result := TTypeDef.Create; 986 | Result.Base := BaseType; 987 | FGarbage.Add(Result); 988 | end; 989 | 990 | function TCompiler.AddTypeRef(TypeDef: TTypeDef): TTypeRef; 991 | begin 992 | Result := TTypeRef.Create; 993 | Result.TypeDef := TypeDef; 994 | FGarbage.Add(Result); 995 | end; 996 | 997 | procedure TCompiler.Clear; 998 | begin 999 | FByteCode.Clear; 1000 | FMain.Clear; 1001 | ClearList(FValues); 1002 | ClearList(FGarbage); 1003 | end; 1004 | 1005 | procedure TCompiler.Compile(Lines: TStrings); 1006 | begin 1007 | Log('Start'); 1008 | Clear; 1009 | FParser.Init(Lines.Text); 1010 | // Code 1011 | FCode := FMain; 1012 | FInteger := SystemType('Integer', stInteger); 1013 | FString := SystemType('String', stString); 1014 | // program ; 1015 | FParser.DropKeyword(kwProgram); 1016 | Log('Program ' + FParser.Token); 1017 | AddSymbol(FParser.GetIdent); 1018 | FParser.DropChar(';'); 1019 | while not FParser.SkipKeyword(kwBegin) do 1020 | begin 1021 | case FParser.SkipKeywords([kwVar]) of 1022 | kwVar: Variables(); 1023 | else 1024 | FParser.Error('Unexpected token'); 1025 | end; 1026 | end; 1027 | // begin 1028 | Statements; 1029 | // end. 1030 | if FParser.Token <> '.' then 1031 | raise Exception.Create('Final dot expected'); 1032 | // ByteCode 1033 | GenByteCode; 1034 | end; 1035 | 1036 | end. 1037 | -------------------------------------------------------------------------------- /lib/TokyoScript.Keywords.pas: -------------------------------------------------------------------------------- 1 | unit TokyoScript.Keywords; 2 | { 3 | 4 | TokyoScript (c)2018 Execute SARL 5 | http://www.execute.Fr 6 | 7 | } 8 | 9 | interface 10 | 11 | uses 12 | System.SysUtils; 13 | 14 | type 15 | TKeyword = ( 16 | kw_None, 17 | kwAnd, 18 | kwArray, 19 | kwAs, 20 | kwBegin, 21 | kwCase, 22 | kwChr, 23 | kwClass, 24 | kwConst, 25 | kwConstructor, 26 | kwDestructor, 27 | kwDiv, 28 | kwDo, 29 | kwDownto, 30 | kwElse, 31 | kwEnd, 32 | kwExcept, 33 | kwExit, 34 | kwExport, 35 | kwExternal, 36 | kwFinalization, 37 | kwFinally, 38 | kwFor, 39 | kwForward, 40 | kwFunction, 41 | kwGoto, 42 | kwIf, 43 | kwImplementation, 44 | kwIn, 45 | kwInherited, 46 | kwInitialization, 47 | kwInterface, 48 | kwIs, 49 | kwLabel, 50 | kwMod, 51 | kwNil, 52 | kwNot, 53 | kwOf, 54 | kwOr, 55 | kwOrd, 56 | kwOut, 57 | kwOverride, 58 | kwPrivate, 59 | kwProcedure, 60 | kwProgram, 61 | kwProperty, 62 | kwProtected, 63 | kwPublic, 64 | kwPublished, 65 | kwRecord, 66 | kwRepeat, 67 | kwSet, 68 | kwShl, 69 | kwShr, 70 | kwThen, 71 | kwTo, 72 | kwTry, 73 | kwType, 74 | kwUnit, 75 | kwUntil, 76 | kwUses, 77 | kwVar, 78 | kwVirtual, 79 | kwWhile, 80 | kwWith, 81 | kwXor 82 | ); 83 | TKeywords = set of TKeyword; 84 | 85 | const 86 | KEYWORDS: array[TKeyword] of string = ( 87 | '', 88 | 'AND', 89 | 'ARRAY', 90 | 'AS', 91 | 'BEGIN', 92 | 'CASE', 93 | 'CHR', 94 | 'CLASS', 95 | 'CONST', 96 | 'CONSTRUCTOR', 97 | 'DESTRUCTOR', 98 | 'DIV', 99 | 'DO', 100 | 'DOWNTO', 101 | 'ELSE', 102 | 'END', 103 | 'EXCEPT', 104 | 'EXIT', 105 | 'EXPORT', 106 | 'EXTERNAL', 107 | 'FINALIZATION', 108 | 'FINALLY', 109 | 'FOR', 110 | 'FORWARD', 111 | 'FUNCTION', 112 | 'GOTO', 113 | 'IF', 114 | 'IMPLEMENTATION', 115 | 'IN', 116 | 'INHERITED', 117 | 'INITIALIZATION', 118 | 'INTERFACE', 119 | 'IS', 120 | 'LABEL', 121 | 'MOD', 122 | 'NIL', 123 | 'NOT', 124 | 'OF', 125 | 'OR', 126 | 'ORD', 127 | 'OUT', 128 | 'OVERRIDE', 129 | 'PRIVATE', 130 | 'PROCEDURE', 131 | 'PROGRAM', 132 | 'PROPERTY', 133 | 'PROTECTED', 134 | 'PUBLIC', 135 | 'PUBLISHED', 136 | 'RECORD', 137 | 'REPEAT', 138 | 'SET', 139 | 'SHL', 140 | 'SHR', 141 | 'THEN', 142 | 'TO', 143 | 'TRY', 144 | 'TYPE', 145 | 'UNIT', 146 | 'UNTIL', 147 | 'USES', 148 | 'VAR', 149 | 'VIRTUAL', 150 | 'WHILE', 151 | 'WITH', 152 | 'XOR' 153 | ); 154 | 155 | function GetKeyword(Str: string): TKeyword; 156 | 157 | implementation 158 | 159 | const 160 | KW2: array[0..7] of TKeyword = ( 161 | kwAs, 162 | kwDo, 163 | kwIf, 164 | kwIn, 165 | kwIs, 166 | kwOf, 167 | kwOr, 168 | kwTo 169 | ); 170 | KW3: array[0..17] of TKeyword = ( 171 | kwAnd, 172 | kwChr, 173 | kwDiv, 174 | kwEnd, 175 | kwFor, 176 | kwMod, 177 | kwSet, 178 | kwVar, 179 | kwNil, 180 | kwNot, 181 | kwOrd, 182 | kwOut, 183 | kwSet, 184 | kwShl, 185 | kwShr, 186 | kwTry, 187 | kwVar, 188 | kwXor 189 | ); 190 | KW4: array[0..8] of TKeyword = ( 191 | kwCase, 192 | kwElse, 193 | kwExit, 194 | kwGoto, 195 | kwThen, 196 | kwType, 197 | kwUnit, 198 | kwUses, 199 | kwWith 200 | ); 201 | KW5: array[0..6] of TKeyword = ( 202 | kwArray, 203 | kwBegin, 204 | kwClass, 205 | kwConst, 206 | kwLabel, 207 | kwUntil, 208 | kwWhile 209 | ); 210 | KW6: array[0..5] of TKeyword = ( 211 | kwDownto, 212 | kwExcept, 213 | kwExport, 214 | kwPublic, 215 | kwRecord, 216 | kwRepeat 217 | ); 218 | KW7: array[0..4] of TKeyword = ( 219 | kwFinally, 220 | kwForward, 221 | kwPrivate, 222 | kwProgram, 223 | kwVirtual 224 | ); 225 | KW8: array[0..3] of TKeyword = ( 226 | kwExternal, 227 | kwFunction, 228 | kwOverride, 229 | kwProperty 230 | ); 231 | KW9: array[0..4] of TKeyword = ( 232 | kwInherited, 233 | kwInterface, 234 | kwProcedure, 235 | kwProtected, 236 | kwPublished 237 | ); 238 | KW10: array[0..0] of TKeyword = ( 239 | kwDestructor 240 | ); 241 | KW11: array[0..0] of TKeyword = ( 242 | kwConstructor 243 | ); 244 | KW12: array[0..0] of TKeyword = ( 245 | kwFinalization 246 | ); 247 | KW14: array[0..1] of TKeyword = ( 248 | kwImplementation, 249 | kwInitialization 250 | ); 251 | 252 | function IsKeyword(const AKeywords: array of TKeyword; const AStr: string): TKeyword; 253 | var 254 | Index: Integer; 255 | begin 256 | for Index := 0 to Length(AKeywords) - 1 do 257 | begin 258 | Result := AKeywords[Index]; 259 | if KEYWORDS[Result] = AStr then 260 | Exit; 261 | end; 262 | Result := kw_None; 263 | end; 264 | 265 | function GetKeyword(Str: string): TKeyword; 266 | var 267 | Index: Integer; 268 | begin 269 | Str := UpperCase(Str); 270 | case Length(Str) of 271 | 2 : Result := IsKeyword(KW2, Str); 272 | 3 : Result := IsKeyword(KW3, Str); 273 | 4 : Result := IsKeyword(KW4, Str); 274 | 5 : Result := IsKeyword(KW5, Str); 275 | 6 : Result := IsKeyword(KW6, Str); 276 | 7 : Result := IsKeyword(KW7, Str); 277 | 8 : Result := IsKeyword(KW8, Str); 278 | 9 : Result := IsKeyword(KW9, Str); 279 | 10 : Result := IsKeyword(KW10, Str); 280 | 11 : Result := IsKeyword(KW11, Str); 281 | 12 : Result := IsKeyword(KW12, Str); 282 | 14 : Result := IsKeyword(KW14, Str); 283 | else 284 | Result := kw_None; 285 | end; 286 | end; 287 | 288 | end. 289 | -------------------------------------------------------------------------------- /lib/TokyoScript.Parser.pas: -------------------------------------------------------------------------------- 1 | unit TokyoScript.Parser; 2 | { 3 | 4 | TokyoScript (c)2018 Execute SARL 5 | http://www.execute.Fr 6 | 7 | } 8 | interface 9 | 10 | uses 11 | System.SysUtils, 12 | TokyoScript.Chars, 13 | TokyoScript.Keywords; 14 | 15 | type 16 | TDefine = class 17 | Value: string; 18 | Next : TDefine; 19 | end; 20 | 21 | TAppType = ( 22 | APPTYPE_GUI, // default 23 | APPTYPE_CONSOLE 24 | ); 25 | 26 | ESourceError = class(Exception) 27 | Row: Integer; 28 | Col: Integer; 29 | constructor Create(const Msg: string; ARow, ACol: Integer); 30 | end; 31 | 32 | TParser = record 33 | private 34 | FDefines: TDefine; 35 | FSource : string; 36 | FIndex : Integer; 37 | FRow : Integer; 38 | FLine : Integer; 39 | FStart : Integer; 40 | FAppType: TAppType; 41 | FLiteral: string; 42 | function GetCol: Integer; 43 | procedure Blanks; 44 | function NextChar: Char; 45 | function ReadChar: Char; 46 | function GetString(var At: Integer): string; 47 | procedure Comment1; 48 | function Comment2: Boolean; 49 | function LineComment: Boolean; 50 | procedure Directive(Start: Integer); 51 | function IsDirective(Start: Integer; const AName: string): Boolean; 52 | function GetAppType(Start: Integer): TAppType; 53 | function AddChar(AChar: Char): Boolean; 54 | procedure AddChars(CharTypes: TCharTypes); 55 | function Match(AChar: Char; AType: TCharType): Boolean; 56 | procedure ParseIdent; 57 | procedure ParseNumber; 58 | function GetChar(Start, Base: Integer): Char; 59 | procedure ParseChar; 60 | procedure ParseHexa; 61 | procedure ParseString; 62 | public 63 | CharType: TCharType; 64 | Keyword: TKeyword; 65 | function Token: string; 66 | procedure Init(const Str: string); 67 | procedure Error(const Msg: string); 68 | procedure Next(); 69 | procedure Define(const Value: string); 70 | procedure Undef(const Value: string); 71 | function IsDef(const Value: string): Boolean; 72 | function SkipChar(AChar: Char): Boolean; 73 | procedure DropChar(AChar: Char); 74 | procedure DropCharType(ACharType: TCharType); 75 | function SkipKeyword(AKeyword: TKeyword): Boolean; 76 | procedure DropKeyword(AKeyword: TKeyword); 77 | function SkipKeywords(AKeywords: TKeywords): TKeyword; 78 | function GetIdent: string; 79 | procedure SemiColon; inline; 80 | procedure Clear; 81 | property Position: Integer read FStart; 82 | property Row: Integer read FRow; 83 | property Col: Integer read GetCol; 84 | property Literal: string read FLiteral; 85 | property AppType: TAppType read FAppType; 86 | end; 87 | 88 | implementation 89 | 90 | { TParser } 91 | 92 | procedure TParser.Clear; 93 | var 94 | Define: TDefine; 95 | begin 96 | if FSource = '' then 97 | begin 98 | FDefines := nil; 99 | end else begin 100 | FSource := ''; 101 | while FDefines <> nil do 102 | begin 103 | Define := FDefines; 104 | FDefines := Define.Next; 105 | Define.Free; 106 | end; 107 | end; 108 | end; 109 | 110 | procedure TParser.Comment1; 111 | var 112 | Start: Integer; 113 | begin 114 | Inc(FIndex); 115 | Start := FIndex; 116 | repeat 117 | until ReadChar = '}'; 118 | if FSource[Start] = '$' then 119 | Directive(Start); 120 | end; 121 | 122 | function TParser.Comment2: Boolean; 123 | var 124 | Start: Integer; 125 | begin 126 | Result := FSource[FIndex + 1] = '*'; 127 | if Result then 128 | begin 129 | Inc(FIndex, 2); 130 | Start := FIndex; 131 | repeat 132 | until (ReadChar = '*') and (NextChar = ')'); 133 | if FSource[Start] = '$' then 134 | Directive(Start); 135 | Inc(FIndex); 136 | end; 137 | end; 138 | 139 | procedure TParser.Define(const Value: string); 140 | var 141 | Def: TDefine; 142 | begin 143 | if not IsDef(Value) then 144 | begin 145 | Def := TDefine.Create; 146 | Def.Value := Value; 147 | Def.Next := FDefines; 148 | FDefines := Def; 149 | end; 150 | end; 151 | 152 | procedure TParser.Directive(Start: Integer); 153 | begin 154 | if IsDirective(Start, 'APPTYPE') then 155 | FAppType := GetAppType(Start) 156 | else 157 | Error('Todo ' + Copy(FSource, Start, FIndex - Start - 1)); 158 | end; 159 | 160 | function TParser.IsDirective(Start: Integer; const AName: string): Boolean; 161 | var 162 | Index: Integer; 163 | begin 164 | Result := False; 165 | for Index := 1 to Length(AName) do 166 | begin 167 | Inc(Start); 168 | if FSource[Start] <> AName[Index] then 169 | Exit; 170 | end; 171 | Result := FSource[Start + 1] = ' '; 172 | end; 173 | 174 | function TParser.GetAppType(Start: Integer): TAppType; 175 | var 176 | Str: string; 177 | Up : string; 178 | begin 179 | Inc(Start, 8); // 'APPTYPE ' 180 | Str := GetString(Start); 181 | Up := UpperCase(Str); 182 | if Up = 'GUI' then 183 | Exit(APPTYPE_GUI); 184 | if Up = 'CONSOLE' then 185 | Exit(APPTYPE_CONSOLE); 186 | Error('Unknown APPTYPE "' + Str + '"'); 187 | end; 188 | 189 | function TParser.GetChar(Start, Base: Integer): Char; 190 | var 191 | Digit: Integer; 192 | Value: Integer; 193 | begin 194 | Value := 0; 195 | while Start < FIndex do 196 | begin 197 | Digit := Ord(FSource[Start]); 198 | Inc(Start); 199 | case Chr(Digit) of 200 | '0'..'9': Dec(Digit, Ord('0')); 201 | 'a'..'f': Dec(Digit, Ord('a')); 202 | 'A'..'F': Dec(Digit, Ord('A')); 203 | end; 204 | Value := Base * Value + Digit; 205 | if Value > $FFFF then 206 | Error('Char overflow'); 207 | end; 208 | Result := Char(Value); 209 | end; 210 | 211 | function TParser.GetCol: Integer; 212 | begin 213 | Result := FStart - FLine + 1; 214 | end; 215 | 216 | function TParser.SkipChar(AChar: Char): Boolean; 217 | begin 218 | Result := (FSource[FStart] = AChar) and (FIndex = FStart + 1); 219 | if Result then 220 | Next(); 221 | end; 222 | 223 | procedure TParser.DropChar(AChar: Char); 224 | begin 225 | if not SkipChar(AChar) then 226 | Error('Expected "' + AChar + '", found, "' + Token +'"'); 227 | end; 228 | 229 | procedure TParser.DropCharType(ACharType: TCharType); 230 | begin 231 | if CharType <> ACharType then 232 | Error('Unexpacted token "' + Token + '"'); 233 | Next(); 234 | end; 235 | 236 | function TParser.SkipKeyword(AKeyword: TKeyword): Boolean; 237 | begin 238 | Result := Keyword = AKeyword; 239 | if Result then 240 | Next(); 241 | end; 242 | 243 | procedure TParser.DropKeyword(AKeyword: TKeyword); 244 | begin 245 | if not SkipKeyword(AKeyword) then 246 | Error('Keyword expected "' + KEYWORDS[AKeyword] + '", found "' + Token + '"'); 247 | end; 248 | 249 | procedure TParser.Error(const Msg: string); 250 | begin 251 | raise ESourceError.Create(Msg, FRow, Col); 252 | end; 253 | 254 | function TParser.GetIdent: string; 255 | begin 256 | Result := Token; 257 | if CharType <> ctIdent then 258 | Error('Ident expected, found "' + Result + '"'); 259 | Next(); 260 | end; 261 | 262 | procedure TParser.Init(const Str: string); 263 | begin 264 | Clear; 265 | FSource := Str; 266 | FIndex := 1; 267 | FRow := 1; 268 | FLine := 0; 269 | Next(); 270 | end; 271 | 272 | function TParser.IsDef(const Value: string): Boolean; 273 | var 274 | Def: TDefine; 275 | begin 276 | Def := FDefines; 277 | while Def <> nil do 278 | begin 279 | if Def.Value = Value then 280 | Exit(True); 281 | Def := Def.Next; 282 | end; 283 | Result := False; 284 | end; 285 | 286 | function TParser.LineComment: Boolean; 287 | begin 288 | Result := FSource[FIndex + 1] = '/'; 289 | if Result then 290 | begin 291 | Inc(FIndex, 2); 292 | repeat 293 | until GetCharType(ReadChar) in [ctLineFeed, ctReturn]; 294 | end; 295 | end; 296 | 297 | function TParser.Match(AChar: Char; AType: TCharType): Boolean; 298 | begin 299 | Result := AddChar(AChar); 300 | if Result then 301 | CharType := AType; 302 | end; 303 | 304 | function TParser.AddChar(AChar: Char): Boolean; 305 | begin 306 | Result := NextChar = AChar; 307 | if Result then 308 | Inc(FIndex); 309 | end; 310 | 311 | procedure TParser.AddChars(CharTypes: TCharTypes); 312 | var 313 | C: Char; 314 | begin 315 | C := NextChar; 316 | while GetCharType(C) in CharTypes do 317 | begin 318 | Inc(FIndex); 319 | C := NextChar; 320 | end; 321 | end; 322 | 323 | procedure TParser.Blanks; 324 | begin 325 | repeat 326 | case GetCharType(NextChar) of 327 | ctPadding : Inc(FIndex); 328 | ctLineFeed : // LF 329 | begin 330 | Inc(FRow); 331 | Inc(FIndex); 332 | FLine := FIndex; 333 | end; 334 | ctReturn: // CR/LF 335 | begin 336 | Inc(FRow); 337 | Inc(FIndex); 338 | if NextChar = #10 then 339 | Inc(FIndex); 340 | FLine := FIndex; 341 | end; 342 | ctLBrace : Comment1; // { 343 | ctLParent: if not Comment2 then Exit; // (* 344 | ctSlash : if not LineComment then Exit; // // 345 | else 346 | Exit; 347 | end; 348 | until False; 349 | end; 350 | 351 | procedure TParser.Next; 352 | begin 353 | FLiteral := ''; 354 | Blanks; // { comment1 } (* comment 2 *) // line comment 355 | FStart := FIndex; 356 | CharType := GetCharType(ReadChar); 357 | Keyword := kw_None; 358 | case CharType of 359 | ctAlpha : ParseIdent; 360 | ctDigit : ParseNumber; 361 | ctColon : Match('=', ctAssign); 362 | ctGT : Match('=', ctGE); 363 | ctLT : if not Match('=', ctLE) then Match('>', ctNE); 364 | ctDot : Match('.', ctRange); 365 | ctSharp : ParseChar; 366 | ctDollar : ParseHexa; 367 | ctSimpleQuote: ParseString; 368 | end; 369 | end; 370 | 371 | function TParser.NextChar: Char; 372 | begin 373 | if FIndex <= Length(FSource) then 374 | Result := FSource[FIndex] 375 | else 376 | Result := #0; 377 | end; 378 | 379 | procedure TParser.ParseChar; 380 | var 381 | Start: Integer; 382 | begin 383 | if NextChar = '$' then 384 | begin 385 | Inc(FIndex); 386 | Start := FIndex; 387 | ParseHexa; 388 | if FIndex = Start then 389 | Error('Expected hexadecimal value'); 390 | FLiteral := FLiteral + GetChar(Start, 16); 391 | end else begin 392 | Start := FIndex; 393 | AddChars([ctDigit]); 394 | if FIndex = Start then 395 | Error('Expected number'); 396 | FLiteral := FLiteral + GetChar(Start, 10); 397 | end; 398 | if NextChar = '''' then 399 | begin 400 | Inc(FIndex); 401 | ParseString; 402 | end else begin 403 | CharType := ctChar; 404 | end; 405 | end; 406 | 407 | procedure TParser.ParseHexa; 408 | begin 409 | while NextChar in ['0'..'9', 'a'..'f', 'A'..'F'] do 410 | Inc(FIndex); 411 | CharType := ctHexa; 412 | end; 413 | 414 | procedure TParser.ParseIdent; 415 | begin 416 | AddChars([ctAlpha, ctDigit]); 417 | CharType := ctIdent; 418 | Keyword := GetKeyword(Token); 419 | if Keyword <> kw_None then 420 | CharType := ctKeyword; 421 | end; 422 | 423 | procedure TParser.ParseNumber; 424 | begin 425 | AddChars([ctDigit]); // 123 426 | CharType := ctNumber; 427 | if NextChar = '.' then // 123.4 428 | begin 429 | CharType := ctReal; 430 | Inc(FIndex); 431 | AddChars([ctDigit]); 432 | end; 433 | if NextChar in ['e', 'E'] then // 123e10, 123.4e10 434 | begin 435 | CharType := ctReal; 436 | Inc(FIndex); 437 | if NextChar in ['+', '-'] then // 123e+10 438 | Inc(FIndex); 439 | AddChars([ctDigit]); 440 | end; 441 | end; 442 | 443 | procedure TParser.ParseString; 444 | var 445 | Start: Integer; 446 | begin 447 | Start := FIndex; 448 | while True do 449 | begin 450 | while NextChar <> '''' do 451 | begin 452 | Inc(FIndex); 453 | end; 454 | Inc(FIndex); 455 | if NextChar = '''' then 456 | begin 457 | FLiteral := FLiteral + Copy(FSource, Start, FIndex - Start); 458 | Inc(FIndex); 459 | Start := FIndex; 460 | end else begin 461 | Break; 462 | end; 463 | end; 464 | FLiteral := FLiteral + Copy(FSource, Start, FIndex - Start - 1); 465 | if NextChar = '#' then 466 | begin 467 | Inc(FIndex); 468 | ParseChar; 469 | end; 470 | CharType := ctString; 471 | end; 472 | 473 | function TParser.ReadChar: Char; 474 | begin 475 | Result := NextChar; 476 | if Result = #0 then 477 | raise Exception.Create('End of File'); 478 | Inc(FIndex); 479 | end; 480 | 481 | function TParser.GetString(var At: Integer): string; 482 | var 483 | Start: Integer; 484 | begin 485 | while (At < FIndex) and (GetCharType(FSource[At]) = ctPadding) do 486 | Inc(At); 487 | Start := At; 488 | while (At < FIndex) and (GetCharType(FSource[At]) in [ctAlpha, ctDigit]) do 489 | Inc(At); 490 | Result := Copy(FSource, Start, At - Start); 491 | end; 492 | 493 | procedure TParser.SemiColon; 494 | begin 495 | DropChar(';'); 496 | end; 497 | 498 | function TParser.SkipKeywords(AKeywords: TKeywords): TKeyword; 499 | begin 500 | if Keyword in AKeywords then 501 | begin 502 | Result := Keyword; 503 | Next(); 504 | end else begin 505 | Result := kw_None; 506 | end; 507 | end; 508 | 509 | function TParser.Token: string; 510 | begin 511 | SetString(Result, PChar(@FSource[FStart]), FIndex - FStart); 512 | end; 513 | 514 | procedure TParser.Undef(const Value: string); 515 | var 516 | Def: TDefine; 517 | Tmp: TDefine; 518 | begin 519 | if FDefines = nil then 520 | Exit; 521 | Def := FDefines; 522 | if Def.Value = Value then 523 | begin 524 | FDefines := Def.Next; 525 | Def.Free; 526 | end else begin 527 | Tmp := Def.Next; 528 | while Tmp <> nil do 529 | begin 530 | if Tmp.Value = Value then 531 | begin 532 | Def.Next := Tmp.Next; 533 | Tmp.Free; 534 | Exit; 535 | end; 536 | Def := Tmp; 537 | Tmp := Def.Next; 538 | end; 539 | end; 540 | end; 541 | 542 | { ESourceError } 543 | 544 | constructor ESourceError.Create(const Msg: string; ARow, ACol: Integer); 545 | begin 546 | inherited Create(Msg + ' at [' + IntToStr(ACol) + ',' + IntToStr(ARow) + ']'); 547 | Row := ARow; 548 | Col := ACol; 549 | end; 550 | 551 | end. 552 | -------------------------------------------------------------------------------- /lib/TokyoScript.Runtime.pas: -------------------------------------------------------------------------------- 1 | unit TokyoScript.Runtime; 2 | { 3 | 4 | TokyoScript (c)2018 Execute SARL 5 | http://www.execute.Fr 6 | 7 | } 8 | interface 9 | 10 | uses 11 | System.Classes, 12 | System.SysUtils; 13 | 14 | const 15 | FLAG_CONSOLE = 1; 16 | 17 | type 18 | TOpCode = ( 19 | opReturn, // empty 20 | opGotoLabel, // goto vLabel 21 | opJumpiEQ, // if vReg1 = vReg2 then goto vLabel 22 | opJumpTrue, // if vReg then goto vLabel 23 | opAssign, // vReg1 := vReg2 24 | opiIncr, // Inc(vReg1) 25 | opIMul, // vReg1 *= VReg2 26 | opiLT, // vReg3 := vReg1 < vReg2 27 | opConcat, // vReg1 += vReg2 28 | opLoadInt, // vReg1 := vValue 29 | opLoadStr, // vReg1 := vString 30 | opWriteInt, // Write(vReg1) 31 | opWriteStr // Write(vReg1) 32 | ); 33 | 34 | TByteCode = class 35 | Version: Word; 36 | Flags : Word; 37 | Strings: TArray; 38 | Values : TArray; 39 | Start : Integer; 40 | Code : TArray; 41 | procedure Clear; 42 | procedure SaveToFile(const AFileName: string); 43 | procedure SaveToStream(AStream: TStream); 44 | procedure LoadFromFile(const AFileName: string); 45 | procedure LoadFromStream(AStream: TStream); 46 | end; 47 | 48 | TWriteStrEvent = procedure(Sender: TObject; const Value: string) of object; 49 | 50 | TRuntime = class 51 | private 52 | FOnWriteStr: TWriteStrEvent; 53 | public 54 | procedure Execute(ByteCode: TByteCode); 55 | procedure WriteStr(const Str: string); virtual; 56 | property OnWriteStr: TWriteStrEvent read FOnWriteStr write FOnWriteStr; 57 | end; 58 | 59 | implementation 60 | 61 | const 62 | SIGN : array[0..3] of AnsiChar = 'TKS1'; 63 | VER = 1; 64 | 65 | { TByteCode } 66 | 67 | procedure TByteCode.Clear; 68 | begin 69 | Version := 0; 70 | Flags := 0; 71 | Strings := nil; 72 | Values := nil; 73 | Start := 0; 74 | Code := nil; 75 | end; 76 | 77 | procedure TByteCode.LoadFromFile(const AFileName: string); 78 | var 79 | Stream: TFileStream; 80 | begin 81 | Stream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone); 82 | try 83 | LoadFromStream(Stream); 84 | finally 85 | Stream.Free; 86 | end; 87 | end; 88 | 89 | procedure TByteCode.LoadFromStream(AStream: TStream); 90 | var 91 | Count: Integer; 92 | Index: Integer; 93 | Len : Integer; 94 | begin 95 | Clear; 96 | try 97 | AStream.ReadBuffer(Count, SizeOf(Count)); 98 | if Count <> Integer(SIGN) then 99 | raise Exception.Create('Not a TokyoScript file'); 100 | AStream.ReadBuffer(Version, SizeOf(Version)); 101 | if Version <> VER then 102 | raise Exception.Create('Unsupported version'); 103 | AStream.ReadBuffer(Flags, SizeOf(Flags)); 104 | AStream.ReadBuffer(Count, SizeOf(Count)); 105 | SetLength(Strings, Count); 106 | for Index := 0 to Count - 1 do 107 | begin 108 | AStream.ReadBuffer(Len, SizeOf(Len)); 109 | if Len > 0 then 110 | begin 111 | SetLength(Strings[Index], Len); 112 | AStream.Read(Strings[Index][1], Len * SizeOf(Char)); 113 | end; 114 | end; 115 | AStream.ReadBuffer(Count, SizeOf(Count)); 116 | if Count > 0 then 117 | begin 118 | SetLength(Values, Count); 119 | AStream.ReadBuffer(Values[0], Count * SizeOf(Integer)); 120 | end; 121 | AStream.ReadBuffer(Len, SizeOf(Len)); 122 | if Len > 0 then 123 | begin 124 | SetLength(Code, Len); 125 | AStream.Read(Code[0], Len); 126 | end; 127 | except 128 | Clear; 129 | raise; 130 | end; 131 | end; 132 | 133 | procedure TByteCode.SaveToFile(const AFileName: string); 134 | var 135 | Stream: TFileStream; 136 | begin 137 | Stream := TFileStream.Create(AFileName, fmCreate); 138 | try 139 | SaveToStream(Stream); 140 | finally 141 | Stream.Free; 142 | end; 143 | end; 144 | 145 | procedure TByteCode.SaveToStream(AStream: TStream); 146 | var 147 | Count: Integer; 148 | Index: Integer; 149 | Len : Integer; 150 | begin 151 | AStream.Write(SIGN, SizeOf(SIGN)); 152 | Version := VER; 153 | AStream.Write(Version, SizeOf(Version)); 154 | AStream.Write(Flags, SizeOf(Flags)); 155 | Count := Length(Strings); 156 | AStream.Write(Count, SizeOf(Count)); 157 | for Index := 0 to Count - 1 do 158 | begin 159 | Len := Length(Strings[Index]); 160 | AStream.Write(Len, SizeOf(Len)); 161 | if Len > 0 then 162 | AStream.Write(Strings[Index][1], Len * SizeOf(Char)); 163 | end; 164 | Count := Length(Values); 165 | AStream.Write(Count, SizeOf(Count)); 166 | if Count > 0 then 167 | AStream.Write(Values[0], Count * SizeOf(Integer)); 168 | Len := Length(Code); 169 | AStream.Write(Len, SizeOf(Len)); 170 | if Len > 0 then 171 | AStream.Write(Code[0], Len) 172 | end; 173 | 174 | { TContext } 175 | 176 | type 177 | TRegister = record 178 | AsInteger: Integer; 179 | AsString : string; 180 | procedure LoadInt(Value: Integer); 181 | procedure LoadStr(const Str: string); 182 | procedure Assign(const Reg: TRegister); 183 | end; 184 | 185 | TContext = record 186 | RT : TRuntime; 187 | BC : TByteCode; 188 | EOC : Integer; 189 | PC : Integer; 190 | Regs: TArray; 191 | Lbls: TArray; 192 | procedure Get(var Data; Size: Integer); 193 | function GetByte: Byte; inline; 194 | function GetWord: Word; inline; 195 | function GetShort: SmallInt; inline; 196 | function GetLong: Integer; inline; 197 | function GetVarLen: Integer; 198 | function GetValue: Integer; 199 | function GetString: string; 200 | function GetReg: Integer; 201 | function GetLabel: Integer; 202 | procedure Start; 203 | procedure Run; 204 | function Next: TOpCode; 205 | procedure LoadInt; 206 | procedure LoadStr; 207 | procedure WriteInt; 208 | procedure WriteStr; 209 | procedure AssignRegs; 210 | procedure iIncr; 211 | procedure iLT; 212 | procedure JumpiEQ; 213 | procedure JumpTrue; 214 | procedure GotoLabel; 215 | end; 216 | 217 | { TRegister } 218 | 219 | procedure TRegister.Assign(const Reg: TRegister); 220 | begin 221 | AsInteger := Reg.AsInteger; 222 | AsString := Reg.AsString; 223 | end; 224 | 225 | procedure TRegister.LoadInt(Value: Integer); 226 | begin 227 | AsInteger := Value; 228 | end; 229 | 230 | procedure TRegister.LoadStr(const Str: string); 231 | begin 232 | AsString := Str; 233 | end; 234 | 235 | { TContext } 236 | 237 | procedure TContext.Get(var Data; Size: Integer); 238 | begin 239 | if PC + Size > Length(BC.Code) then 240 | raise Exception.Create('Code overflow'); 241 | Move(BC.Code[PC], Data, Size); 242 | Inc(PC, Size); 243 | end; 244 | 245 | function TContext.GetByte: Byte; 246 | begin 247 | Get(Result, SizeOf(Result)); 248 | end; 249 | 250 | function TContext.GetWord: Word; 251 | begin 252 | Get(Result, SizeOf(Result)); 253 | end; 254 | 255 | function TContext.GetShort: SmallInt; 256 | begin 257 | Get(Result, SizeOf(Result)); 258 | end; 259 | 260 | function TContext.GetLong: Integer; 261 | begin 262 | Get(Result, SizeOf(Result)); 263 | end; 264 | 265 | function TContext.GetVarLen: Integer; 266 | begin 267 | Result := GetByte; 268 | case Result of 269 | 254: Result := GetWord; 270 | 255: Result := GetLong; 271 | end; 272 | end; 273 | 274 | function TContext.GetString: string; 275 | var 276 | Index: Integer; 277 | begin 278 | Index := GetVarLen; 279 | if Index >= Length(BC.Strings) then 280 | raise Exception.Create('Strings index overflow'); 281 | Result := BC.Strings[Index]; 282 | end; 283 | 284 | function TContext.GetValue: Integer; 285 | begin 286 | Result := GetVarLen; 287 | if Result >= Length(BC.Values) then 288 | raise Exception.Create('Values overflow'); 289 | Result := BC.Values[Result]; 290 | end; 291 | 292 | function TContext.GetLabel: Integer; 293 | begin 294 | Result := GetVarLen; 295 | if Result >= Length(Lbls) then 296 | raise Exception.Create('Labels overflow'); 297 | Result := Lbls[Result]; 298 | end; 299 | 300 | function TContext.GetReg: Integer; 301 | begin 302 | Result := GetVarLen; 303 | if Result >= Length(Regs) then 304 | raise Exception.Create('Register overflow'); 305 | end; 306 | 307 | procedure TContext.AssignRegs; 308 | var 309 | R1, R2: Integer; 310 | begin 311 | R1 := GetReg; 312 | R2 := GetReg; 313 | Regs[R1].Assign(Regs[R2]); 314 | end; 315 | 316 | procedure TContext.iIncr; 317 | var 318 | R: Integer; 319 | begin 320 | R := GetReg; 321 | Inc(Regs[R].AsInteger); 322 | end; 323 | 324 | procedure TContext.iLT; 325 | var 326 | R1: Integer; 327 | R2: Integer; 328 | R3: Integer; 329 | begin 330 | R1 := GetReg; 331 | R2 := GetReg; 332 | R3 := GetReg; 333 | Regs[R3].AsInteger := Ord(Regs[R1].AsInteger < Regs[R2].AsInteger); 334 | end; 335 | 336 | procedure TContext.GotoLabel; 337 | begin 338 | PC := GetLabel; 339 | end; 340 | 341 | procedure TContext.JumpiEQ; 342 | var 343 | R1: Integer; 344 | R2: Integer; 345 | AD: Integer; 346 | begin 347 | R1 := GetReg; 348 | R2 := GetReg; 349 | AD := GetLabel; 350 | if Regs[R1].AsInteger = Regs[R2].AsInteger then 351 | PC := AD; 352 | end; 353 | 354 | procedure TContext.JumpTrue; 355 | var 356 | R: Integer; 357 | A: Integer; 358 | begin 359 | R := GetReg; 360 | A := GetLabel; 361 | if Regs[R].AsInteger <> 0 then 362 | PC := A; 363 | end; 364 | 365 | procedure TContext.LoadInt; 366 | var 367 | R: Integer; 368 | begin 369 | R := GetReg; 370 | Regs[R].LoadInt(GetValue); 371 | end; 372 | 373 | procedure TContext.LoadStr; 374 | var 375 | R: Integer; 376 | begin 377 | R := GetReg; 378 | Regs[R].LoadStr(GetString); 379 | end; 380 | 381 | procedure TContext.WriteInt; 382 | var 383 | R: Integer; 384 | begin 385 | R := GetReg; 386 | RT.WriteStr(IntToStr(Regs[R].AsInteger)); 387 | end; 388 | 389 | procedure TContext.WriteStr; 390 | var 391 | R: Integer; 392 | begin 393 | R := GetReg; 394 | RT.WriteStr(Regs[R].AsString); 395 | end; 396 | 397 | procedure TContext.Start; 398 | begin 399 | PC := BC.Start; 400 | case GetByte of 401 | 1: Run; // Format 1 402 | else 403 | raise Exception.Create('Unsupported code version'); 404 | end; 405 | end; 406 | 407 | procedure TContext.Run; 408 | var 409 | Save : Integer; 410 | Index: Integer; 411 | begin 412 | // Registers Count 413 | SetLength(Regs, GetVarLen); 414 | // Labels count 415 | SetLength(Lbls, GetVarLen); 416 | // End of code Offset 417 | EOC := GetLong; 418 | if EOC > Length(BC.Code) then 419 | raise Exception.Create('Code overflow'); 420 | // get Labels offsets 421 | if Length(Lbls) > 0 then 422 | begin 423 | Save := PC; 424 | PC := EOC; 425 | for Index := 0 to Length(Lbls) - 1 do 426 | Lbls[Index] := GetVarLen; 427 | PC := Save; 428 | end; 429 | // execute byte code until opReturn 430 | repeat until Next() = opReturn; 431 | end; 432 | 433 | function TContext.Next: TOpCode; 434 | begin 435 | Result := TOpCode(GetByte); 436 | case Result of 437 | opReturn : { done }; 438 | opLoadInt : LoadInt; 439 | opiIncr : iIncr; 440 | opLoadStr : LoadStr; 441 | opWriteInt : WriteInt; 442 | opWriteStr : WriteStr; 443 | opJumpiEQ : JumpiEQ; 444 | opJumpTrue : JumpTrue; 445 | opiLT : iLT; 446 | opAssign : AssignRegs; 447 | opGotoLabel : GotoLabel; 448 | else 449 | raise Exception.Create('Unknow opcode #' + IntToStr(Ord(Result))); 450 | end; 451 | end; 452 | 453 | 454 | { TRuntime } 455 | 456 | procedure TRuntime.Execute(ByteCode: TByteCode); 457 | var 458 | C: TContext; 459 | begin 460 | if ByteCode.Version <> VER then 461 | raise Exception.Create('Unsupported version'); 462 | C.RT := Self; 463 | C.BC := ByteCode; 464 | C.Start; 465 | end; 466 | 467 | procedure TRuntime.WriteStr(const Str: string); 468 | begin 469 | if Assigned(FOnWriteStr) then 470 | FOnWriteStr(Self, Str); 471 | end; 472 | 473 | end. 474 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # TokyoScript 2 | 3 | TokyoScript is an educational project about building a scripting language for Delphi. 4 | 5 | ![screenshot](TokyoScript.png) 6 | 7 | If you want a functional product, look at DWScript or PascalScript. 8 | 9 | [![French Video](https://img.youtube.com/vi/0-l2ZgTG9WI/0.jpg)](https://youtu.be/0-l2ZgTG9WI) -------------------------------------------------------------------------------- /src/Demo1.pas: -------------------------------------------------------------------------------- 1 | program Demo1; 2 | {$APPTYPE CONSOLE} 3 | begin 4 | WriteLn('Hello'); 5 | end. -------------------------------------------------------------------------------- /src/Demo2.pas: -------------------------------------------------------------------------------- 1 | program Demo2; 2 | {$APPTYPE CONSOLE} 3 | var 4 | i: Integer; 5 | begin 6 | for i := 0 to 10 do 7 | WriteLn('Hello ', i); 8 | end. -------------------------------------------------------------------------------- /src/Demo3.pas: -------------------------------------------------------------------------------- 1 | program Demo3; 2 | {$APPTYPE CONSOLE} 3 | var 4 | i: Integer; 5 | begin 6 | i := 0; 7 | while i < 10 do 8 | begin 9 | WriteLn('Hello ', i); 10 | Inc(i); 11 | end; 12 | end. -------------------------------------------------------------------------------- /src/Demos.rc: -------------------------------------------------------------------------------- 1 | DEMO1 RCDATA Demo1.pas 2 | DEMO2 RCDATA Demo2.pas 3 | DEMO3 RCDATA Demo3.pas -------------------------------------------------------------------------------- /src/TokyoScript.Main.dfm: -------------------------------------------------------------------------------- 1 | object Main: TMain 2 | Left = 0 3 | Top = 0 4 | Caption = 'TokyoScript (c)2018 Execute SARL' 5 | ClientHeight = 544 6 | ClientWidth = 995 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | OldCreateOrder = False 14 | OnCreate = FormCreate 15 | PixelsPerInch = 96 16 | TextHeight = 13 17 | object spLog: TSplitter 18 | Left = 0 19 | Top = 452 20 | Width = 995 21 | Height = 3 22 | Cursor = crVSplit 23 | Align = alBottom 24 | ExplicitTop = 35 25 | ExplicitWidth = 295 26 | end 27 | object Splitter1: TSplitter 28 | Left = 717 29 | Top = 35 30 | Height = 417 31 | Align = alRight 32 | ExplicitLeft = 408 33 | ExplicitTop = 176 34 | ExplicitHeight = 100 35 | end 36 | object SynEdit: TSynEdit 37 | Left = 0 38 | Top = 35 39 | Width = 717 40 | Height = 417 41 | Align = alClient 42 | Font.Charset = DEFAULT_CHARSET 43 | Font.Color = clWindowText 44 | Font.Height = -13 45 | Font.Name = 'Courier New' 46 | Font.Style = [] 47 | TabOrder = 0 48 | CodeFolding.CollapsedLineColor = clGrayText 49 | CodeFolding.FolderBarLinesColor = clGrayText 50 | CodeFolding.ShowCollapsedLine = True 51 | CodeFolding.IndentGuidesColor = clGray 52 | CodeFolding.IndentGuides = True 53 | UseCodeFolding = False 54 | Gutter.Font.Charset = DEFAULT_CHARSET 55 | Gutter.Font.Color = clWindowText 56 | Gutter.Font.Height = -11 57 | Gutter.Font.Name = 'Courier New' 58 | Gutter.Font.Style = [] 59 | Gutter.ShowLineNumbers = True 60 | Highlighter = SynPasSyn1 61 | FontSmoothing = fsmNone 62 | ExplicitWidth = 807 63 | ExplicitHeight = 295 64 | end 65 | object Panel1: TPanel 66 | Left = 0 67 | Top = 0 68 | Width = 995 69 | Height = 35 70 | Align = alTop 71 | Caption = 'Panel1' 72 | ParentBackground = False 73 | ParentColor = True 74 | ShowCaption = False 75 | TabOrder = 1 76 | ExplicitWidth = 807 77 | object btRun: TButton 78 | AlignWithMargins = True 79 | Left = 4 80 | Top = 4 81 | Width = 29 82 | Height = 27 83 | Align = alLeft 84 | Caption = '4' 85 | Font.Charset = SYMBOL_CHARSET 86 | Font.Color = clWindowText 87 | Font.Height = -21 88 | Font.Name = 'Webdings' 89 | Font.Style = [] 90 | ParentFont = False 91 | TabOrder = 0 92 | OnClick = btRunClick 93 | end 94 | object cbSource: TComboBox 95 | AlignWithMargins = True 96 | Left = 39 97 | Top = 7 98 | Width = 145 99 | Height = 22 100 | Margins.Top = 6 101 | Margins.Bottom = 6 102 | Align = alLeft 103 | Style = csOwnerDrawVariable 104 | TabOrder = 1 105 | OnChange = cbSourceChange 106 | end 107 | end 108 | object mmLog: TMemo 109 | Left = 0 110 | Top = 455 111 | Width = 995 112 | Height = 89 113 | Align = alBottom 114 | Lines.Strings = ( 115 | 'mmLog') 116 | ScrollBars = ssBoth 117 | TabOrder = 2 118 | Visible = False 119 | ExplicitTop = 330 120 | ExplicitWidth = 807 121 | end 122 | object mmDump: TMemo 123 | Left = 720 124 | Top = 35 125 | Width = 275 126 | Height = 417 127 | Align = alRight 128 | Font.Charset = ANSI_CHARSET 129 | Font.Color = clWindowText 130 | Font.Height = -12 131 | Font.Name = 'Courier New' 132 | Font.Style = [] 133 | ParentFont = False 134 | ScrollBars = ssBoth 135 | TabOrder = 3 136 | end 137 | object SynPasSyn1: TSynPasSyn 138 | Options.AutoDetectEnabled = False 139 | Options.AutoDetectLineLimit = 0 140 | Options.Visible = False 141 | CommentAttri.Foreground = clGreen 142 | DirectiveAttri.Foreground = clTeal 143 | NumberAttri.Foreground = clFuchsia 144 | FloatAttri.Foreground = clFuchsia 145 | StringAttri.Foreground = clBlue 146 | CharAttri.Foreground = clBlue 147 | Left = 312 148 | Top = 152 149 | end 150 | end 151 | -------------------------------------------------------------------------------- /src/TokyoScript.Main.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/TokyoScript/41c3b657bc5adf058de8ff3132f0b9513dcd3b12/src/TokyoScript.Main.pas -------------------------------------------------------------------------------- /src/TokyoScript.dpr: -------------------------------------------------------------------------------- 1 | program TokyoScript; 2 | 3 | {$R 'Demos.res' 'Demos.rc'} 4 | 5 | uses 6 | madExcept, 7 | madLinkDisAsm, 8 | madListHardware, 9 | madListProcesses, 10 | madListModules, 11 | Vcl.Forms, 12 | TokyoScript.Main in 'TokyoScript.Main.pas' {Main}, 13 | TokyoScript.Compiler in '..\lib\TokyoScript.Compiler.pas', 14 | TokyoScript.Runtime in '..\lib\TokyoScript.Runtime.pas', 15 | TokyoScript.Chars in '..\lib\TokyoScript.Chars.pas', 16 | TokyoScript.Keywords in '..\lib\TokyoScript.Keywords.pas', 17 | TokyoScript.Parser in '..\lib\TokyoScript.Parser.pas', 18 | TokyoScript.BuiltIn in '..\lib\TokyoScript.BuiltIn.pas'; 19 | 20 | {$R *.res} 21 | 22 | begin 23 | Application.Initialize; 24 | Application.MainFormOnTaskbar := True; 25 | Application.CreateForm(TMain, Main); 26 | Application.Run; 27 | end. 28 | -------------------------------------------------------------------------------- /src/TokyoScript.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {56A77600-51A7-4E6B-998A-0D2EF921C532} 4 | 18.4 5 | VCL 6 | TokyoScript.dpr 7 | True 8 | Debug 9 | Win32 10 | 1 11 | Application 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Cfg_1 34 | true 35 | true 36 | 37 | 38 | true 39 | Base 40 | true 41 | 42 | 43 | true 44 | Cfg_2 45 | true 46 | true 47 | 48 | 49 | .\$(Platform)\$(Config) 50 | .\$(Platform)\$(Config) 51 | false 52 | false 53 | false 54 | false 55 | false 56 | RESTComponents;emsclientfiredac;DataSnapFireDAC;FireDACIBDriver;emsclient;FireDACCommon;RESTBackendComponents;soapserver;CloudService;FireDACCommonDriver;inet;FireDAC;FireDACSqliteDriver;soaprtl;soapmidas;$(DCC_UsePackage) 57 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) 58 | $(BDS)\bin\delphi_PROJECTICON.ico 59 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png 60 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png 61 | TokyoScript 62 | 63 | 64 | DBXSqliteDriver;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;SepiCore140;vclactnband;vclFireDAC;svnui;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;svn;DBXOracleDriver;inetdb;VirtualTreesDR;FmxTeeUI;emsedge;Execute.MD2Importer.Package;fmx;fmxdae;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;DataSnapConnectors;VCLRESTComponents;Execute.LetsEncryptRuntime;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;Execute.CustomForms.Runtime.Package;FireDACCommonODBC;DataSnapClient;SDL140;bindcompdbx;IndyIPCommon;CrossAPI.Runtime;vcl;DBXSybaseASEDriver;IndyIPServer;IndySystem;FireDACDb2Driver;dsnapcon;madExcept_;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;madBasic_;TeeDB;Execute.LetsEncryptDesign;emshosting;FireDACPgDriver;SVCL140;FireDACASADriver;FOOD.CrossComponents;DBXOdbcDriver;FireDACTDataDriver;FMXTee;DbxCommonDriver;Tee;FOOD.CrossAPI;DataSnapServer;xmlrtl;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;madDisAsm_;DbxClientDriver;Execute.CustomForms.DesignTime.Package;DBXSybaseASADriver;Execute.RecordProperties.Package;CustomIPTransport;vcldsnap;SynEditDR;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;CrossCode.Runtime;bindcompvcl;TeeUI;dbxcds;VclSmp;FOODPackage;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;FOODPackageRegister;Execute.StringVisualizer;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;Execute.Sockets.Runtime;fmxase;$(DCC_UsePackage) 65 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 66 | Debug 67 | true 68 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 69 | 1033 70 | $(BDS)\bin\default_app.manifest 71 | 72 | 73 | DBXSqliteDriver;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;DBXOracleDriver;inetdb;VirtualTreesDR;FmxTeeUI;emsedge;fmx;fmxdae;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;DataSnapConnectors;VCLRESTComponents;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;DataSnapClient;bindcompdbx;IndyIPCommon;vcl;DBXSybaseASEDriver;IndyIPServer;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;emshosting;FireDACPgDriver;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;FMXTee;DbxCommonDriver;Tee;DataSnapServer;xmlrtl;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;SynEditDR;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;fmxase;$(DCC_UsePackage) 74 | 75 | 76 | DEBUG;$(DCC_Define) 77 | true 78 | false 79 | true 80 | true 81 | true 82 | 83 | 84 | false 85 | true 86 | true 87 | madExcept;LeakChecking;$(DCC_Define) 88 | 3 89 | 90 | 91 | false 92 | RELEASE;$(DCC_Define) 93 | 0 94 | 0 95 | 96 | 97 | true 98 | true 99 | 100 | 101 | 102 | MainSource 103 | 104 | 105 |
Demos.res
106 |
107 | 108 |
Main
109 | dfm 110 |
111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | Cfg_2 119 | Base 120 | 121 | 122 | Base 123 | 124 | 125 | Cfg_1 126 | Base 127 | 128 |
129 | 130 | Delphi.Personality.12 131 | Application 132 | 133 | 134 | 135 | TokyoScript.dpr 136 | 137 | 138 | 139 | 140 | 141 | TokyoScript.exe 142 | true 143 | 144 | 145 | 146 | 147 | 1 148 | 149 | 150 | Contents\MacOS 151 | 1 152 | 153 | 154 | Contents\MacOS 155 | 0 156 | 157 | 158 | 159 | 160 | classes 161 | 1 162 | 163 | 164 | 165 | 166 | library\lib\armeabi-v7a 167 | 1 168 | 169 | 170 | 171 | 172 | library\lib\armeabi 173 | 1 174 | 175 | 176 | 177 | 178 | library\lib\mips 179 | 1 180 | 181 | 182 | 183 | 184 | library\lib\armeabi-v7a 185 | 1 186 | 187 | 188 | 189 | 190 | res\drawable 191 | 1 192 | 193 | 194 | 195 | 196 | res\values 197 | 1 198 | 199 | 200 | 201 | 202 | res\drawable 203 | 1 204 | 205 | 206 | 207 | 208 | res\drawable-xxhdpi 209 | 1 210 | 211 | 212 | 213 | 214 | res\drawable-ldpi 215 | 1 216 | 217 | 218 | 219 | 220 | res\drawable-mdpi 221 | 1 222 | 223 | 224 | 225 | 226 | res\drawable-hdpi 227 | 1 228 | 229 | 230 | 231 | 232 | res\drawable-xhdpi 233 | 1 234 | 235 | 236 | 237 | 238 | res\drawable-small 239 | 1 240 | 241 | 242 | 243 | 244 | res\drawable-normal 245 | 1 246 | 247 | 248 | 249 | 250 | res\drawable-large 251 | 1 252 | 253 | 254 | 255 | 256 | res\drawable-xlarge 257 | 1 258 | 259 | 260 | 261 | 262 | 1 263 | 264 | 265 | Contents\MacOS 266 | 1 267 | 268 | 269 | 0 270 | 271 | 272 | 273 | 274 | Contents\MacOS 275 | 1 276 | .framework 277 | 278 | 279 | 0 280 | 281 | 282 | 283 | 284 | 1 285 | .dylib 286 | 287 | 288 | 1 289 | .dylib 290 | 291 | 292 | 1 293 | .dylib 294 | 295 | 296 | Contents\MacOS 297 | 1 298 | .dylib 299 | 300 | 301 | 0 302 | .dll;.bpl 303 | 304 | 305 | 306 | 307 | 1 308 | .dylib 309 | 310 | 311 | 1 312 | .dylib 313 | 314 | 315 | 1 316 | .dylib 317 | 318 | 319 | Contents\MacOS 320 | 1 321 | .dylib 322 | 323 | 324 | 0 325 | .bpl 326 | 327 | 328 | 329 | 330 | 0 331 | 332 | 333 | 0 334 | 335 | 336 | 0 337 | 338 | 339 | 0 340 | 341 | 342 | Contents\Resources\StartUp\ 343 | 0 344 | 345 | 346 | 0 347 | 348 | 349 | 350 | 351 | 1 352 | 353 | 354 | 1 355 | 356 | 357 | 1 358 | 359 | 360 | 361 | 362 | 1 363 | 364 | 365 | 1 366 | 367 | 368 | 1 369 | 370 | 371 | 372 | 373 | 1 374 | 375 | 376 | 1 377 | 378 | 379 | 1 380 | 381 | 382 | 383 | 384 | 1 385 | 386 | 387 | 1 388 | 389 | 390 | 1 391 | 392 | 393 | 394 | 395 | 1 396 | 397 | 398 | 1 399 | 400 | 401 | 1 402 | 403 | 404 | 405 | 406 | 1 407 | 408 | 409 | 1 410 | 411 | 412 | 1 413 | 414 | 415 | 416 | 417 | 1 418 | 419 | 420 | 1 421 | 422 | 423 | 1 424 | 425 | 426 | 427 | 428 | 1 429 | 430 | 431 | 432 | 433 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 434 | 1 435 | 436 | 437 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 438 | 1 439 | 440 | 441 | 442 | 443 | 1 444 | 445 | 446 | 1 447 | 448 | 449 | 450 | 451 | ..\ 452 | 1 453 | 454 | 455 | ..\ 456 | 1 457 | 458 | 459 | 460 | 461 | 1 462 | 463 | 464 | 1 465 | 466 | 467 | 1 468 | 469 | 470 | 471 | 472 | 1 473 | 474 | 475 | 1 476 | 477 | 478 | 1 479 | 480 | 481 | 482 | 483 | ..\ 484 | 1 485 | 486 | 487 | 488 | 489 | Contents 490 | 1 491 | 492 | 493 | 494 | 495 | Contents\Resources 496 | 1 497 | 498 | 499 | 500 | 501 | library\lib\armeabi-v7a 502 | 1 503 | 504 | 505 | 1 506 | 507 | 508 | 1 509 | 510 | 511 | 1 512 | 513 | 514 | 1 515 | 516 | 517 | Contents\MacOS 518 | 1 519 | 520 | 521 | 0 522 | 523 | 524 | 525 | 526 | 1 527 | 528 | 529 | 1 530 | 531 | 532 | 533 | 534 | Assets 535 | 1 536 | 537 | 538 | Assets 539 | 1 540 | 541 | 542 | 543 | 544 | Assets 545 | 1 546 | 547 | 548 | Assets 549 | 1 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | True 563 | False 564 | 565 | 566 | 12 567 | 568 | 569 | 570 | 571 |
572 | --------------------------------------------------------------------------------