1 // Written in the D programming language. Мохов Геннадий Владимирович 2015 2 // Версия v1.0 - 30.04.15 10:45 3 // Попытка перенести на asm D форт реализацию >SPF-Fork 2005-2013 mOleg mOlegg@ya.ru 4 /** 5 * <b><u>SPF-Fork 2005-2013 mOleg mOlegg@ya.ru для D.</u></b> 6 */ 7 8 // initForth() - инициализировать Форт 9 // evalForth(string str) - выполнить строку как строку Форта 10 // includedForth(string NameFileForth) - Загрузить и выполнить файл Форта 11 // pp asr = getCommonAdr(int n) - Вернуть из общей таблицы (ячейка n) значение 12 // setCommonAdr(int n, pp adr) - Записать в ячейку общей таблицы n значение равное adr 13 // adrContext() - Указатель на adr[256] со списками слов 14 // extern (C) pp executeForth(pp adrexec, uint kolPar, ...) { 15 16 // История изменений 17 // 28.06.15 - BMOVE Копировать байты 18 // 05.07.15 - Пропускать в поиске слова из одних цифр 19 // 06.07.15 - Добавил DDUP 20 // 10.04.16 - Исправлена ошибка в EXECUTEFROMD 21 22 module forth; 23 24 import std.stdio; 25 import core.stdc.stdio : printf; 26 import std.conv; 27 // import std.c.stdio; 28 29 int kolPer; 30 31 alias void* p; // Просто указатель 32 alias void** pp; // Указатель на указатель 33 alias ubyte* pb; // Указатель на байт 34 alias char* ps; // Указатель на char 35 36 // Стеки и кодофайл выделены в хипе и не пересекаются 37 private const CELL = 4; 38 private const sizeCodeFile = 30000; // Количество CELL для кодофайла 39 private const sizeStack = 1000; // Количество CELL для стеков 40 41 // Таблица общих для F и D адресов. В неё можно помещать адреса переменных или функций. 42 // Контроля над тем, что лежит нет! 43 private pp[100] commonTable; 44 45 // Выдать адрес context из структуры forth 46 void* adrContext() {return gpcb.context; } 47 // Выдать адрес начала стека SD 48 void* adr_cSD() { return gpcb.csd; } 49 // Выдать адрес сохраненого стека SP 50 void* adr_SD() { return gpcb.saveEBP; } 51 52 // Выдать адрес начала кодофайла 53 void* adr_begKDF() { return gpcb.akdf; } 54 // Выдать адрес HERE 55 void* adr_here() { return gpcb.here; } 56 // Выдать адрес конца кодофайла 57 void* adr_endKDF() { return gpcb.akdf + sizeCodeFile; } 58 59 // Контекст Fotrh процесса 60 private struct NPcb { 61 pp csd; // указатель на начало стека SD 62 pp csr; // указатель на начало стека SR 63 pp csc; // указатель на начало стека SC 64 pp akdf; // указатель на начало кодофайла 65 pb here; // указатель начала свободной области кодофайла 66 pp latest; // указатель на аоследнее скомпилированное слово 67 pp context; // указатель на массив из 256 cell в каждой ячейке context на эту букву 68 pp executeFromD; // ' EXECUTEFROMD 69 pp state; // текущее состояние компиляции 0=интерпретация 70 byte imm; // запомнить состояние IMM в последнем FIND 71 72 pp adrCommonTable; // адрес общий таблицы 73 74 ps In; // указатель на место интерпретации в вход. буфеpе 75 ps Tib; // указатель на сам входной буфеp 76 int dlTib; // Размер строки прочитанной в Tib 77 // Регистры сохранения состояния 78 pp saveEBP; // Место под EBP форта 79 pp saveEAX; // Место под EAX форта 80 pp saveESI; // Место под ESI форта 81 pp saveEDI; // Место под EDI форта 82 } 83 84 /* private */ NPcb gpcb; // Глобальное определение блока управления 85 private pb kdf; // Сюда будем компилировать код 86 private pp stSD, stSR, stSL; // Указатели на стеки 87 88 private ubyte[1000] tib; // Буфер строки для иекстового разбора 89 90 // Распечатать дамп памяти для указанного адреса 91 void dumpAdr(pp adr) { 92 import std.stdio: writefln; 93 ubyte* uk = cast(ubyte*)adr; ubyte* ur; 94 for(int i; i !=5; i++) { 95 ur = uk+(10*i); 96 writefln("[%10s] %3X %3X %3X %3X %3X %3X %3X %3X %3X %3X", 97 cast(void*)ur, 98 *(cast(pb)ur+0), *(cast(pb)ur+1), *(cast(pb)ur+2), *(cast(pb)ur+3), 99 *(cast(pb)ur+4), *(cast(pb)ur+5), *(cast(pb)ur+6), *(cast(pb)ur+7), 100 *(cast(pb)ur+8), *(cast(pb)ur+9) 101 ); 102 writefln("[%10s] [%1s] [%1s] [%1s] [%1s] [%1s] [%1s] [%1s] [%1s] [%1s] [%1s]", 103 "--->", 104 *(cast(ps)ur+0), *(cast(ps)ur+1), *(cast(ps)ur+2), *(cast(ps)ur+3), 105 *(cast(ps)ur+4), *(cast(ps)ur+5), *(cast(ps)ur+6), *(cast(ps)ur+7), 106 *(cast(ps)ur+8), *(cast(ps)ur+9) 107 ); 108 } 109 } 110 111 // ======================== defkern.f ======================== 112 113 // 01-02-2008 ~mOleg 114 // Copyright [C] 2006-2013 mOleg mOlegg@ya.ru 115 // Процедуры времени выполнения для CONSTANT, VARIABLE, etc. 116 117 // Сравнение. 118 // CODE = ( A B --> T/F ) 119 private void f_RAWNO() { 120 asm { naked; 121 xor EAX,dword ptr SS:[EBP]; 122 sub EAX, 1; 123 sbb EAX,EAX; 124 lea EBP,[EBP+CELL]; 125 ret; 126 } 127 } 128 // Сравнение. 129 // CODE <> ( A B --> T/F ) 130 private void f_NRAWNO() { 131 asm { naked; 132 xor EAX,dword ptr SS:[EBP]; 133 neg EAX; 134 sbb EAX,EAX; 135 lea EBP,[EBP+CELL]; 136 ret; 137 } 138 } 139 // Сравнение. 140 // CODE < ( A B --> T/F ) 141 private void f_MENSHE() { 142 asm { naked; 143 cmp EAX,dword ptr SS:[EBP]; 144 setle AL; 145 and EAX, 1; 146 dec EAX; 147 lea EBP,[EBP+CELL]; 148 ret; 149 } 150 } 151 // Сравнение. 152 // CODE > ( A B --> T/F ) 153 private void f_BOLSHE() { 154 asm { naked; 155 cmp EAX,dword ptr SS:[EBP]; 156 setge AL; 157 and EAX, 1; 158 dec EAX; 159 lea EBP,[EBP+CELL]; 160 ret; 161 } 162 } 163 // ничего не делать. 164 // CODE NOOP ( --> ) 165 private void f_NOOP() { 166 asm { naked; 167 ret; 168 } 169 } 170 // выполнить слова, представленного своим исполнимым адресом xt v 171 // CODE EXECUTE ( xt --> ) 172 private void f_EXECUTE() { 173 asm { naked; 174 mov EBX, EAX; 175 mov EAX,dword ptr SS:[EBP]; 176 lea EBP,[EBP+CELL]; 177 jmp EBX; 178 } 179 } 180 // выполнить слово, адрес которого хранится в ячейке памяти addr v 181 // то есть A@ EXECUTE 182 // CODE PERFORM ( addr --> ) 183 // выполнить слово, адрес которого хранится в ячейке памяти addr √ 184 // то есть A@ EXECUTE 185 private void f_PERFORM() { 186 asm { naked; 187 mov EBX,dword ptr DS:[EAX]; 188 mov EAX,dword ptr SS:[EBP]; 189 lea EBP, [EBP+CELL]; 190 jmp EBX; 191 } 192 } 193 // безусловный переход на адрес без возможности возврата за точку JMP 194 // аналог RDROP >R EXIT 195 // CODE JUMP ( addr --> ) 196 private void f_JUMP() { 197 asm { naked; 198 mov dword ptr [ESP],EAX; 199 mov EAX,dword ptr SS:[EBP]; 200 lea EBP,[EBP+CELL]; 201 ret; 202 } 203 } 204 // закончить выполнение текущего слова 205 // CODE EXIT ( --> ) 206 private void f_EXIT() { 207 asm { naked; 208 pop EDX; 209 ret; 210 } 211 } 212 // выйти из текущего слова, если флаг отличен от нуля v 213 // CODE ?EXIT ( flag --> ) 214 private void f_Q_EXIT() { 215 asm { naked; 216 or EAX,EAX; 217 mov EAX,dword ptr SS:[EBP]; 218 lea EBP,[EBP+CELL]; 219 jz M1; 220 lea ESP,[ESP]; 221 M1: 222 ret; 223 } 224 } 225 // выбор нужного варианта из списка v 226 // CODE (switch) ( n --> ) unfeasible 227 private void f_s_switch_s() { 228 asm { naked; 229 pop EBX; 230 mov ECX,dword ptr DS:[EBX]; 231 lea EDX,[EBX+ECX+CELL]; 232 push EDX; 233 lea EAX,[EAX*4+CELL]; 234 cmp ECX,EAX; 235 jbe M2; 236 lea EBX,[EBX+EAX+CELL]; 237 mov EAX,dword ptr SS:[EBP]; 238 lea EBP,[EBP+CELL]; 239 jmp [EBX]; 240 M2: lea EBX,[EBX+CELL]; 241 mov EAX,dword ptr SS:[EBP]; 242 lea EBP,[EBP+CELL]; 243 jmp [EBX]; 244 } 245 } 246 // вернуть значение литерала скомпилированного в коде за (LIT) 247 // CODE (LIT) ( r: addr --> d: n ) unfeasible 248 private void h_s_LIT_s() { 249 asm { naked; 250 pop EBX; 251 lea EBP,[EBP-CELL]; 252 mov dword ptr SS:[EBP],EAX; 253 mov EAX,dword ptr DS:[EBX]; 254 lea EBX,[EBX+CELL]; 255 jmp EBX; 256 } 257 } 258 // вернуть значение литерала двойной длины скомпилированного в коде за (DLIT) 259 // CODE (DLIT) ( r: addr --> d ) unfeasible 260 private void f_s_DLIT_s() { 261 asm { naked; 262 pop EBX; 263 lea EBP,[EBP-CELL*2]; 264 mov dword ptr SS:[EBP+CELL],EAX; 265 mov EDX,dword ptr DS:[EBX+CELL]; 266 mov EAX,dword ptr DS:[EBX]; 267 lea EBX,[EBX+CELL*2]; 268 mov dword ptr SS:[EBP],EDX; 269 jmp EBX; 270 } 271 } 272 // выполнить переход на адрес, значение которого содержится в коде за (BRANCH) 273 // CODE BRANCH ( r: addr --> ) unfeasible 274 private void f_BRANCH() { 275 asm { naked; 276 pop EBX; 277 add EBX,dword ptr DS:[EBX]; 278 jmp EBX; 279 } 280 } 281 // условное ветвление по false, флаговое значение не удаляется 282 // адрес перехода хранится в коде следом за *BRANCH 283 // CODE *BRANCH ( r: addr d: flag --> flag ) unfeasible 284 private void f_Z_BRANCH() { 285 asm { naked; 286 pop EBX; 287 or EAX,EAX; 288 jnz M3; 289 add EBX,dword ptr DS:[EBX]; 290 jmp EBX; 291 M3: lea EBX,[EBX+CELL]; 292 jmp EBX; 293 } 294 } 295 // условное ветвление, если флаговое значение меньше нуля 296 // флаговое значение не удаляется с вершины стека данных 297 // адрес перехода хранится в коде следом за -BRANCH 298 // CODE -BRANCH ( r: addr d: flag --> flag ) unfeasible 299 private void f_N_BRANCH() { 300 asm { naked; 301 pop EBX; 302 cmp EAX,0; 303 js M4; 304 add EBX,dword ptr DS:[EBX]; 305 jmp EBX; 306 M4: lea EBX,[EBX+CELL]; 307 jmp EBX; 308 } 309 } 310 // условное ветвление, если флаговое значение нуль 311 // адрес перехода хранится в коде следом за ?BRANCH 312 // CODE ?BRANCH ( r: addr d: flag --> ) unfeasible 313 private void f_ZW_BRANCH() { 314 asm { naked; 315 pop EBX; 316 or EAX,EAX; 317 mov EAX,dword ptr SS:[EBP]; 318 lea EBP,[EBP+CELL]; 319 jnz M5; 320 add EBX,dword ptr DS:[EBX]; 321 jmp EBX; 322 M5: lea EBX,[EBX+CELL]; 323 jmp EBX; 324 } 325 } 326 // условное ветвление, если флаговое значение отлично от нуля 327 // адрес перехода хранится в коде следом за N?BRANCH 328 // CODE N?BRANCH ( r: addr d: flag --> ) unfeasible 329 private void f_N_ZW_BRANCH() { 330 asm { naked; 331 pop EBX; 332 or EAX,EAX; 333 mov EAX,dword ptr SS:[EBP]; 334 lea EBP,[EBP+CELL]; 335 jz M6; 336 add EBX,dword ptr DS:[EBX]; 337 jmp EBX; 338 M6: lea EBX,[EBX+CELL]; 339 jmp EBX; 340 } 341 } 342 343 // ======================== dtc.f ======================== 344 345 // 01-02-2008 ~mOleg 346 // Copyright [C] 2006-2013 mOleg mOlegg@ya.ru 347 // Процедуры времени выполнения для CONSTANT, VARIABLE, etc. 348 349 // вернуть адрес данных, следующих в коде за (CREATE) 350 // CODE (CREATE) ( r: addr --> addr ) 351 private void f_s_CREATE_s() { 352 asm { naked; 353 lea EBP,[EBP-CELL]; 354 mov dword ptr SS:[EBP],EAX; 355 pop EAX; 356 ret; 357 } 358 } 359 // вернуть содержимое, хранимое в коде за скомпилированным (CONST) 360 // на вершину стека данных 361 // CODE (CONST) ( r: addr --> n ) 362 private void f_s_CONST_s() { 363 asm { naked; 364 lea EBP,[EBP-CELL]; 365 mov dword ptr SS:[EBP],EAX; 366 pop EBX; 367 mov EAX,dword ptr DS:[EBX]; 368 ret; 369 } 370 } 371 // извлечь содержимое переменной, находящейся в коде за скомпилированным 372 // (value) (с неким фиксированным смещением, определяемым # методов), 373 // вернуть значение на вершину стека данных 374 // : (value) ( r: addr --> n ) R> [ 2 TOKEN * LIT, ] + @ ; 375 // CODE (value) ( --> n ) 376 private void f_s_value_s() { 377 asm { naked; 378 lea EBP,[EBP-CELL]; 379 mov dword ptr SS:[EBP],EAX; 380 pop EBX; 381 mov EAX,dword ptr DS:[EBX+10]; 382 ret; 383 } 384 } 385 // сохранить значение с вершины стека данных в коде за скомпилированным 386 // (store) ( с некоторым фиксированным смещением, определяемым # методов) 387 // : (store) ( r: addr d: n --> ) R> TOKEN + ! ; 388 // CODE (store) ( n --> ) 389 private void f_s_store_s() { 390 asm { naked; 391 pop EBX; 392 mov dword ptr DS:[EBX+5],EAX; 393 mov EAX,dword ptr SS:[EBP]; 394 lea EBP,[EBP+4]; 395 ret; 396 } 397 } 398 // ======================== token.f ======================== 399 // \ 22.06.2009 ~mOleg 400 // \ Copyright [C] 2009-2013 mOleg mOlegg@ya.ru 401 // \ работа со скомпилированными токенами 402 403 // 5 CONSTANT CFL ( --> cfl# ) \ длинна поля кода 404 private void f_CFL() { 405 asm { naked; 406 call f_s_CONST_s; 407 add EAX,0x9D000000; 408 pop EDI; 409 pop ESP; 410 } 411 } 412 // ALIAS CFL TOKEN ( --> token# ) \ размер одной ссылки в коде √ 413 private void f_TOKEN() { 414 asm { naked; 415 call f_s_CONST_s; 416 add EAX,0x9D000000; 417 pop EDI; 418 pop ESP; 419 } 420 } 421 // \ вернуть адрес слова, скомпилированного в коде по указанному адресу 422 // : TOKEN@ ( addr --> xt ) DUP 1 + REF@ + TOKEN + ; 423 private void f_TOKEN_get() { 424 asm { naked; 425 call h_DUP; 426 call h_s_LIT_s; 427 add dword ptr DS:[EAX],EAX; 428 add byte ptr DS:[EAX],AL; 429 call h_PLUS; 430 call h_getFromAdr; 431 call h_PLUS; 432 call f_TOKEN; 433 call h_PLUS; 434 ret; 435 } 436 } 437 // \ заменить значение токена dst на src 438 // : TOKEN! ( src dst --> ) TUCK TOKEN + - SWAP 1 + REF! ; 439 private void f_TOKEN_set() { 440 asm { naked; 441 call h_TUCK; 442 call f_TOKEN; 443 call h_PLUS; 444 call h_MINUS; 445 call h_SWAP; 446 call h_s_LIT_s; 447 add dword ptr DS:[EAX],EAX; 448 add byte ptr DS:[EAX],AL; 449 call h_PLUS; 450 call h_setToAdr; 451 ret; 452 } 453 } 454 // ======================== Быстрая арифметика =============== 455 // 1+ ( A -- A+1 ) 456 private void h_inc() { 457 asm { naked; 458 inc EAX; 459 ret; 460 } 461 } 462 // 1- ( A -- A-1 ) 463 private void h_dec() { 464 asm { naked; 465 dec EAX; 466 ret; 467 } 468 } 469 470 // ======================== marks.f ======================== 471 472 // % ( A B -- A%B ) 473 private void h_ZP() { 474 asm { naked; 475 mov ECX, EAX; 476 mov EAX, [EBP]; 477 cdq; 478 idiv ECX; 479 lea EBP,[EBP+CELL]; 480 mov EAX, EDX; 481 ret; 482 } 483 } 484 485 // / ( A B -- A/B ) 486 private void h_ZD() { 487 asm { naked; 488 mov ECX, EAX; 489 mov EAX, [EBP]; 490 cdq; 491 idiv ECX; 492 lea EBP,[EBP+CELL]; 493 ret; 494 } 495 } 496 497 // * ( A B -- A*B ) 498 private void h_ZW() { 499 asm { naked; 500 imul dword ptr SS:[EBP]; 501 lea EBP,[EBP+CELL]; 502 ret; 503 } 504 } 505 // + ( A B -- A+B ) 506 private void h_PLUS() { 507 asm { naked; 508 add EAX,dword ptr SS:[EBP]; 509 lea EBP,[EBP+CELL]; 510 ret; 511 } 512 } 513 // - ( A B -- A-B ) 514 private void h_MINUS() { 515 asm { naked; 516 neg EAX; 517 add EAX,dword ptr SS:[EBP]; 518 lea EBP,[EBP+CELL]; 519 ret; 520 } 521 } 522 // Выдать размер ячейки (32 разряда) 523 // 4 CONSTANT CELL 524 private void f_CELL() { 525 asm { naked; 526 call f_s_CONST_s; 527 add AL,0; 528 add byte ptr DS:[EAX],AL; 529 pop ESP; 530 } 531 } 532 // ALIAS CELL REF ( --> const ) \ размер ссылки в байтах 533 private void f_REF() { 534 asm { naked; 535 call f_s_CONST_s; 536 add AL,0; 537 add byte ptr DS:[EAX],AL; 538 pop ESP; 539 } 540 } 541 // \ компилировать ссылку на код 542 // : REF, ( ref --> ) REF PLACE REF! ; 543 private void f_REFzpt() { 544 asm { naked; 545 call f_REF; 546 call h_PLACE; 547 call h_setToAdr; 548 ret; 549 } 550 } 551 // \ !!! часто используется и по сути выдает смещение от текущего 552 // \ адреса до указанного. Стоит вынести в отдельное слово. 553 // : atod ( addr --> disp ) HERE REF + - ; 554 private void f_atod() { 555 asm { naked; 556 call h_HERE; 557 call f_REF; 558 call h_PLUS; 559 call h_MINUS; 560 ret; 561 } 562 } 563 // \ разрешить ссылку вперед(в коде) 564 // \ : >resolve ( addr --> ) HERE OVER - REF - SWAP ! ; 565 private void f_R_RESOLVE() { 566 asm { naked; 567 call h_HERE; 568 call h_OVER; 569 call h_MINUS; 570 call f_REF; 571 call h_MINUS; 572 call h_SWAP; 573 call h_setToAdr; 574 ret; 575 } 576 } 577 // \ разрешить ссылку(в коде, то есть в поле данных команды JMP или CALL) назад 578 // : <resolve ( addr --> ) atod REF, ; 579 private void f_L_resolve() { 580 asm { naked; 581 call f_atod; 582 call f_REFzpt; 583 ret; 584 } 585 } 586 // \ запомнить положение для ссылки вперед 587 // : >MARK ( --> addr ) HERE REF - ; 588 private void f_R_MARK() { 589 asm { naked; 590 call h_HERE; 591 call f_REF; 592 call h_MINUS; 593 ret; 594 } 595 } 596 // \ заполнить положение для ссылки назад 597 // : <MARK ( --> addr ) HERE ; 598 private void f_L_MARK() { 599 asm { naked; 600 call h_HERE; 601 ret; 602 } 603 } 604 // : <RESOLVE ( addr --> ) HERE - REF, ; 605 private void f_L_RESOLVE() { 606 asm { naked; 607 call h_HERE; 608 call h_MINUS; 609 call f_REFzpt; 610 ret; 611 } 612 } 613 // : RESOLVE> ( addr --> ) HERE OVER - SWAP ! ; 614 private void f_RESOLVE_R() { 615 asm { naked; 616 call h_HERE; 617 call h_OVER; 618 call h_MINUS; 619 call h_SWAP; 620 call h_setToAdr; 621 ret; 622 } 623 } 624 // 26-06-2005 ~mOleg 625 // Copyright [C] 2005-2013 mOleg mOlegg@ya.ru 626 // стековые манипуляции 627 628 // -- стек данных ------------------------------------------------------------ 629 630 // установить новое значение указателя стека данных 631 // SP! ( addr --> ) 632 private void SP_set() { 633 asm { naked; 634 lea EBP, [EAX+CELL]; 635 mov EAX, [EBP-CELL]; 636 ret; 637 } 638 } 639 // прочесть на вершину стека текущее значение указателя стека данных 640 // SP@ ( --> addr ) 641 private void SP_get() { 642 asm { naked; 643 lea EBP, [EBP-CELL]; 644 mov [EBP], EAX; 645 mov EAX, EBP; 646 ret; 647 } 648 } 649 // USER S0 ( --> addr ) \ ячейка хранит адрес дна стека данных 650 651 // -- Стек возвратов --------------------------------------------------------- 652 // установить новое значение указателя стека возвратов 653 // RP! ( addr --> ) 654 private void RP_set() { 655 asm { naked; 656 pop EBX; // адрес куда надо вернутся 657 mov ESP, EAX; 658 mov EAX, [EBP]; 659 lea EBP, [EBP+CELL]; 660 jmp EBX; 661 } 662 } 663 // прочесть на вершину стека данных текущее значение указателя стека возвратов 664 // RP@ ( --> addr ) 665 private void RP_get() { 666 asm { naked; 667 lea EBP, [EBP-CELL]; 668 mov [EBP], EAX; 669 lea EAX, [ESP+CELL]; 670 ret; 671 } 672 } 673 // USER R0 ( --> addr ) \ ячейка хранит адрес дна стека возвратов 674 // -- локальный стек ------------------------------------------------------------ 675 // установить новое значение указателя стека данных 676 // LP! ( addr --> ) 677 private void LP_set() { 678 asm { naked; 679 mov ESI, EAX; 680 mov EAX, [EBP]; 681 lea EBP, [EBP+CELL]; 682 ret; 683 } 684 } 685 // прочесть на вершину стека текущее значение указателя стека данных 686 // LP@ ( --> addr ) 687 private void LP_get() { 688 asm { naked; 689 lea EBP, [EBP-CELL]; 690 mov [EBP], EAX; 691 mov EAX, ESI; 692 ret; 693 } 694 } 695 // USER L0 ( --> addr ) \ хранит адрес дна локального стека 696 // 26-06-2005 ~mOleg 697 // Copyright [C] 2006-2013 mOleg mOlegg@ya.ru 698 // манипуляция данными на стеке данных - псевдоассемблер 699 700 // Продублировать верхнее значение на вершине стека данных. 701 // DUP ( n --> n n ) 702 private void h_DUP() { 703 asm { naked; 704 lea EBP, [EBP-CELL]; 705 mov [EBP], EAX; 706 ret; 707 } 708 } 709 // Убрать верхнее значение со стека данных. 710 // DROP ( n --> ) 711 private void h_DROP() { 712 asm { naked; 713 mov EAX, [EBP]; 714 lea EBP, [EBP+CELL]; 715 ret; 716 } 717 } 718 // поменять местами два верхних элемента стека 719 // SWAP ( a b --> b a ) 720 private void h_SWAP() { 721 asm { naked; 722 mov EDX, [EBP]; 723 mov [EBP], EAX; 724 mov EAX, EDX; 725 ret; 726 } 727 } 728 // Положить копию x1 на вершину стека. 729 // OVER ( a b --> a b a ) 730 private void h_OVER() { 731 asm { naked; 732 lea EBP, [EBP-CELL]; 733 mov dword ptr SS:[EBP], EAX; 734 mov EAX, dword ptr SS:[EBP+CELL]; 735 ret; 736 } 737 } 738 // Убрать первый элемент под вершиной стека. 739 // NIP ( a b --> b ) 740 private void SP_nip() { 741 asm { naked; 742 lea EBP, [EBP+CELL]; 743 ret; 744 } 745 } 746 // Прокрутить три верхних элемента стека. 747 // ROT ( a b c --> b c a ) 748 private void SP_rot() { 749 asm { naked; 750 mov EDX, [EBP]; 751 mov [EBP], EAX; 752 mov EAX, [EBP+CELL]; 753 mov [EBP+CELL], EDX; 754 ret; 755 } 756 } 757 // Прокрутить три верхних элемента стека. 758 // -ROT ( a b c --> c a b ) 759 private void SP_minusrot() { 760 asm { naked; 761 mov EDX, [EBP+CELL]; 762 mov [EBP+CELL], EAX; 763 mov EAX, [EBP]; 764 mov [EBP], EDX; 765 ret; 766 } 767 } 768 // Положить копию верхнего элемента стека под следующий за ним. 769 // TUCK ( a b --> b a b ) 770 private void h_TUCK() { 771 asm { naked; 772 lea EBP, [EBP-CELL]; 773 mov EDX, [EBP+CELL]; 774 mov [EBP+CELL], EAX; 775 mov [EBP], EDX; 776 ret; 777 } 778 } 779 // Сделать копию верхней пары элементов стека данных 780 // DDUP ( d --> d d ) 781 private void SP_ddup() { 782 asm { naked; 783 mov EDX, [EBP]; 784 mov [EBP-CELL], EAX; 785 mov [EBP-CELL*2], EDX; 786 lea EBP, [EBP-CELL*2]; 787 ret; 788 } 789 } 790 // Убрать со стека пару ячеек x1 x2. 791 // DDROP ( d --> ) 792 private void SP_ddrop() { 793 asm { naked; 794 mov EAX, [EBP+CELL]; 795 lea EBP, [EBP+CELL*2]; 796 ret; 797 } 798 } 799 // Удалить с вершины стека данных три верхних ячейки 800 // TDROP ( n n n --> ) 801 private void SP_tdrop() { 802 asm { naked; 803 mov EAX, [EBP+CELL*2]; 804 lea EBP, [EBP+CELL*3]; 805 ret; 806 } 807 } 808 // Поменять местами две верхние пары ячеек. 809 // DSWAP ( da db --> db da ) 810 private void SP_dswap() { 811 asm { naked; 812 mov EDX, [EBP]; 813 mov EBX, [EBP+CELL]; 814 mov ECX, [EBP+CELL*2]; 815 mov [EBP+CELL*2], EDX; 816 mov [EBP+CELL], EAX; 817 mov [EBP], ECX; 818 mov EAX, EBX; 819 ret; 820 } 821 } 822 // 26-06-2005 ~mOleg 823 // Copyright [C] 2005-2013 mOleg mOlegg@ya.ru 824 // манипуляция числами на стеке возвратов 825 826 // прочесть верхнее значение со стека возвратов 827 // R@ ( r: n --> r: n d: n ) 828 private void h_R_get() { 829 asm { naked; 830 lea EBP, [EBP-CELL]; 831 mov [EBP], EAX; 832 mov EAX, [ESP+CELL]; 833 ret; 834 } 835 } 836 // Удалить одно значение с вершины стека возвратов 837 // RDROP ( r: n --> ) 838 private void SR_rdrop() { 839 asm { naked; 840 pop EBX; 841 pop EDX; 842 jmp EBX; 843 } 844 } 845 // Перенести значение со стека данных на стек возвратов 846 // >R ( d: n --> r: n ) 847 private void h_toR() { 848 asm { naked; 849 pop EBX; 850 push EAX; 851 mov EAX, [EBP]; 852 lea EBP, [EBP+CELL]; 853 jmp EBX; 854 } 855 } 856 // Перенести значение со стека возвратов на стек данных 857 // R> ( r: n --> d: n ) 858 private void h_Rto() { 859 asm { naked; 860 lea EBP, [EBP-CELL]; 861 mov [EBP], EAX; 862 pop EBX; 863 pop EAX; 864 jmp EBX; 865 } 866 } 867 // Добавить значение к тому, что лежит на вершине стека возвратов 868 // R+ ( r: a d: b --> R: a+b ) 869 private void h_R_PLUS() { 870 asm { naked; 871 pop EBX; 872 add [ESP], EAX; 873 mov EAX, [EBP]; 874 lea EBP, [EBP+CELL]; 875 jmp EBX; 876 } 877 } 878 // Поместить значение 0 на вершину ст возвратов, вернуть адрес значения 879 // 0>R' ( --> r: 0 d: RP@ ) 880 private void SR_SR_0toRadr() { 881 asm { naked; 882 mov EBX, [ESP]; 883 mov [ESP], 0; 884 lea EBP, [EBP-CELL]; 885 mov [EBP], EAX; 886 mov EAX, ESP; 887 jmp EBX; 888 } 889 } 890 // Перенести два значения на стек возвратов со стека данных 891 // D>R ( D: x1 x2 --> R: --> x1 x2 ) 892 private void SR_DtoR() { 893 asm { naked; 894 pop EBX; 895 push [EBP]; 896 push EAX; 897 lea EBP, [EBP+CELL*2]; 898 mov EAX, [EBP-CELL]; 899 jmp EBX; 900 } 901 } 902 // Вернуть два значения со стека возвратов на стек данных 903 // CODE DR> ( r: d --> D: d ) 904 private void SR_DRfrom() { 905 asm { naked; 906 mov EBX, [ESP]; 907 mov [EBP-CELL], EAX; 908 mov EDX, [ESP+CELL*2]; 909 mov EAX, [ESP+CELL]; 910 mov [EBP-CELL*2], EDX; 911 lea EBP, [EBP-CELL*2]; // замечание: выделять место на стеке нужно до 912 lea ESP, [ESP+CELL*3]; // того, как туда будут положены значения 913 jmp EBX; 914 } 915 } 916 // Прочитать на вершину стека данных два верхних значения со ст возвратов 917 // DR@ ( r: d --> r: d d: d ) 918 private void SR_DRrazm() { 919 asm { naked; 920 mov [EBP-CELL],EAX; 921 mov EAX, [ESP+CELL]; 922 mov EDX, [ESP+CELL*2]; 923 mov [EBP-CELL*2],EDX; 924 lea EBP, [EBP-8]; 925 ret; 926 } 927 } 928 929 // локальный стек данных 930 931 // прочитать значение с вершины локального стека 932 // L@ ( l: n --> l: n d: n ) 933 private void SL_get() { 934 asm { naked; 935 lea EBP, [EBP-CELL]; 936 mov [EBP], EAX; 937 mov EAX, [ESI]; 938 ret; 939 } 940 } 941 // прибавить значение с вершины стека данных, к значению на вершине локального стека 942 // L+ ( l: a d: b --> l: a+b ) 943 private void SL_add() { 944 asm { naked; 945 add [ESI], EAX; 946 mov EAX, [EBP]; 947 lea EBP, [EBP+CELL]; 948 ret; 949 } 950 } 951 // переместить значение на вершину локального стека 952 // >L ( d: n --> l: n ) 953 private void SL_toL() { 954 asm { naked; 955 lea ESI, [ESI-CELL]; 956 mov [ESI], EAX; 957 mov EAX, [EBP]; 958 lea EBP, [EBP+CELL]; 959 ret; 960 } 961 } 962 // переместить значение с вершины локального стека 963 // L> ( l: n --> d: n ) 964 private void SL_Lfrom() { 965 asm { naked; 966 lea EBP, [EBP-CELL]; 967 mov [EBP], EAX; 968 mov EAX, [ESI]; 969 lea ESI, [ESI+CELL]; 970 ret; 971 } 972 } 973 // дублировать значение на вершине локального стека 974 // LDUP ( l: n --> l: n n ) 975 private void SL_Ldup() { 976 asm { naked; 977 mov EDX, [ESI]; 978 lea ESI, [ESI-CELL]; 979 mov [ESI], EDX; 980 ret; 981 } 982 } 983 // удалить элемент с вершины локального стека 984 // LDROP ( l: n --> ) 985 private void SL_Ldrop() { 986 asm { naked; 987 lea ESI, [ESI+4]; 988 ret; 989 } 990 } 991 992 // Процедуры времени выполнения для CONSTANT, VARIABLE, etc. 993 994 // Записать значение по адресу 995 // ! ( x a-addr --> ) 996 private void h_setToAdr() { 997 asm { naked; 998 mov EDX, dword ptr SS:[EBP]; 999 mov dword ptr DS:[EAX], EDX; 1000 mov EAX, dword ptr SS:[EBP+CELL]; 1001 lea EBP, [EBP+CELL*2]; 1002 ret; 1003 } 1004 } 1005 // Прочитать значение по адресу 1006 // @ ( a-addr --> x ) 1007 private void h_getFromAdr() { 1008 asm { naked; 1009 mov EAX, DS:[EAX]; 1010 ret; 1011 } 1012 } 1013 // Получить byte по адресу c-addr. 1014 // Незначащие старшие биты ячейки нулевые. 1015 // B@ ( c-addr --> byte ) 1016 private void h_getFromAdrByte() { 1017 asm { naked; 1018 movzx EAX, byte ptr DS:[EAX]; 1019 ret; 1020 } 1021 } 1022 // Записать byte по адресу a-addr. 1023 // CODE B! ( byte c-addr --> ) 1024 private void h_setToAdrByte() { 1025 asm { naked; 1026 mov EDX, SS:[EBP]; 1027 mov byte ptr DS:[EAX],DL; 1028 mov EAX, dword ptr SS:[EBP+CELL]; 1029 lea EBP,[EBP+CELL*2]; 1030 ret; 1031 } 1032 } 1033 1034 // ======================== Проверочные слова ======================= 1035 1036 // Проверим передачу 3 параметров 1037 private void t9( int a, int b, int c) { 1038 writeln(); 1039 writeln("~~~~> ", "3 param ", a, " ", b, " ", c); 1040 } 1041 private void exec_D() { 1042 asm { naked; 1043 // mov EAX, 7; call t1; // t1(7); 1044 call h_DUP; 1045 push 2; 1046 push 3; 1047 mov EAX, 4; 1048 // mov EAX, 4; 1049 lea ECX, t9; 1050 call ECX; 1051 // call t9; 1052 call h_DROP; 1053 ret; 1054 } 1055 } 1056 1057 // int qwe = 7; 1058 1059 // Вызов внешних функций 1060 // ( .... Af -- ... ) 1061 private void callD() { 1062 asm { naked; 1063 mov ECX, EAX; // Адрес функции, для вызова CALL 1064 pop EAX; // Забираем адрес возврата из callD 1065 call SL_toL; // Прячем его во временный стек 1066 call h_DUP; 1067 call ECX; // Вызов функции по адресу 1068 mov ECX, EAX; // Сохраним Return 1069 call SL_Lfrom; // Вернем с доп стека в EAX адрес возврата из callD 1070 push EAX; // Вернем его на место 1071 mov EAX, ECX; 1072 ret; 1073 } 1074 } 1075 // LATEST ( -- Aexec) 1076 // Выдать на стек данных F адрес CFA последнего изготовленного слова 1077 private void* d_LATEST() { return &(gpcb.latest); } 1078 private void h_LATEST() { 1079 asm { naked; call h_DUP; call d_LATEST; ret; } 1080 } 1081 // CONTEXT ( -- Alfa) 1082 // Выдать на стек данных F адрес NFA последнего изготовленного слова. С этого 1083 // адреса можно перебрать всю цепочку слов в словаре 1084 private void* d_CONTEXT() { return &(gpcb.context); } 1085 private void h_CONTEXT() { 1086 asm { naked; call h_DUP; call d_CONTEXT; ret; } 1087 } 1088 // TIB ( -- Atib) 1089 // Выдать на стек данных F адрес буфера, в котором содержится исходная строка форта 1090 // для текстового разбора словом WORD 1091 private void* d_TIB() { return &(gpcb.Tib); } 1092 private void h_TIB() { 1093 asm { naked; call h_DUP; call d_TIB; ret; } 1094 } 1095 // <IN ( -- A) 1096 // Выдать на стек данных F адрес (позицию) того места, в строковом буфере, откуда 1097 // будет начинаться поиск след слова (лексемы) словом WORD 1098 private void* d_IN() { return &(gpcb.In); } 1099 private void h_IN() { 1100 asm { naked; call h_DUP; call d_IN; ret; } 1101 } 1102 // dlTib ( -- N ) 1103 // Выдать на стек данных размер строки в TIB 1104 private void* d_dlTib() { return cast(void*)gpcb.dlTib; } 1105 private void h_dlTib() { 1106 asm { naked; call h_DUP; call d_dlTib; ret; } 1107 } 1108 // ALLOT ( n -- ) 1109 // Зарезервировать в кодофайле n байт, под собственные нужды 1110 private void d_ALLOT(int n) { gpcb.here = gpcb.here + n; } 1111 private void h_ALLOT() { 1112 asm { naked; call d_ALLOT; call h_DROP; ret; } 1113 } 1114 // HERE ( -- Ahere) 1115 // Выдать позицию в кодофайле, куда будут записываться новые определяемые слова 1116 private void* d_HERE() { return gpcb.here; } 1117 private void h_HERE() { 1118 asm { naked; call h_DUP; call d_HERE; ret; } 1119 } 1120 // STATE ( -- Ahere) 1121 // Выдать состояние переменной, показывающий в компиляции или интерпретации сейчас 1122 // мы находимся. TRUE=компиляция, FALSE=интерпретация 1123 private void* d_STATE() { return &gpcb.state; } 1124 private void h_STATE() { 1125 asm { naked; call h_DUP; call d_STATE; ret; } 1126 } 1127 // COMMONADR ( -- A ) 1128 // Выдать указатель на начало общей таблицы CommonAdr 1129 private void* d_COMMONADR() { return gpcb.adrCommonTable; } 1130 private void h_COMMONADR() { 1131 asm { naked; call h_DUP; call d_COMMONADR; ret; } 1132 } 1133 // : PLACE ( # --> addr ) HERE SWAP ALLOT ; 1134 // Указатель на начало "дырки" свободной области в кодофайле 1135 private void h_PLACE() { 1136 asm { naked; 1137 call h_HERE; 1138 call h_SWAP; 1139 call h_ALLOT; 1140 ret; 1141 } 1142 } 1143 // Зарезервировать одну ячейку в области данных и поместить x в эту ячейку. 1144 // : , ( x --> ) CELL PLACE ! ; 1145 private void h_zpt() { 1146 asm { naked; 1147 // int 3; 1148 call h_DUP; mov EAX, CELL; 1149 call h_PLACE; 1150 call h_setToAdr; 1151 ret; 1152 } 1153 } 1154 // Зарезервировать одну ячейку в области данных и поместить x в эту ячейку. 1155 // : B, ( x --> ) 1 PLACE B! ; 1156 private void h_Bzpt() { 1157 asm { naked; 1158 call h_DUP; mov EAX, 1; 1159 call h_PLACE; 1160 call h_setToAdrByte; 1161 ret; 1162 } 1163 } 1164 1165 // -------------------------- compie.f ------------------------- 1166 1167 // \ 31-01-2007 ~mOleg 1168 // \ Copyright [C] 1992-1999 A.Cherezov ac@forth.org 1169 // \ Компиляция. 1170 1171 // \ скомпилировать адрес следующего токена в текущее определение 1172 // \ классический не-immediate вариант. Не работает со immediate словами 1173 // : COMPILE ( r: addr --> ) AR@ TOKEN@ TOKEN R+ COMPILE, ; 1174 private void h_COMPILE() { 1175 asm { naked; 1176 call h_R_get; // R@ 1177 call f_TOKEN_get; 1178 call f_TOKEN; 1179 call h_R_PLUS; 1180 call h_COMPILEzpt; 1181 ret; 1182 } 1183 } 1184 // скомпилировать инструкцию INT3 1185 // : INT3, ( --> ) 0xCC B, ; 1186 private void h_INT3zpt() { 1187 asm { naked; 1188 call h_DUP; mov EAX, 0xCC; 1189 call h_Bzpt; 1190 ret; 1191 } 1192 } 1193 // скомпилировать инструкцию RET 1194 // : RET, ( --> ) 0xC3 B, ; 1195 private void h_RETzpt() { 1196 asm { naked; 1197 call h_DUP; mov EAX, 0xC3; 1198 call h_Bzpt; 1199 ret; 1200 } 1201 } 1202 // скомпилировать инструкцию CALL √ 1203 // : CALL, ( --> ) 0xE8 B, ; 1204 private void h_CALLzpt() { 1205 asm { naked; 1206 call h_DUP; mov EAX, 0xE8; 1207 call h_Bzpt; 1208 ret; 1209 } 1210 } 1211 // \ компилировать вызов указанного xt √ 1212 // : COMPILE, ( xt --> ) CALL, <resolve ; 1213 private void h_COMPILEzpt() { 1214 asm { naked; 1215 call h_CALLzpt; 1216 call f_L_resolve; 1217 ret; 1218 } 1219 } 1220 // \ компилировать безусловный переход на указанный адрес √ 1221 // : JUMP, ( addr --> ) 0xE9 B, <resolve ; 1222 private void h_JUMPzpt() { 1223 asm { naked; 1224 call h_DUP; mov EAX, 0xE9; 1225 call h_Bzpt; 1226 call f_L_resolve; 1227 ret; 1228 } 1229 } 1230 // ???????????????????????? Возможно ошибочное словл 1231 // \ компилировать код, возвращающий число в текущее определение 1232 // : LIT, ( N --> ) COMPILE (LIT) , ; 1233 private void h_LITzpt() { 1234 asm { naked; 1235 call h_COMPILE; 1236 call h_s_LIT_s; 1237 call h_zpt; 1238 } 1239 } 1240 // Шитое слово TRUE 1241 // -1 CONSTANT TRUE 1242 private void f_TRUE() { 1243 asm { naked; 1244 call f_s_CONST_s; 1245 di 0xFFFFFFFF; 1246 } 1247 } 1248 // Шитое слово TRUE 1249 // -1 CONSTANT TRUE 1250 private void f_FALSE() { 1251 asm { naked; 1252 call f_s_CONST_s; 1253 di 0x0; 1254 } 1255 } 1256 // Шитое слово BL 1257 // 32 CONSTANT BL 1258 private void f_BL() { 1259 asm { naked; 1260 call f_s_CONST_s; 1261 di 0x20; 1262 } 1263 } 1264 // CODE [ - начать интерпретацию 1265 private void h_COMP_OFF() { 1266 asm { naked; 1267 call f_FALSE; 1268 call h_STATE; 1269 call h_setToAdr; 1270 ret; 1271 } 1272 } 1273 // CODE ] - начать компиляцию 1274 private void h_COMP_ON() { 1275 asm { naked; 1276 call f_TRUE; 1277 call h_STATE; 1278 call h_setToAdr; 1279 ret; 1280 } 1281 } 1282 // DUMP ( A -- ) Распечатать указанный адрес 1283 void h_zz(pp adr) { 1284 writeln("- dump -- dump -- dump -- dump -- dump -"); 1285 dumpAdr(adr); 1286 writeln("- dump -- dump -- dump -- dump -- dump -"); 1287 } 1288 void h_dump() { 1289 asm { naked; 1290 call h_zz; 1291 call h_DROP; 1292 ret; 1293 } 1294 } 1295 // Выдать тип OS W - windows, L - Linux 1296 void h_osname() { 1297 version(Windows) { 1298 asm { naked; 1299 call h_DUP; 1300 mov EAX, 87; 1301 ret; 1302 } 1303 } 1304 version(linux) { 1305 asm { naked; 1306 call h_DUP; 1307 mov EAX, 76; 1308 ret; 1309 } 1310 } 1311 } 1312 // Вернуть на стек адрес функции LoadLibrary 1313 pp h_LoadLibrary() { 1314 pp rez; 1315 version(Windows) { 1316 import core.sys.windows.windows: LoadLibraryA ; 1317 rez = cast(pp)&LoadLibraryA; 1318 } 1319 return rez; 1320 } 1321 void f_LoadLibraryA() { 1322 asm { naked; 1323 call h_DUP; 1324 call h_LoadLibrary; 1325 ret; 1326 } 1327 } 1328 pp h_DlOpen() { 1329 pp rez; 1330 version(linux) { 1331 import core.sys.posix.dlfcn; // Определения dlopen() и dlsym() 1332 rez = cast(pp)&dlopen; 1333 } 1334 return rez; 1335 } 1336 void f_DlOpen() { 1337 asm { naked; 1338 call h_DUP; 1339 call h_DlOpen; 1340 ret; 1341 } 1342 } 1343 // Вернуть на стек адрес функции GetProcAdres 1344 pp h_GetPrAdressA() { 1345 pp rez; 1346 version(Windows) { 1347 import core.sys.windows.windows: GetProcAddress ; 1348 rez = cast(pp)&GetProcAddress; 1349 } 1350 return rez; 1351 } 1352 void f_GetPrAdressA() { 1353 asm { naked; 1354 call h_DUP; 1355 call h_GetPrAdressA; 1356 ret; 1357 } 1358 } 1359 pp h_DlSym() { 1360 pp rez; 1361 version(linux) { 1362 import core.sys.posix.dlfcn; // Определения dlopen() и dlsym() 1363 rez = cast(pp)&dlsym; 1364 } 1365 return rez; 1366 } 1367 void f_DlSym() { 1368 asm { naked; 1369 call h_DUP; 1370 call h_DlSym; 1371 ret; 1372 } 1373 } 1374 1375 1376 // use std.stdout instead of std.c.stdio.stdout 1377 1378 pp h_getSTDOUT() { 1379 // Linux 1380 import core.stdc.stdio; 1381 return cast(pp)(core.stdc.stdio.stdout); 1382 } 1383 // Выдать на стек стандартный указатель на stdout 1384 void getSTDOUT() { 1385 asm { naked; 1386 call h_DUP; 1387 call h_getSTDOUT; 1388 ret; 1389 } 1390 } 1391 1392 // TYPE ( A -- ) Распечатать строку на консоли 1393 void h_TYPE(ps adr) { 1394 printf("%s", adr); stdout.flush(); 1395 } 1396 void f_TYPE() { 1397 asm { naked; 1398 call h_TYPE; 1399 call h_DROP; 1400 ret; 1401 } 1402 } 1403 1404 // CMOVE ( Afrom Ato N -- ) Скопировать байты 1405 private void h_bmove(int n, ps to, ps from) { 1406 import core.stdc..string : memcpy; 1407 memcpy(to, from, n); 1408 } 1409 private void f_bmove() { 1410 asm { naked; 1411 push EAX; 1412 call h_DROP; 1413 push EAX; 1414 call h_DROP; 1415 call h_bmove; 1416 call h_DROP; 1417 ret; 1418 } 1419 } 1420 1421 // Странное слово. Понятно, что вызывается, когда есть ветка с исключительной 1422 // ситуацией. По идее, должно проинформировать и корректно прервать 1423 // программу 1424 private void h_THROW(int n) { 1425 writeln(); 1426 writeln("[", n, "]", " THROW - error, this mast find ..."); 1427 } 1428 private void f_THROW() { 1429 asm { naked; call h_THROW; call h_DROP; ret; } 1430 } 1431 // ?COMP - разрешено только при компиляции 1432 // private void f_ZNW_COMP() { 1433 // asm { naked; call h_DUP; mov EAX, 1; call h_THROW; ret; } 1434 // } 1435 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1436 1437 // Обработка вызова слота Slot_A_N_v 1438 // Выдать адрес обработчика для вызова функции с параметрами A и N 1439 private void* h_A_CALL_AN() { return &executeForth_A_N; } 1440 // Forth слово: выдать адрес обработчика для вызова функции с параметрами A и N 1441 private void f_A_CALL_AN() { 1442 asm { naked; 1443 call h_DUP; 1444 call h_A_CALL_AN; 1445 ret; 1446 } 1447 } 1448 // Обработка вызова слота Slot_A_N_v 1449 extern (C) void executeForth_A_N(pp adr, int n) { 1450 writeln("this is Call from C witch adr = ", adr, " n = ", n); 1451 executeForth(adr, 1, n); 1452 } 1453 1454 // Выполнить адрес через EXECUTE 1455 extern (C) pp executeForth(pp adrexec, uint kolPar, ...) { 1456 pp Adr_execD = gpcb.executeFromD; // ' EXECUTEFROMD 1457 // writeln("Adr_execD = ", Adr_execD, " adrexec = ", adrexec, " kolPar = ", kolPar); 1458 pp ret; // Место под возвращаемое значение 1459 NPcb npcb = gpcb; // Возможность работы с PCB (контекст) переменными в ASM 1460 pp adrKolPar = cast(pp)&kolPar; // Адрес количества параметров 1461 asm { 1462 align 4; 1463 // Сохраним регистры D 1464 push EBX; push ESI; push EAX; push ECX; push EDX; push EBP; 1465 // -------------------- 1466 // Запишем наши параметры 1467 push Adr_execD; // Адрес xt специальный слова в Forth (EXECUTEFROMD) 1468 push adrexec; // Адпес слова Forth которое будет выполнено из EXECUTEFROMD 1469 push adrKolPar; // Адрес количества параметров для передачи в Форт 1470 // Востановим регитры F 1471 mov EAX, npcb.saveEAX.offsetof[npcb]; 1472 mov ESI, npcb.saveESI.offsetof[npcb]; 1473 mov EDI, npcb.saveEDI.offsetof[npcb]; 1474 mov EBP, npcb.saveEBP.offsetof[npcb]; 1475 call h_DUP; // Сохраним то что было на вершине стека Форта 1476 pop EAX; // На веншину SD количество пораметров 1477 call h_DUP; // Сохраним,освободив вершину SD 1478 pop EAX; // На веншину SD адрес вызываемого слова 1479 call h_DUP; // Сохраним,освободив вершину SD 1480 pop EAX; // На вершине SD адрес EXECUTEFROMD 1481 call f_EXECUTE; // Вызов EXECUTEFROMD 1482 // mov EBX, EAX; // Сохранить возвращаемое значение 1483 mov ret, EAX; 1484 call h_DROP; // Выкинуть со стека в форте, так как вызов внешний 1485 1486 // Сохраним F 1487 mov ECX, EBP; 1488 pop EBP; 1489 mov npcb.saveEAX.offsetof[npcb], EAX; 1490 mov npcb.saveEBP.offsetof[npcb], ECX; // Сохраним запомненный EBP 1491 mov npcb.saveESI.offsetof[npcb], ESI; 1492 mov npcb.saveEDI.offsetof[npcb], EDI; 1493 // mov ret, EBX; 1494 // ---------------------- 1495 // Восстановим регистры D 1496 pop EDX; pop ECX; pop EAX; pop ESI; pop EBX; 1497 } 1498 gpcb.saveEBP = npcb.saveEBP; // Возможность работы с PCB (контекст) переменными в ASM 1499 gpcb.saveEAX = npcb.saveEAX; // Возможность работы с PCB (контекст) переменными в ASM 1500 gpcb.saveESI = npcb.saveESI; // Возможность работы с PCB (контекст) переменными в ASM 1501 gpcb.saveEDI = npcb.saveEDI; // Возможность работы с PCB (контекст) переменными в ASM 1502 return ret; 1503 } 1504 1505 void evalForth(char *str) { 1506 evalForth(to!string(str)); 1507 } 1508 void evalForth(string str) { 1509 // Linux корректировка 1510 if(str.length>0 && str[$-1]==13) str.length = str.length-1; 1511 1512 gpcb.dlTib = str.length; // Запишем длину строки в gpcb 1513 gpcb.In = cast(ps)gpcb.Tib; // указатель смещения во входном буфере 1514 for(int i; i != str.length; i++) tib[i] = cast(ubyte)str[i]; 1515 NPcb npcb = gpcb; // Возможность работы с PCB (контекст) переменными в ASM 1516 asm { 1517 align 4; 1518 // Сохраним регистры D 1519 push EBX; push ESI; push EAX; push ECX; push EDX; push EBP; 1520 // -------------------- 1521 // Востановим регитры F 1522 // int 3; 1523 mov EAX, npcb.saveEAX.offsetof[npcb]; 1524 mov ESI, npcb.saveESI.offsetof[npcb]; 1525 mov EDI, npcb.saveEDI.offsetof[npcb]; 1526 mov EBP, npcb.saveEBP.offsetof[npcb]; 1527 1528 call f_inter; 1529 1530 // Сохраним F 1531 mov ECX, EBP; 1532 pop EBP; 1533 mov npcb.saveEAX.offsetof[npcb], EAX; 1534 mov npcb.saveEBP.offsetof[npcb], ECX; // Сохраним запомненный EBP 1535 mov npcb.saveESI.offsetof[npcb], ESI; 1536 mov npcb.saveEDI.offsetof[npcb], EDI; 1537 // ---------------------- 1538 // Восстановим регистры D 1539 pop EDX; pop ECX; pop EAX; pop ESI; pop EBX; 1540 } 1541 gpcb.saveEBP = npcb.saveEBP; // Возможность работы с PCB (контекст) переменными в ASM 1542 gpcb.saveEAX = npcb.saveEAX; // Возможность работы с PCB (контекст) переменными в ASM 1543 gpcb.saveESI = npcb.saveESI; // Возможность работы с PCB (контекст) переменными в ASM 1544 gpcb.saveEDI = npcb.saveEDI; // Возможность работы с PCB (контекст) переменными в ASM 1545 } 1546 // Записать в общую таблицу адрес adr в ячейку с номером n 1547 void setCommonAdr(int n, pp adr) { commonTable[n] = adr; } 1548 // Прочитать из общий таблицы адрес в ячейке n 1549 pp getCommonAdr(int n) { return commonTable[n]; } 1550 // Инициализировать Forth и подготовить его к работе 1551 1552 void initForth() { 1553 kdf = cast(pb)(new uint[sizeCodeFile]).ptr; // Изготовим кодофайл на sizeCodeFile адр 1554 NPcb npcb = gpcb; 1555 npcb.adrCommonTable = cast(pp)commonTable.ptr; 1556 const sizeSt = sizeStack; // По sizeStack CELL на каждый стек 1557 // uint[sizeSt] stSD, stSR, stSL; // Память под стеки 1558 stSD = cast(pp)(new uint[sizeSt]); // Запомнить начало области SP в глобальной переменной 1559 npcb.csd = stSD + sizeSt - 1; // Запомнить вершину стека SP в контексте 1560 1561 // npcb.csr = cast(pp)stSR[sizeSt-1]; ---> Совмещен со стеком D 1562 stSL = cast(pp)(new uint[sizeSt]); // Запомнить начало SP в глобальной переменной 1563 npcb.csc = stSL + sizeSt - 1; // Запомнить вершину SL в контексте 1564 1565 npcb.here = kdf; // HERE на начало буфера 1566 npcb.context = cast(pp)kdf; // Вектор context лежит в начале кодофайла 1567 npcb.akdf = cast(pp)kdf; // Указатель на кодофайл 1568 npcb.Tib = cast(ps)&tib; // Указатель на входной буфер текста 1569 // npcb._Tib = cast(ps)&_tib; // ??? не используется // Указатель на входной буфер WORD 1570 npcb.In = cast(ps)&tib; // указатель смещения во входном буфере 1571 asm { 1572 align 4; 1573 // Сохраним регистры D 1574 push EBX; push ESI; push EAX; push ECX; push EDX; push EBP; 1575 // -------------------- 1576 // В ESI запомним указатель на доп стек SL 1577 lea EAX, npcb.csc.offsetof[npcb]; 1578 mov ESI, DS:[EAX]; 1579 // Из контекста возьмем указатель на стек данных ... 1580 lea EAX, npcb.csd.offsetof[npcb]; 1581 mov EAX, DS:[EAX]; 1582 call SP_set; // ... и инициализируем его 1583 mov EAX, ESI; call LP_set; // Стек дополнительный для Форк 1584 // Сохраним F 1585 mov ECX, EBP; 1586 pop EBP; 1587 mov npcb.saveEAX.offsetof[npcb], EAX; 1588 mov npcb.saveEBP.offsetof[npcb], ECX; // Сохраним запомненный EBP 1589 mov npcb.saveESI.offsetof[npcb], ESI; 1590 mov npcb.saveEDI.offsetof[npcb], EDI; 1591 // ---------------------- 1592 // Восстановим регистры D 1593 pop EDX; pop ECX; pop EAX; pop ESI; pop EBX; 1594 } 1595 // writeln("Local PCB: ", npcb); 1596 gpcb = npcb; 1597 // Надо выделить 256 CELL для хранения цепочек context 1598 pb u = gpcb.here; for(int i; i != (256 * CELL); i++) *u = 0; 1599 gpcb.here = gpcb.here + (256 * CELL); 1600 // Перенесём сюда определение HARD слов 1601 CreateVocItem(cast(char*)"\3EXD".ptr, cast(pp)&exec_D, &gpcb.context); 1602 CreateVocItem(cast(char*)"\6CALL_A".ptr,cast(pp)&callD, &gpcb.context); 1603 CreateVocItem(cast(char*)"\7CONTEXT".ptr, cast(pp)&h_CONTEXT, &gpcb.context); 1604 CreateVocItem(cast(char*)"\4JUMP".ptr, cast(pp)&f_JUMP, &gpcb.context); 1605 CreateVocItem(cast(char*)"\4EXIT".ptr, cast(pp)&f_EXIT, &gpcb.context); 1606 CreateVocItem(cast(char*)"\3NIP".ptr, cast(pp)&SP_nip, &gpcb.context); 1607 CreateVocItem(cast(char*)"\3ROT".ptr, cast(pp)&SP_rot, &gpcb.context); 1608 CreateVocItem(cast(char*)"\4-ROT".ptr, cast(pp)&SP_minusrot, &gpcb.context); 1609 CreateVocItem(cast(char*)"\3D>R".ptr, cast(pp)&SR_DtoR, &gpcb.context); 1610 CreateVocItem(cast(char*)"\3DR>".ptr, cast(pp)&SR_DRfrom, &gpcb.context); 1611 // CreateVocItem(cast(char*)"\5?COMP".ptr, cast(pp)&f_ZNW_COMP, &gpcb.context); 1612 1613 CreateVocItem(cast(char*)"\6OSNAME".ptr, cast(pp)&h_osname, &gpcb.context); 1614 1615 CreateVocItem(cast(char*)"\10(STDOUT)".ptr, cast(pp)&getSTDOUT, &gpcb.context); 1616 1617 CreateVocItem(cast(char*)"\14LOADLIBRARYA".ptr, cast(pp)&f_LoadLibraryA, &gpcb.context); 1618 CreateVocItem(cast(char*)"\10GPADRESS".ptr, cast(pp)&f_GetPrAdressA, &gpcb.context); 1619 CreateVocItem(cast(char*)"\6DLOPEN".ptr, cast(pp)&f_DlOpen, &gpcb.context); 1620 CreateVocItem(cast(char*)"\5DLSYM".ptr, cast(pp)&f_DlSym, &gpcb.context); 1621 1622 CreateVocItem(cast(char*)"\2L@".ptr, cast(pp)&SL_get, &gpcb.context); 1623 CreateVocItem(cast(char*)"\2L+".ptr, cast(pp)&SL_add, &gpcb.context); 1624 CreateVocItem(cast(char*)"\2>L".ptr, cast(pp)&SL_toL, &gpcb.context); 1625 CreateVocItem(cast(char*)"\2L>".ptr, cast(pp)&SL_Lfrom, &gpcb.context); 1626 CreateVocItem(cast(char*)"\4LDUP".ptr, cast(pp)&SL_Ldup, &gpcb.context); 1627 CreateVocItem(cast(char*)"\5LDROP".ptr, cast(pp)&SL_Ldrop, &gpcb.context); 1628 1629 CreateVocItem(cast(char*)"\3SP!".ptr, cast(pp)&SP_set, &gpcb.context); 1630 CreateVocItem(cast(char*)"\3SP@".ptr, cast(pp)&SP_get, &gpcb.context); 1631 CreateVocItem(cast(char*)"\3RP!".ptr, cast(pp)&RP_set, &gpcb.context); 1632 CreateVocItem(cast(char*)"\3RP@".ptr, cast(pp)&RP_get, &gpcb.context); 1633 CreateVocItem(cast(char*)"\3LP!".ptr, cast(pp)&LP_set, &gpcb.context); 1634 CreateVocItem(cast(char*)"\3LP@".ptr, cast(pp)&LP_get, &gpcb.context); 1635 // CreateVocItem(cast(char*)"\2T5".ptr, cast(pp)&t5, &gpcb.context); 1636 // CreateVocItem(cast(char*)"\3TCW".ptr, cast(pp)&TestCompileWord, &gpcb.context); 1637 CreateVocItem(cast(char*)"\5INT3,".ptr, cast(pp)&h_INT3zpt, &gpcb.context); 1638 CreateVocItem(cast(char*)"\3<IN".ptr, cast(pp)&h_IN, &gpcb.context); 1639 CreateVocItem(cast(char*)"\3TIB".ptr, cast(pp)&h_TIB, &gpcb.context); 1640 CreateVocItem(cast(char*)"\5DLTIB".ptr, cast(pp)&h_dlTib, &gpcb.context); 1641 CreateVocItem(cast(char*)"\4NOOP".ptr, cast(pp)&f_NOOP, &gpcb.context); 1642 1643 CreateVocItem(cast(char*)"\4DUMP".ptr, cast(pp)&h_dump, &gpcb.context); 1644 CreateVocItem(cast(char*)"\5RDROP".ptr, cast(pp)&SR_rdrop, &gpcb.context); 1645 CreateVocItem(cast(char*)"\5DDROP".ptr, cast(pp)&SP_ddrop, &gpcb.context); 1646 CreateVocItem(cast(char*)"\4DDUP".ptr, cast(pp)&SP_ddup, &gpcb.context); 1647 CreateVocItem(cast(char*)"\2>R".ptr, cast(pp)&h_toR, &gpcb.context); 1648 CreateVocItem(cast(char*)"\2R>".ptr, cast(pp)&h_Rto, &gpcb.context); 1649 CreateVocItem(cast(char*)"\2R+".ptr, cast(pp)&h_R_PLUS, &gpcb.context); 1650 CreateVocItem(cast(char*)"\2R@".ptr, cast(pp)&h_R_get, &gpcb.context); 1651 CreateVocItem(cast(char*)"\2B,".ptr, cast(pp)&h_Bzpt, &gpcb.context); 1652 CreateVocItem(cast(char*)"\4REF,".ptr, cast(pp)&f_REFzpt, &gpcb.context); 1653 1654 CreateVocItem(cast(char*)"\5(LIT)".ptr, cast(pp)&h_s_LIT_s, &gpcb.context); 1655 CreateVocItem(cast(char*)"\4RET,".ptr, cast(pp)&h_RETzpt, &gpcb.context); 1656 // ????? CreateVocItem(cast(char*)"\4LIT,".ptr, cast(pp)&h_LITzpt, &gpcb.context); 1657 CreateVocItem(cast(char*)"\4TUCK".ptr, cast(pp)&h_TUCK, &gpcb.context); 1658 CreateVocItem(cast(char*)"\3DUP".ptr, cast(pp)&h_DUP, &gpcb.context); 1659 CreateVocItem(cast(char*)"\4SWAP".ptr, cast(pp)&h_SWAP, &gpcb.context); 1660 CreateVocItem(cast(char*)"\4DROP".ptr, cast(pp)&h_DROP, &gpcb.context); 1661 CreateVocItem(cast(char*)"\4OVER".ptr, cast(pp)&h_OVER, &gpcb.context); 1662 CreateVocItem(cast(char*)"\1+".ptr, cast(pp)&h_PLUS, &gpcb.context); 1663 CreateVocItem(cast(char*)"\1*".ptr, cast(pp)&h_ZW, &gpcb.context); 1664 CreateVocItem(cast(char*)"\1/".ptr, cast(pp)&h_ZD, &gpcb.context); 1665 CreateVocItem(cast(char*)"\1%".ptr, cast(pp)&h_ZP, &gpcb.context); 1666 CreateVocItem(cast(char*)"\1-".ptr, cast(pp)&h_MINUS, &gpcb.context); 1667 CreateVocItem(cast(char*)"\1=".ptr, cast(pp)&f_RAWNO, &gpcb.context); 1668 CreateVocItem(cast(char*)"\2<>".ptr, cast(pp)&f_NRAWNO, &gpcb.context); 1669 CreateVocItem(cast(char*)"\1<".ptr, cast(pp)&f_MENSHE, &gpcb.context); 1670 CreateVocItem(cast(char*)"\1>".ptr, cast(pp)&f_BOLSHE, &gpcb.context); 1671 1672 CreateVocItem(cast(char*)("\2" ~ "1+").ptr, cast(pp)&h_inc, &gpcb.context); 1673 CreateVocItem(cast(char*)("\2" ~ "1-").ptr, cast(pp)&h_dec, &gpcb.context); 1674 1675 CreateVocItem(cast(char*)"\4CELL".ptr, cast(pp)&f_CELL, &gpcb.context); 1676 CreateVocItem(cast(char*)"\3REF".ptr, cast(pp)&f_REF, &gpcb.context); 1677 CreateVocItem(cast(char*)"\5PLACE".ptr, cast(pp)&h_PLACE, &gpcb.context); 1678 CreateVocItem(cast(char*)"\5ALLOT".ptr, cast(pp)&h_ALLOT, &gpcb.context); 1679 1680 // ========== Странные шитые слова ============= 1681 CreateVocItem(cast(char*)"\4TRUE".ptr, cast(pp)&f_TRUE, &gpcb.context); 1682 CreateVocItem(cast(char*)"\5FALSE".ptr, cast(pp)&f_FALSE, &gpcb.context); 1683 CreateVocItem(cast(char*)"\5STATE".ptr, cast(pp)&h_STATE, &gpcb.context); 1684 CreateVocItem(cast(char*)"\3IMM".ptr, cast(pp)&f_getIMM, &gpcb.context); 1685 CreateVocItem(cast(char*)"\2BL".ptr, cast(pp)&f_BL, &gpcb.context); 1686 CreateVocItem(cast(char*)"\3CFL".ptr, cast(pp)&f_CFL, &gpcb.context); 1687 CreateVocItem(cast(char*)"\5TOKEN".ptr, cast(pp)&f_TOKEN, &gpcb.context); 1688 CreateVocItem(cast(char*)"\6TOKEN@".ptr, cast(pp)&f_TOKEN_get, &gpcb.context); 1689 CreateVocItem(cast(char*)"\6TOKEN!".ptr, cast(pp)&f_TOKEN_set, &gpcb.context); 1690 CreateVocItem(cast(char*)"\4WORD".ptr, cast(pp)&f_word, &gpcb.context); 1691 CreateVocItem(cast(char*)"\4FIND".ptr, cast(pp)&f_find, &gpcb.context); 1692 CreateVocItem(cast(char*)"\4HERE".ptr, cast(pp)&h_HERE, &gpcb.context); 1693 CreateVocItem(cast(char*)"\6NUMBER".ptr, cast(pp)&h_NUMBER, &gpcb.context); 1694 CreateVocItem(cast(char*)"\11COMMONADR".ptr,cast(pp)&h_COMMONADR, &gpcb.context); 1695 CreateVocItem(cast(char*)"\1.".ptr, cast(pp)&h_tck, &gpcb.context); 1696 CreateVocItem(cast(char*)"\1[".ptr, cast(pp)&h_COMP_OFF, &gpcb.context, 1); 1697 CreateVocItem(cast(char*)"\1]".ptr, cast(pp)&h_COMP_ON, &gpcb.context); 1698 CreateVocItem(cast(char*)"\1:".ptr, cast(pp)&h_dwoetoc, &gpcb.context); 1699 CreateVocItem(cast(char*)"\1;".ptr, cast(pp)&h_tckzpt, &gpcb.context, 1); 1700 1701 // ========== kernel\vm\STC\BASE\memory.f ============= 1702 CreateVocItem(cast(char*)"\1@".ptr, cast(pp)&h_getFromAdr, &gpcb.context); 1703 CreateVocItem(cast(char*)"\1!".ptr, cast(pp)&h_setToAdr, &gpcb.context); 1704 CreateVocItem(cast(char*)"\2B@".ptr, cast(pp)&h_getFromAdrByte, &gpcb.context); 1705 CreateVocItem(cast(char*)"\2B!".ptr, cast(pp)&h_setToAdrByte,&gpcb.context); 1706 CreateVocItem(cast(char*)"\5BMOVE".ptr, cast(pp)&f_bmove, &gpcb.context); 1707 1708 // ========== List words for call from C++ QtE5 ============= 1709 CreateVocItem(cast(char*)"\11A_CALL_AN".ptr, cast(pp)&f_A_CALL_AN, &gpcb.context); 1710 1711 // ========== kernel\vm\STC\BASE\ ...... ============= ссылки 1712 CreateVocItem(cast(char*)"\5>MARK".ptr, cast(pp)&f_R_MARK, &gpcb.context); 1713 CreateVocItem(cast(char*)"\5<MARK".ptr, cast(pp)&f_L_MARK, &gpcb.context); 1714 CreateVocItem(cast(char*)"\10<RESOLVE".ptr, cast(pp)&f_L_RESOLVE, &gpcb.context); 1715 CreateVocItem(cast(char*)"\10RESOLVE>".ptr, cast(pp)&f_RESOLVE_R, &gpcb.context); 1716 CreateVocItem(cast(char*)"\7?BRANCH".ptr, cast(pp)&f_ZW_BRANCH, &gpcb.context); 1717 CreateVocItem(cast(char*)"\6BRANCH".ptr, cast(pp)&f_BRANCH, &gpcb.context); 1718 CreateVocItem(cast(char*)"\6LATEST".ptr, cast(pp)&h_LATEST, &gpcb.context); 1719 CreateVocItem(cast(char*)"\5THROW".ptr, cast(pp)&f_THROW, &gpcb.context); 1720 1721 // ========== Компиляция ============= 1722 CreateVocItem(cast(char*)"\1,".ptr, cast(pp)&h_zpt, &gpcb.context); 1723 CreateVocItem(cast(char*)"\5JUMP,".ptr, cast(pp)&h_JUMPzpt, &gpcb.context); 1724 CreateVocItem(cast(char*)"\10COMPILE,".ptr, cast(pp)&h_COMPILEzpt, &gpcb.context); 1725 CreateVocItem(cast(char*)"\7COMPILE".ptr, cast(pp)&h_COMPILE, &gpcb.context); 1726 CreateVocItem(cast(char*)"\10(CREATE)".ptr, cast(pp)&f_s_CREATE_s, &gpcb.context); 1727 1728 CreateVocItem(cast(char*)"\6CREATE".ptr, cast(pp)&h_CREATE, &gpcb.context); 1729 CreateVocItem(cast(char*)"\7EXECUTE".ptr, cast(pp)&f_EXECUTE, &gpcb.context); 1730 1731 CreateVocItem(cast(char*)"\4TYPE".ptr, cast(pp)&f_TYPE, &gpcb.context); 1732 CreateVocItem(cast(char*)"\10INCLUDED".ptr, cast(pp)&f_INCLUDED, &gpcb.context); 1733 1734 /* // Проверим вектор context 1735 pp[256]* vect = cast(pp[256]*)gpcb.context; 1736 1737 writeln((*vect)); 1738 asm { int 3; } 1739 */ // *cast(pp)(gpcb.here) = (*vect)[b1b]; // запись LFA, то что лежало в ячейке vect[69] 1740 1741 1742 // Работа со словарной статьёй 1743 evalForth(": C@ B@ ; : C! B! ; : CFA>NFA DUP 6 - C@ 8 + - ; : CFA>LFA CELL - ; : NFA>LFA DUP C@ DUP + + ; : LFA>NFA CELL + CFA>NFA ; : NFA>CFA NFA>LFA CELL + ;"); 1744 // Классический Immediate 1745 evalForth(": IMMEDIATE 1 LATEST @ 1 CELL + - B! ;"); 1746 // Create Does> - классика 1747 evalForth(": (JOIN) R> LATEST @ TOKEN! ; : (DOES) R> R> SWAP EXECUTE ; : DOES> COMPILE (JOIN) COMPILE (DOES) ; IMMEDIATE"); 1748 // Constant и Variable 1749 evalForth(": CONST CREATE COMPILE (CREATE) , DOES> @ ; : VAR CREATE 0 COMPILE (CREATE) , DOES> ;"); 1750 // Комментарий 1751 evalForth(r": \ TIB @ DLTIB + <IN ! ; IMMEDIATE : // TIB @ DLTIB + <IN ! ; IMMEDIATE"); 1752 // IF ELSE THEN 1753 evalForth(": IF COMPILE ?BRANCH CELL ALLOT >MARK ; IMMEDIATE"); 1754 evalForth(": ELSE COMPILE BRANCH CELL ALLOT >MARK SWAP RESOLVE> ; IMMEDIATE"); 1755 evalForth(": THEN RESOLVE> ; IMMEDIATE"); 1756 // BEGIN WHILE UNTIL 1757 evalForth(": BEGIN <MARK ; IMMEDIATE : WHILE COMPILE ?BRANCH CELL ALLOT >MARK ; IMMEDIATE"); 1758 evalForth(": REPEAT COMPILE BRANCH SWAP <RESOLVE RESOLVE> ; IMMEDIATE"); 1759 evalForth(": UNTIL COMPILE ?BRANCH <RESOLVE ; IMMEDIATE"); 1760 // Работа с символами 1761 // LITERAL ( n --> \\ --> n ) I (ни чего не делать), С (закомпилировать код выкл на стек) 1762 evalForth(": LIT, COMPILE (LIT) , ; : LITERAL STATE @ IF LIT, THEN ; : [CHAR] BL WORD 1+ C@ LITERAL ; IMMEDIATE"); 1763 evalForth(": ' BL WORD DUP IF FIND DUP IF ELSE 3 THROW DROP THEN ELSE 2 THROW DROP THEN ;"); 1764 // ['] Найти xt идущего следом слова и закомпилировать его в новое определение 1765 // BOX - обойти данные в коде, начинающиеся со следующей ячейки, вернуть адрес начала данных 1766 evalForth(": ['] ' LIT, ; IMMEDIATE : (BOX) R@ DUP B@ 2 + R+ ;"); 1767 evalForth(`: S" [CHAR] " STATE @ IF COMPILE (BOX) WORD ELSE WORD DUP THEN B@ 2 + ALLOT ; IMMEDIATE`); 1768 // Работа с векторами 1769 // VECT ( / name --> ) Создать слово, которое передаёт управление по JMP на NOOP 1770 evalForth(": VECT CREATE ['] NOOP JUMP, ;"); 1771 // LITERAL ( n --> \\ --> n ) I (ни чего не делать), С (закомпилировать код выкл на стек) 1772 // evalForth(": LITERAL STATE @ IF LIT, THEN ;"); 1773 // REGULAR ( xt --> ) I (исполнить слово), С (закомпилировать в определение) 1774 evalForth(": REGULAR STATE @ IF COMPILE, ELSE EXECUTE THEN ; : CELLS CELL * ; "); 1775 // IS ( xt / name --> ) Присвоить значение вектору, HAS ( / name --> xt ) получить значение вектора 1776 evalForth(": IS ' LITERAL ['] TOKEN! REGULAR ; : HAS ' LITERAL ['] TOKEN@ REGULAR ;"); 1777 // COMMONADR@ ( n -- Value ) Значение в ячейке n общй таблицы. COMMONADR! ( Value n -- ) Запись значения в ячейку n 1778 evalForth(": COMMONADR! CELL * COMMONADR + ! ; : COMMONADR@ CELL * COMMONADR + @ ;"); 1779 evalForth(": IF=W OSNAME 76 = IF TIB @ DLTIB + <IN ! THEN ; IMMEDIATE"); 1780 evalForth(": IF=L OSNAME 87 = IF TIB @ DLTIB + <IN ! THEN ; IMMEDIATE"); 1781 evalForth(": NOT IF FALSE ELSE TRUE THEN ;"); 1782 // Проверить, что мы в режиме компиляции или интерпретации 1783 evalForth(": ?COMP STATE NOT IF 1 THROW THEN ; : ?EXEC STATE IF 2 THROW THEN ;"); 1784 // ( -- ) Забрать из потока слово немедленного исполнения и закомпилировать его 1785 evalForth(": [COMPILE] ?COMP ' COMPILE, ; IMMEDIATE"); 1786 // Счетный цикл 10 0 DO .. I .. LOOP - 10 раз от 0 до 9 - в любом случае 1 раз выполнение 1787 // Для работы использует стек L 1788 evalForth(": (DO) SWAP >L >L ; : DO COMPILE (DO) <MARK ; IMMEDIATE : I L@ ;"); 1789 evalForth(": (LOOP) L> 1+ L> DDUP < NOT IF DDROP TRUE ELSE >L >L FALSE THEN ;"); 1790 evalForth(": LOOP COMPILE (LOOP) COMPILE ?BRANCH <RESOLVE ; IMMEDIATE"); 1791 evalForth(": (+LOOP) L> + L> DDUP < NOT IF DDROP TRUE ELSE >L >L FALSE THEN ;"); 1792 evalForth(": +LOOP COMPILE (+LOOP) COMPILE ?BRANCH <RESOLVE ; IMMEDIATE"); 1793 1794 // EXECUTEFROMD ( Aколпарамтровcpp Aсловафорта -- Rez ) Выполнить из D слово по EXECUTE 1795 evalForth(": EXECUTEFROMD >R DUP @ BEGIN DUP WHILE DDUP CELL * + @ -ROT 1- REPEAT DDROP R> EXECUTE ;"); 1796 gpcb.executeFromD = gpcb.latest; // Сохраним адрес EXECUTEFROMD 1797 1798 } 1799 // CODE WORD ( Rz -- A/0) Выдать адрес на начало следующей лексемы в формате 1800 // \4ABCD\0\4 Причем эта лексема находится по адресу HERE 1801 private ps h_word(char rz) { 1802 // Указатель на TIB 1803 ps adr = null; 1804 ps uTib = cast(char*)gpcb.Tib; 1805 ps uIn = cast(char*)gpcb.In; 1806 int dlTib = gpcb.dlTib; 1807 ps maxTib = uTib + dlTib - 1; // Это максимальный знак в Tib 1808 // Строка сейчас кладется в специальный бцфер _Tib 1809 // ps _tib = gpcb._Tib + 1; 1810 // Строка кладется по HERE 1811 ps _tib = cast(ps)gpcb.here + 1; 1812 1813 int kps; 1814 // dumpAdr(cast(pp)uIn); 1815 for(;;) { 1816 // writeln(); 1817 //writeln("[", *uIn,"] uIn+1 = ", *(uIn+1), " *uIn = ", cast(ubyte)*uIn); 1818 //writeln(uIn, " ~ ", maxTib); 1819 1820 if(uIn > maxTib+1) { adr = null; goto en; } 1821 if((*uIn == rz) || (uIn > maxTib)) { 1822 if(adr != null) { 1823 *_tib++ = 0; 1824 // *gpcb._Tib = cast(char)kps; // Это если в буфер 1825 *gpcb.here = cast(char)kps; // Это если в HERE 1826 *_tib = cast(char)kps; 1827 gpcb.In = ++uIn; 1828 // adr = gpcb._Tib; // Это если в буфер 1829 adr = cast(ps)gpcb.here; // Это если HERE 1830 goto en; 1831 } 1832 } 1833 else { 1834 if(adr == null) adr = _tib; 1835 *_tib++ = *uIn; 1836 kps++; 1837 } 1838 uIn++; 1839 } 1840 en: 1841 return adr; 1842 } 1843 void f_word() { 1844 asm { naked; 1845 call h_word; 1846 ret; 1847 } 1848 } 1849 // CODE FIND - ( Astr -- Acfa/0 ) Найти в словаре CFA (если не нашли, то 0) 1850 private ps h_find(ps s) { 1851 char* str = s; 1852 // printf("\n Start find [%s] STATE = %d\n", s+1, gpcb.state); 1853 ps _nfa; pp[256]* vect; ubyte b1b; 1854 // Надо проверить, может это число? Если строго в строке одни цифры, то пропускаем и не ищем в словаре 1855 char* ss = s + 1; bool isNoDig = false; 1856 for(; *ss != 0; ss++) { if( !((*ss > 47) && (*ss < 58)) ) { isNoDig = true; break; } } 1857 if(!isNoDig) { goto kn; } 1858 1859 // Тут надо подумать. В этот момент context ulfa показывает на вектор 1860 b1b = *(s + 1); // смещение в векторе context 1861 vect = cast(pp[256]*)gpcb.context; 1862 // *cast(pp)(gpcb.here) = (*vect)[b1b]; // запись LFA, то что лежало в ячейке vect[69] 1863 // было ---> ps _nfa = cast(ps)gpcb.context; 1864 _nfa = cast(ps)(*vect)[b1b]; 1865 for(;;) { 1866 kolPer++; 1867 if(_nfa == null) goto kn; 1868 // printf("{%s}", _nfa+1); 1869 if(cmpString(str, _nfa) == 1) { 1870 // вычислим CFA 1871 // ps cfa = _nfa + (*_nfa + 8); 1872 // надо установвть глобальный признак IMM 1873 gpcb.imm = *(_nfa + (*_nfa + 3)); 1874 // printf("-----> {%s}", _nfa+1); 1875 return _nfa + (*_nfa + 8); 1876 } 1877 else { 1878 _nfa = _nfa + (*_nfa + 4); // Перейти на lfa 1879 _nfa = cast(ps)(*cast(pp)_nfa); 1880 } 1881 } 1882 kn: 1883 return null; 1884 } 1885 private void f_find() { 1886 asm { naked; 1887 call h_find; 1888 ret; 1889 } 1890 } 1891 // CODE IMM ( -- N ) Выдать на стек байт IMM для анализа 1892 private pp h_getIMM() { 1893 return cast(pp)gpcb.imm; 1894 } 1895 // Выдать IMM на стек 1896 private void f_getIMM() { 1897 asm { naked; 1898 call h_DUP; 1899 call h_getIMM; 1900 ret; 1901 } 1902 } 1903 // Первый (простейший) интерпретатор на основе asm 1904 private void f_inter() { 1905 asm { naked; 1906 // int 3; 1907 // mov EAX, 7; // По этой 7 будем контролировать стек ... 7 1908 ms: call f_BL; // Положить на стек 32 0x20; ... 7 32 1909 call f_word; 1910 mov ECX, 0; 1911 cmp EAX, ECX; 1912 je me; // WORD выдало 0 - входной поток исчерпан 1913 call f_find; // 7 Адр_найденного_слова 1914 mov ECX, 0; 1915 cmp EAX, ECX; 1916 je m2; // FIND не нашло слово в словаре 1917 call h_STATE; // 7 Адр_найденного_слова STATE 1918 call h_getFromAdr; 1919 mov ECX, 0; 1920 cmp EAX, ECX; 1921 call h_DROP; 1922 je m1; // Мы в интерпретации и идем на выполнение слова 1923 call f_getIMM; // Мы в компиляции, проверим IMM 1924 mov ECX, 1; 1925 cmp EAX, ECX; 1926 call h_DROP; // сбросим IMM со стека 1927 je m1; // Мы в икомпиляции и идем на компилирование 1928 // int 3; 1929 call h_COMPILEzpt; // Закомпилируем вызов этого слова 1930 jmp ms; // Начинаем всё сначала 1931 m1: call f_EXECUTE; // Выполним слово 1932 jmp ms; // Начинаем всё сначала 1933 m2: call h_DROP; // Сбросим 0 после не найденного Find слова 1934 call h_HERE; // слово не найдено, может это цифра? 1935 call h_NUMBER; // попытка преобразовать в число 1936 // call f_TRUE; 1937 mov ECX, 0; 1938 cmp EAX, ECX; 1939 call h_DROP; // сбросим возврат NUMBER 1940 je ms; // ----> ошибка прочто пропустив в потоке 1941 call h_STATE; // 7 Число STATE 1942 call h_getFromAdr; 1943 mov ECX, 0; 1944 cmp EAX, ECX; 1945 call h_DROP; 1946 je ms; // 7 Число 1947 call h_COMPILE; 1948 call h_s_LIT_s; 1949 call h_zpt; 1950 jmp ms; 1951 me: call h_DROP; 1952 ret; 1953 } 1954 } 1955 // Слово NUMBER. Задача, положить на стек число 32 разр знаковое 1956 private int number(ps str) { 1957 import std.conv; 1958 int rez = 0; 1959 // dumpAdr(cast(pp)str); 1960 try { 1961 rez = to!int(to!string(str+1)); 1962 } 1963 catch { 1964 writeln("Error conv [", to!string(str+1) ,"] --> Integer"); 1965 } 1966 // printf("\nInput str = [%s], Output rez = [%d]\n", str, rez); 1967 return rez; 1968 } 1969 private void h_NUMBER() { 1970 asm { naked; 1971 // call h_DUP; 1972 call number; 1973 call f_TRUE; 1974 ret; 1975 } 1976 } 1977 1978 private void tck(int n) { 1979 writeln(n); 1980 } 1981 private void h_tck() { 1982 asm { naked; 1983 call tck; 1984 call h_DROP; 1985 ret; 1986 } 1987 } 1988 // Часть слова CREATE ( Astr -- ) Создаёт словарную статью, с LFA, но дальше ни чего не делает 1989 // т.к. дальнейшее изготовление кода последует позже 1990 private void h_createST(ps name) { 1991 pb con_tmp = gpcb.here; // Контекст на начало Here 1992 // Нужно обойти имя 1993 gpcb.here = gpcb.here +(*gpcb.here + 3); // Перейти на Imm 1994 *gpcb.here = cast(ubyte)0; // запись Immediate 1995 gpcb.here = gpcb.here + 1; // обходим Imm 1996 1997 // Тут надо подумать. В этот момент context ulfa показывает на вектор 1998 ubyte b1b = *(name + 1); // смещение в векторе context 1999 pp[256]* vect = cast(pp[256]*)gpcb.context; 2000 // printf("[%s] - %d\n", name, b1b); 2001 // writeln("[", cast(string)name ,"] b1b = ", b1b); 2002 *cast(pp)(gpcb.here) = (*vect)[b1b]; // запись LFA, то что лежало в ячейке vect[69] 2003 2004 // *cast(pp)(gpcb.here) = cast(pp)gpcb.context; // запись LFA 2005 // gpcb.context = cast(pp)con_tmp; 2006 (*vect)[b1b] = cast(pp)con_tmp; // фактически управляем Context 2007 2008 gpcb.here = gpcb.here + CELL; // обходим LFA 2009 } 2010 private void h_CREATE() { 2011 asm { naked; 2012 call f_BL; // Положить на стек 32 0x20; ... 7 32 2013 call f_word; 2014 call h_createST; 2015 call h_DROP; 2016 call h_HERE; 2017 call h_LATEST; 2018 call h_setToAdr; 2019 ret; 2020 } 2021 } 2022 // CODE : ( слово читает имя из входного потока и создаёт новое слово ) 2023 private void h_dwoetoc() { 2024 asm { naked; 2025 call h_CREATE; 2026 call h_COMP_ON; 2027 ret; 2028 } 2029 } 2030 // CODE ; ( заканчивает компиляцию слова начатаю : ) 2031 private void h_tckzpt() { 2032 asm { naked; 2033 call h_RETzpt; 2034 call h_COMP_OFF; 2035 ret; 2036 } 2037 } 2038 // Создаёт список в кодофайле начальных "hard" слов 2039 private void CreateVocItem(ps name, pp ucfa, p ulfa, ubyte imm=0) { 2040 // ps name - указатель на строку со счетчиком (имея,типа \4gena) 2041 // p ucfa - указатель на процедуру C++ 2042 // p ulfa - указатель на предыдущее слово ( NFA ) 2043 // unsigned char imm - признак Immediate (+1=немедленная,0=обычная) 2044 2045 import core.stdc..string : memcpy; 2046 // import asc1251; 2047 // Отладочное слово 2048 /* writeln(toCON("Начало кодофайла = "), cast(uint)gpcb.akdf); 2049 writeln(toCON("НERE показывает = "), cast(uint)gpcb.here); 2050 writeln(toCON("ulfa показывает = "), cast(uint)*cast(pp)ulfa); 2051 */ 2052 pb con_tmp = gpcb.here; // Контекст на начало Here 2053 int dlina = *name; // Запомним длину имени созд слова 2054 memcpy(gpcb.here, name, dlina+1); // копируем строку по Here 2055 // uprString(ps(mTakeHERE)); // конвертируем в большие быквы 2056 gpcb.here = gpcb.here + dlina + 1; // сдвигаем Here за имя 2057 *gpcb.here = 0; // Пишем 0 2058 gpcb.here = gpcb.here + 1; // обходим 0 2059 *gpcb.here = cast(ubyte)dlina; // запись длины имени 2060 gpcb.here = gpcb.here + 1; // обходим длину имени 2061 *gpcb.here = cast(ubyte)imm; // запись Immediate 2062 gpcb.here = gpcb.here + 1; // обходим Imm 2063 2064 // Тут надо подумать. В этот момент context ulfa показывает на вектор 2065 ubyte b1b = *(con_tmp + 1); // смещение в векторе context 2066 pp[256]* vect = cast(pp[256]*)gpcb.context; 2067 *cast(pp)(gpcb.here) = (*vect)[b1b]; // запись LFA, то что лежало в ячейке vect[69] 2068 2069 // (*vect)[b1b] = cast(pp)7; 2070 // writeln(toCON("Записываю в (*vect)[b1b] по адресу = "), cast(uint)&((*vect)[b1b]), " b1b = ", b1b); 2071 2072 2073 gpcb.here = gpcb.here + CELL; // обходим LFA 2074 gpcb.latest = cast(pp)(gpcb.here); // запомним LATEST 2075 *gpcb.here = cast(ubyte)0xE9; // компиляция кода JMP 2076 gpcb.here = gpcb.here + 1; // обходим JAMP 2077 *cast(pp)(gpcb.here) = cast(pp)(cast(pb)ucfa 2078 - (gpcb.here + CELL)); // и смещения для JMP 2079 gpcb.here = gpcb.here + CELL; // обходим CFA 2080 // *cast(pp)ulfa = cast(pp)con_tmp; // фактически управляем Context 2081 (*vect)[b1b] = cast(pp)con_tmp; // фактически управляем Context 2082 } 2083 2084 // Выдать 1 - если строки равны 2085 private int cmpString (const char *s1, const char *s2) 2086 { 2087 char *s11 = cast(char*)s1; 2088 char *s22 = cast(char*)s2; 2089 byte d1 = cast(byte)*s11++; 2090 byte d2 = cast(byte)*s22++; 2091 if ( d1 != d2 ) return 0; 2092 for( int i=0; i < d1; i++ ) { 2093 if ( *s11 != *s22 ) return 0; 2094 s11++; s22++; 2095 } 2096 return 1; 2097 } 2098 2099 // INCLUDED ( Astrz -- ) Загрузить файл Форта 2100 private void h_INCLUDED(ps adr) { 2101 string s = to!string(adr); 2102 File f1 = File(s, "r"); foreach(line; f1.byLine()) evalForth(cast(string)line); 2103 } 2104 private void f_INCLUDED() { 2105 asm { naked; 2106 call h_INCLUDED; 2107 call h_DROP; 2108 ret; 2109 } 2110 } 2111 2112 // Загрузить и выполнить файл Forth 2113 void includedForth(string s) { 2114 h_INCLUDED(cast(ps)(s ~ 0).ptr); 2115 } 2116 void includedForth(char* sz) { 2117 h_INCLUDED(sz); 2118 }