![]() ![]() | ![]() |
prims2x now generates CASE before the label
1: \ converts primitives to, e.g., C code 2: 3: \ Copyright (C) 1995,1996,1997,1998,2000 Free Software Foundation, Inc. 4: 5: \ This file is part of Gforth. 6: 7: \ Gforth is free software; you can redistribute it and/or 8: \ modify it under the terms of the GNU General Public License 9: \ as published by the Free Software Foundation; either version 2 10: \ of the License, or (at your option) any later version. 11: 12: \ This program is distributed in the hope that it will be useful, 13: \ but WITHOUT ANY WARRANTY; without even the implied warranty of 14: \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15: \ GNU General Public License for more details. 16: 17: \ You should have received a copy of the GNU General Public License 18: \ along with this program; if not, write to the Free Software 19: \ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. 20: 21: 22: \ This is not very nice (hard limits, no checking, assumes 1 chars = 1). 23: \ And it grew even worse when it aged. 24: 25: \ Optimizations: 26: \ superfluous stores are removed. GCC removes the superfluous loads by itself 27: \ TOS and FTOS can be kept in register( variable)s. 28: \ 29: \ Problems: 30: \ The TOS optimization is somewhat hairy. The problems by example: 31: \ 1) dup ( w -- w w ): w=TOS; sp-=1; sp[1]=w; TOS=w; 32: \ The store is not superfluous although the earlier opt. would think so 33: \ Alternatively: sp[0]=TOS; w=TOS; sp-=1; TOS=w; 34: \ 2) ( -- .. ): sp[0] = TOS; ... /* This additional store is necessary */ 35: \ 3) ( .. -- ): ... TOS = sp[0]; /* as well as this load */ 36: \ 4) ( -- ): /* but here they are unnecessary */ 37: \ 5) Words that call NEXT themselves have to be done very carefully. 38: \ 39: \ To do: 40: \ add the store optimization for doubles 41: \ regarding problem 1 above: It would be better (for over) to implement 42: \ the alternative 43: \ store optimization for combined instructions. 44: 45: \ Design Uglyness: 46: 47: \ - global state (values, variables) in connection with combined instructions. 48: 49: \ - index computation is different for instruction-stream and the 50: \ stacks; there are two mechanisms for dealing with that 51: \ (stack-in-index-xt and a test for stack==instruction-stream); there 52: \ should be only one. 53: 54: warnings off 55: 56: [IFUNDEF] try 57: include startup.fs 58: [THEN] 59: 60: : struct% struct ; \ struct is redefined in gray 61: 62: warnings off 63: 64: include ./gray.fs 65: 66: 32 constant max-effect \ number of things on one side of a stack effect 67: 4 constant max-stacks \ the max. number of stacks (including inst-stream). 68: 255 constant maxchar 69: maxchar 1+ constant eof-char 70: #tab constant tab-char 71: #lf constant nl-char 72: 73: variable rawinput \ pointer to next character to be scanned 74: variable endrawinput \ pointer to the end of the input (the char after the last) 75: variable cookedinput \ pointer to the next char to be parsed 76: variable line \ line number of char pointed to by input 77: variable line-start \ pointer to start of current line (for error messages) 78: 0 line ! 79: 2variable filename \ filename of original input file 80: 0 0 filename 2! 81: 2variable f-comment 82: 0 0 f-comment 2! 83: variable skipsynclines \ are sync lines ("#line ...") invisible to the parser? 84: skipsynclines on 85: 86: : th ( addr1 n -- addr2 ) 87: cells + ; 88: 89: : holds ( addr u -- ) 90: \ like HOLD, but for a string 91: tuck + swap 0 +do 92: 1- dup c@ hold 93: loop 94: drop ; 95: 96: : insert-wordlist { c-addr u wordlist xt -- } 97: \ adds name "addr u" to wordlist using defining word xt 98: \ xt may cause additional stack effects 99: get-current >r wordlist set-current 100: c-addr u nextname xt execute 101: r> set-current ; 102: 103: : start ( -- addr ) 104: cookedinput @ ; 105: 106: : end ( addr -- addr u ) 107: cookedinput @ over - ; 108: 109: : print-error-line ( -- ) 110: \ print the current line and position 111: line-start @ endrawinput @ over - 2dup nl-char scan drop nip ( start end ) 112: over - type cr 113: line-start @ rawinput @ over - typewhite ." ^" cr ; 114: 115: : ?print-error { f addr u -- } 116: f ?not? if 117: outfile-id >r try 118: stderr to outfile-id 119: filename 2@ type ." :" line @ 0 .r ." : " addr u type cr 120: print-error-line 121: 0 122: recover endtry 123: r> to outfile-id throw 124: abort 125: endif ; 126: 127: : quote ( -- ) 128: [char] " emit ; 129: 130: variable output \ xt ( -- ) of output word for simple primitives 131: variable output-combined \ xt ( -- ) of output word for combined primitives 132: 133: struct% 134: cell% field stack-number \ the number of this stack 135: cell% 2* field stack-pointer \ stackpointer name 136: cell% field stack-type \ name for default type of stack items 137: cell% field stack-in-index-xt \ ( in-size item -- in-index ) 138: end-struct stack% 139: 140: struct% 141: cell% 2* field item-name \ name, excluding stack prefixes 142: cell% field item-stack \ descriptor for the stack used, 0 is default 143: cell% field item-type \ descriptor for the item type 144: cell% field item-offset \ offset in stack items, 0 for the deepest element 145: cell% field item-first \ true if this is the first occurence of the item 146: end-struct item% 147: 148: struct% 149: cell% 2* field type-c-name 150: cell% field type-stack \ default stack 151: cell% field type-size \ size of type in stack items 152: cell% field type-fetch \ xt of fetch code generator ( item -- ) 153: cell% field type-store \ xt of store code generator ( item -- ) 154: end-struct type% 155: 156: variable next-stack-number 0 next-stack-number ! 157: create stacks max-stacks cells allot \ array of stacks 158: 159: : stack-in-index ( in-size item -- in-index ) 160: item-offset @ - 1- ; 161: 162: : inst-in-index ( in-size item -- in-index ) 163: nip dup item-offset @ swap item-type @ type-size @ + 1- ; 164: 165: : make-stack ( addr-ptr u1 type "stack-name" -- ) 166: next-stack-number @ max-stacks < s" too many stacks" ?print-error 167: create stack% %allot >r 168: r@ stacks next-stack-number @ th ! 169: next-stack-number @ r@ stack-number ! 170: 1 next-stack-number +! 171: r@ stack-type ! 172: save-mem r@ stack-pointer 2! 173: ['] stack-in-index r> stack-in-index-xt ! ; 174: 175: : map-stacks { xt -- } 176: \ perform xt for all stacks except inst-stream 177: next-stack-number @ 1 +do 178: stacks i th @ xt execute 179: loop ; 180: 181: \ stack items 182: 183: : init-item ( addr u addr1 -- ) 184: \ initialize item at addr1 with name addr u 185: \ !! remove stack prefix 186: dup item% %size erase 187: item-name 2! ; 188: 189: : map-items { addr end xt -- } 190: \ perform xt for all items in array addr...end 191: end addr ?do 192: i xt execute 193: item% %size +loop ; 194: 195: \ types 196: 197: : print-type-prefix ( type -- ) 198: body> >head name>string type ; 199: 200: \ various variables for storing stuff of one primitive 201: 202: struct% 203: cell% 2* field prim-name 204: cell% 2* field prim-wordset 205: cell% 2* field prim-c-name 206: cell% 2* field prim-doc 207: cell% 2* field prim-c-code 208: cell% 2* field prim-forth-code 209: cell% 2* field prim-stack-string 210: cell% field prim-num \ ordinal number 211: cell% field prim-items-wordlist \ unique items 212: item% max-effect * field prim-effect-in 213: item% max-effect * field prim-effect-out 214: cell% field prim-effect-in-end 215: cell% field prim-effect-out-end 216: cell% max-stacks * field prim-stacks-in \ number of in items per stack 217: cell% max-stacks * field prim-stacks-out \ number of out items per stack 218: end-struct prim% 219: 220: : make-prim ( -- prim ) 221: prim% %alloc { p } 222: s" " p prim-doc 2! s" " p prim-forth-code 2! s" " p prim-wordset 2! 223: p ; 224: 225: 0 value prim \ in combined prims either combined or a part 226: 0 value combined \ in combined prims the combined prim 227: variable in-part \ true if processing a part 228: in-part off 229: 230: 1000 constant max-combined 231: create combined-prims max-combined cells allot 232: variable num-combined 233: 234: table constant combinations 235: \ the keys are the sequences of pointers to primitives 236: 237: create current-depth max-stacks cells allot 238: create max-depth max-stacks cells allot 239: create min-depth max-stacks cells allot 240: 241: wordlist constant primitives 242: 243: : create-prim ( prim -- ) 244: dup prim-name 2@ primitives ['] constant insert-wordlist ; 245: 246: : stack-in ( stack -- addr ) 247: \ address of number of stack items in effect in 248: stack-number @ cells prim prim-stacks-in + ; 249: 250: : stack-out ( stack -- addr ) 251: \ address of number of stack items in effect out 252: stack-number @ cells prim prim-stacks-out + ; 253: 254: \ global vars 255: variable c-line 256: 2variable c-filename 257: variable name-line 258: 2variable name-filename 259: 2variable last-name-filename 260: Variable function-number 0 function-number ! 261: 262: \ a few more set ops 263: 264: : bit-equivalent ( w1 w2 -- w3 ) 265: xor invert ; 266: 267: : complement ( set1 -- set2 ) 268: empty ['] bit-equivalent binary-set-operation ; 269: 270: \ stack access stuff 271: 272: : normal-stack-access ( n stack -- ) 273: stack-pointer 2@ type 274: dup 275: if 276: ." [" 0 .r ." ]" 277: else 278: drop ." TOS" 279: endif ; 280: 281: \ forward declaration for inst-stream (breaks cycle in definitions) 282: defer inst-stream-f ( -- stack ) 283: 284: : part-stack-access { n stack -- } 285: \ print _<stack><x>, x=inst-stream? n : maxdepth-currentdepth-n-1 286: ." _" stack stack-pointer 2@ type 287: stack stack-number @ { stack# } 288: current-depth stack# th @ n + { access-depth } 289: stack inst-stream-f = if 290: access-depth 291: else 292: combined prim-stacks-in stack# th @ 293: assert( dup max-depth stack# th @ = ) 294: access-depth - 1- 295: endif 296: 0 .r ; 297: 298: : stack-access ( n stack -- ) 299: \ print a stack access at index n of stack 300: in-part @ if 301: part-stack-access 302: else 303: normal-stack-access 304: endif ; 305: 306: : item-in-index { item -- n } 307: \ n is the index of item (in the in-effect) 308: item item-stack @ dup >r stack-in @ ( in-size r:stack ) 309: item r> stack-in-index-xt @ execute ; 310: 311: : item-stack-type-name ( item -- addr u ) 312: item-stack @ stack-type @ type-c-name 2@ ; 313: 314: : fetch-single ( item -- ) 315: \ fetch a single stack item from its stack 316: >r 317: r@ item-name 2@ type 318: ." = vm_" r@ item-stack-type-name type 319: ." 2" r@ item-type @ print-type-prefix ." (" 320: r@ item-in-index r@ item-stack @ stack-access 321: ." );" cr 322: rdrop ; 323: 324: : fetch-double ( item -- ) 325: \ fetch a double stack item from its stack 326: >r 327: ." vm_two" 328: r@ item-stack-type-name type ." 2" 329: r@ item-type @ print-type-prefix ." (" 330: r@ item-name 2@ type ." , " 331: r@ item-in-index r@ item-stack @ 2dup ." (Cell)" stack-access 332: ." , " -1 under+ ." (Cell)" stack-access 333: ." );" cr 334: rdrop ; 335: 336: : same-as-in? ( item -- f ) 337: \ f is true iff the offset and stack of item is the same as on input 338: >r 339: r@ item-first @ if 340: rdrop false exit 341: endif 342: r@ item-name 2@ prim prim-items-wordlist @ search-wordlist 0= abort" bug" 343: execute @ 344: dup r@ = 345: if \ item first appeared in output 346: drop false 347: else 348: dup item-stack @ r@ item-stack @ = 349: swap item-offset @ r@ item-offset @ = and 350: endif 351: rdrop ; 352: 353: : item-out-index ( item -- n ) 354: \ n is the index of item (in the in-effect) 355: >r r@ item-stack @ stack-out @ r> item-offset @ - 1- ; 356: 357: : really-store-single ( item -- ) 358: >r 359: r@ item-out-index r@ item-stack @ stack-access ." = vm_" 360: r@ item-type @ print-type-prefix ." 2" 361: r@ item-stack-type-name type ." (" 362: r@ item-name 2@ type ." );" 363: rdrop ; 364: 365: : store-single ( item -- ) 366: >r 367: r@ same-as-in? 368: if 369: r@ item-in-index 0= r@ item-out-index 0= xor 370: if 371: ." IF_" r@ item-stack @ stack-pointer 2@ type 372: ." TOS(" r@ really-store-single ." );" cr 373: endif 374: else 375: r@ really-store-single cr 376: endif 377: rdrop ; 378: 379: : store-double ( item -- ) 380: \ !! store optimization is not performed, because it is not yet needed 381: >r 382: ." vm_" 383: r@ item-type @ print-type-prefix ." 2two" 384: r@ item-stack-type-name type ." (" 385: r@ item-name 2@ type ." , " 386: r@ item-out-index r@ item-stack @ 2dup stack-access 387: ." , " -1 under+ stack-access 388: ." );" cr 389: rdrop ; 390: 391: : single ( -- xt1 xt2 n ) 392: ['] fetch-single ['] store-single 1 ; 393: 394: : double ( -- xt1 xt2 n ) 395: ['] fetch-double ['] store-double 2 ; 396: 397: : s, ( addr u -- ) 398: \ allocate a string 399: here swap dup allot move ; 400: 401: wordlist constant prefixes 402: 403: : declare ( addr "name" -- ) 404: \ remember that there is a stack item at addr called name 405: create , ; 406: 407: : !default ( w addr -- ) 408: dup @ if 409: 2drop \ leave nonzero alone 410: else 411: ! 412: endif ; 413: 414: : create-type { addr u xt1 xt2 n stack -- } ( "prefix" -- ) 415: \ describes a type 416: \ addr u specifies the C type name 417: \ stack effect entries of the type start with prefix 418: create type% %allot >r 419: addr u save-mem r@ type-c-name 2! 420: xt1 r@ type-fetch ! 421: xt2 r@ type-store ! 422: n r@ type-size ! 423: stack r@ type-stack ! 424: rdrop ; 425: 426: : type-prefix ( xt1 xt2 n stack "prefix" -- ) 427: get-current >r prefixes set-current 428: create-type r> set-current 429: does> ( item -- ) 430: \ initialize item 431: { item typ } 432: typ item item-type ! 433: typ type-stack @ item item-stack !default 434: item item-name 2@ prim prim-items-wordlist @ search-wordlist 0= if 435: item item-name 2@ nextname item declare 436: item item-first on 437: \ typ type-c-name 2@ type space type ." ;" cr 438: else 439: drop 440: item item-first off 441: endif ; 442: 443: : execute-prefix ( item addr1 u1 -- ) 444: \ execute the word ( item -- ) associated with the longest prefix 445: \ of addr1 u1 446: 0 swap ?do 447: dup i prefixes search-wordlist 448: if \ ok, we have the type ( item addr1 xt ) 449: nip execute 450: UNLOOP EXIT 451: endif 452: -1 s+loop 453: \ we did not find a type, abort 454: false s" unknown prefix" ?print-error ; 455: 456: : declaration ( item -- ) 457: dup item-name 2@ execute-prefix ; 458: 459: : declaration-list ( addr1 addr2 -- ) 460: ['] declaration map-items ; 461: 462: : declarations ( -- ) 463: wordlist dup prim prim-items-wordlist ! set-current 464: prim prim-effect-in prim prim-effect-in-end @ declaration-list 465: prim prim-effect-out prim prim-effect-out-end @ declaration-list ; 466: 467: : print-declaration { item -- } 468: item item-first @ if 469: item item-type @ type-c-name 2@ type space 470: item item-name 2@ type ." ;" cr 471: endif ; 472: 473: : print-declarations ( -- ) 474: prim prim-effect-in prim prim-effect-in-end @ ['] print-declaration map-items 475: prim prim-effect-out prim prim-effect-out-end @ ['] print-declaration map-items ; 476: 477: : stack-prefix ( stack "prefix" -- ) 478: get-current >r prefixes set-current 479: name tuck nextname create ( stack length ) 2, 480: r> set-current 481: does> ( item -- ) 482: 2@ { item stack prefix-length } 483: item item-name 2@ prefix-length /string item item-name 2! 484: stack item item-stack ! 485: item declaration ; 486: 487: \ types pointed to by stacks for use in combined prims 488: \ !! output-c-combined shouldn't use these names! 489: : stack-type-name ( addr u "name" -- ) 490: single 0 create-type ; 491: 492: wordlist constant type-names \ this is here just to meet the requirement 493: \ that a type be a word; it is never used for lookup 494: 495: : stack ( "name" "stack-pointer" "type" -- ) 496: \ define stack 497: name { d: stack-name } 498: name { d: stack-pointer } 499: name { d: stack-type } 500: get-current type-names set-current 501: stack-type 2dup nextname stack-type-name 502: set-current 503: stack-pointer lastxt >body stack-name nextname make-stack ; 504: 505: stack inst-stream IP Cell 506: ' inst-in-index inst-stream stack-in-index-xt ! 507: ' inst-stream <is> inst-stream-f 508: \ !! initialize stack-in and stack-out 509: 510: \ offset computation 511: \ the leftmost (i.e. deepest) item has offset 0 512: \ the rightmost item has the highest offset 513: 514: : compute-offset { item xt -- } 515: \ xt specifies in/out; update stack-in/out and set item-offset 516: item item-type @ type-size @ 517: item item-stack @ xt execute dup @ >r +! 518: r> item item-offset ! ; 519: 520: : compute-offset-in ( addr1 addr2 -- ) 521: ['] stack-in compute-offset ; 522: 523: : compute-offset-out ( addr1 addr2 -- ) 524: ['] stack-out compute-offset ; 525: 526: : clear-stack { -- } 527: dup stack-in off stack-out off ; 528: 529: : compute-offsets ( -- ) 530: ['] clear-stack map-stacks 531: inst-stream clear-stack 532: prim prim-effect-in prim prim-effect-in-end @ ['] compute-offset-in map-items 533: prim prim-effect-out prim prim-effect-out-end @ ['] compute-offset-out map-items 534: inst-stream stack-out @ 0= s" # can only be on the input side" ?print-error ; 535: 536: : process-simple ( -- ) 537: prim prim { W^ key } key cell 538: combinations ['] constant insert-wordlist 539: declarations compute-offsets 540: output @ execute ; 541: 542: : flush-a-tos { stack -- } 543: stack stack-out @ 0<> stack stack-in @ 0= and 544: if 545: ." IF_" stack stack-pointer 2@ 2dup type ." TOS(" 546: 2dup type ." [0] = " type ." TOS);" cr 547: endif ; 548: 549: : flush-tos ( -- ) 550: ['] flush-a-tos map-stacks ; 551: 552: : fill-a-tos { stack -- } 553: stack stack-out @ 0= stack stack-in @ 0<> and 554: if 555: ." IF_" stack stack-pointer 2@ 2dup type ." TOS(" 556: 2dup type ." TOS = " type ." [0]);" cr 557: endif ; 558: 559: : fill-tos ( -- ) 560: \ !! inst-stream for prefetching? 561: ['] fill-a-tos map-stacks ; 562: 563: : fetch ( addr -- ) 564: dup item-type @ type-fetch @ execute ; 565: 566: : fetches ( -- ) 567: prim prim-effect-in prim prim-effect-in-end @ ['] fetch map-items ; 568: 569: : stack-pointer-update { stack -- } 570: \ stack grow downwards 571: stack stack-in @ stack stack-out @ - 572: ?dup-if \ this check is not necessary, gcc would do this for us 573: stack stack-pointer 2@ type ." += " 0 .r ." ;" cr 574: endif ; 575: 576: : inst-pointer-update ( -- ) 577: inst-stream stack-in @ ?dup-if 578: ." INC_IP(" 0 .r ." );" cr 579: endif ; 580: 581: : stack-pointer-updates ( -- ) 582: inst-pointer-update 583: ['] stack-pointer-update map-stacks ; 584: 585: : store ( item -- ) 586: \ f is true if the item should be stored 587: \ f is false if the store is probably not necessary 588: dup item-type @ type-store @ execute ; 589: 590: : stores ( -- ) 591: prim prim-effect-out prim prim-effect-out-end @ ['] store map-items ; 592: 593: : print-debug-arg { item -- } 594: ." fputs(" quote space item item-name 2@ type ." =" quote ." , vm_out); " 595: ." printarg_" item item-type @ print-type-prefix 596: ." (" item item-name 2@ type ." );" cr ; 597: 598: : print-debug-args ( -- ) 599: ." #ifdef VM_DEBUG" cr 600: ." if (vm_debug) {" cr 601: prim prim-effect-in prim prim-effect-in-end @ ['] print-debug-arg map-items 602: \ ." fputc('\n', vm_out);" cr 603: ." }" cr 604: ." #endif" cr ; 605: 606: : print-debug-result { item -- } 607: item item-first @ if 608: item print-debug-arg 609: endif ; 610: 611: : print-debug-results ( -- ) 612: cr 613: ." #ifdef VM_DEBUG" cr 614: ." if (vm_debug) {" cr 615: ." fputs(" quote ." -- " quote ." , vm_out); " 616: prim prim-effect-out prim prim-effect-out-end @ ['] print-debug-result map-items 617: ." fputc('\n', vm_out);" cr 618: ." }" cr 619: ." #endif" cr ; 620: 621: : output-super-end ( -- ) 622: prim prim-c-code 2@ s" SET_IP" search if 623: ." SUPER_END;" cr 624: endif 625: 2drop ; 626: 627: : output-c-tail ( -- ) 628: \ the final part of the generated C code 629: output-super-end 630: print-debug-results 631: ." NEXT_P1;" cr 632: stores 633: fill-tos 634: ." NEXT_P2;" ; 635: 636: : type-c-code ( c-addr u xt -- ) 637: \ like TYPE, but replaces "TAIL;" with tail code produced by xt 638: { xt } 639: begin ( c-addr1 u1 ) 640: 2dup s" TAIL;" search 641: while ( c-addr1 u1 c-addr3 u3 ) 642: 2dup 2>r drop nip over - type 643: xt execute 644: 2r> 5 /string 645: \ !! resync #line missing 646: repeat 647: 2drop type ; 648: 649: : print-entry ( -- ) 650: ." CASE I_" prim prim-c-name 2@ type ." :" ; 651: 652: : output-c ( -- ) 653: print-entry ." /* " prim prim-name 2@ type ." ( " prim prim-stack-string 2@ type ." ) */" cr 654: ." /* " prim prim-doc 2@ type ." */" cr 655: ." NAME(" quote prim prim-name 2@ type quote ." )" cr \ debugging 656: ." {" cr 657: ." DEF_CA" cr 658: print-declarations 659: ." NEXT_P0;" cr 660: flush-tos 661: fetches 662: print-debug-args 663: stack-pointer-updates 664: ." {" cr 665: ." #line " c-line @ . quote c-filename 2@ type quote cr 666: prim prim-c-code 2@ ['] output-c-tail type-c-code 667: ." }" cr 668: output-c-tail 669: ." }" cr 670: cr 671: ; 672: 673: : disasm-arg { item -- } 674: item item-stack @ inst-stream = if 675: ." fputc(' ', vm_out); " 676: ." printarg_" item item-type @ print-type-prefix 677: ." ((" item item-type @ type-c-name 2@ type ." )" 678: ." ip[" item item-offset @ 1+ 0 .r ." ]);" cr 679: endif ; 680: 681: : disasm-args ( -- ) 682: prim prim-effect-in prim prim-effect-in-end @ ['] disasm-arg map-items ; 683: 684: : output-disasm ( -- ) 685: \ generate code for disassembling VM instructions 686: ." if (ip[0] == prim[" function-number @ 0 .r ." ]) {" cr 687: ." fputs(" quote prim prim-name 2@ type quote ." , vm_out);" cr 688: disasm-args 689: ." ip += " inst-stream stack-in @ 1+ 0 .r ." ;" cr 690: ." goto _endif_;" cr 691: ." }" cr ; 692: 693: : output-profile ( -- ) 694: \ generate code for postprocessing the VM block profile stuff 695: ." if (VM_IS_INST(*ip, " function-number @ 0 .r ." )) {" cr 696: ." add_inst(b, " quote prim prim-name 2@ type quote ." );" cr 697: ." ip += " inst-stream stack-in @ 1+ 0 .r ." ;" cr 698: prim prim-c-code 2@ s" SET_IP" search nip nip 699: prim prim-c-code 2@ s" SUPER_END" search nip nip or if 700: ." return;" cr 701: else 702: ." goto _endif_;" cr 703: endif 704: ." }" cr ; 705: 706: : gen-arg-parm { item -- } 707: item item-stack @ inst-stream = if 708: ." , " item item-type @ type-c-name 2@ type space 709: item item-name 2@ type 710: endif ; 711: 712: : gen-args-parm ( -- ) 713: prim prim-effect-in prim prim-effect-in-end @ ['] gen-arg-parm map-items ; 714: 715: : gen-arg-gen { item -- } 716: item item-stack @ inst-stream = if 717: ." genarg_" item item-type @ print-type-prefix 718: ." (ctp, " item item-name 2@ type ." );" cr 719: endif ; 720: 721: : gen-args-gen ( -- ) 722: prim prim-effect-in prim prim-effect-in-end @ ['] gen-arg-gen map-items ; 723: 724: : output-gen ( -- ) 725: \ generate C code for generating VM instructions 726: ." void gen_" prim prim-c-name 2@ type ." (Inst **ctp" gen-args-parm ." )" cr 727: ." {" cr 728: ." gen_inst(ctp, vm_prim[" function-number @ 0 .r ." ]);" cr 729: gen-args-gen 730: ." }" cr ; 731: 732: : stack-used? { stack -- f } 733: stack stack-in @ stack stack-out @ or 0<> ; 734: 735: : output-funclabel ( -- ) 736: ." &I_" prim prim-c-name 2@ type ." ," cr ; 737: 738: : output-forthname ( -- ) 739: '" emit prim prim-name 2@ type '" emit ." ," cr ; 740: 741: \ : output-c-func ( -- ) 742: \ \ used for word libraries 743: \ ." Cell * I_" prim prim-c-name 2@ type ." (Cell *SP, Cell **FP) /* " prim prim-name 2@ type 744: \ ." ( " prim prim-stack-string 2@ type ." ) */" cr 745: \ ." /* " prim prim-doc 2@ type ." */" cr 746: \ ." NAME(" quote prim prim-name 2@ type quote ." )" cr 747: \ \ debugging 748: \ ." {" cr 749: \ print-declarations 750: \ \ !! don't know what to do about that 751: \ inst-stream stack-used? IF ." Cell *ip=IP;" cr THEN 752: \ data-stack stack-used? IF ." Cell *sp=SP;" cr THEN 753: \ fp-stack stack-used? IF ." Cell *fp=*FP;" cr THEN 754: \ return-stack stack-used? IF ." Cell *rp=*RP;" cr THEN 755: \ flush-tos 756: \ fetches 757: \ stack-pointer-updates 758: \ fp-stack stack-used? IF ." *FP=fp;" cr THEN 759: \ ." {" cr 760: \ ." #line " c-line @ . quote c-filename 2@ type quote cr 761: \ prim prim-c-code 2@ type 762: \ ." }" cr 763: \ stores 764: \ fill-tos 765: \ ." return (sp);" cr 766: \ ." }" cr 767: \ cr ; 768: 769: : output-label ( -- ) 770: ." (Label)&&I_" prim prim-c-name 2@ type ." ," cr ; 771: 772: : output-alias ( -- ) 773: ( primitive-number @ . ." alias " ) ." Primitive " prim prim-name 2@ type cr ; 774: 775: : output-forth ( -- ) 776: prim prim-forth-code @ 0= 777: IF \ output-alias 778: \ this is bad for ec: an alias is compiled if tho word does not exist! 779: \ JAW 780: ELSE ." : " prim prim-name 2@ type ." ( " 781: prim prim-stack-string 2@ type ." )" cr 782: prim prim-forth-code 2@ type cr 783: THEN ; 784: 785: : output-tag-file ( -- ) 786: name-filename 2@ last-name-filename 2@ compare if 787: name-filename 2@ last-name-filename 2! 788: #ff emit cr 789: name-filename 2@ type 790: ." ,0" cr 791: endif ; 792: 793: : output-tag ( -- ) 794: output-tag-file 795: prim prim-name 2@ 1+ type 796: 127 emit 797: space prim prim-name 2@ type space 798: 1 emit 799: name-line @ 0 .r 800: ." ,0" cr ; 801: 802: [IFDEF] documentation 803: : register-doc ( -- ) 804: prim prim-name 2@ documentation ['] create insert-wordlist 805: prim prim-name 2@ 2, 806: prim prim-stack-string 2@ condition-stack-effect 2, 807: prim prim-wordset 2@ 2, 808: prim prim-c-name 2@ condition-pronounciation 2, 809: prim prim-doc 2@ 2, ; 810: [THEN] 811: 812: 813: \ combining instructions 814: 815: \ The input should look like this: 816: 817: \ lit_+ = lit + 818: 819: \ The output should look like this: 820: 821: \ I_lit_+: 822: \ { 823: \ DEF_CA 824: \ Cell _x_ip0; 825: \ Cell _x_sp0; 826: \ Cell _x_sp1; 827: \ NEXT_P0; 828: \ _x_ip0 = (Cell) IPTOS; 829: \ _x_sp0 = (Cell) spTOS; 830: \ INC_IP(1); 831: \ /* sp += 0; */ 832: \ /* lit ( #w -- w ) */ 833: \ /* */ 834: \ NAME("lit") 835: \ { 836: \ Cell w; 837: \ w = (Cell) _x_ip0; 838: \ #ifdef VM_DEBUG 839: \ if (vm_debug) { 840: \ fputs(" w=", vm_out); printarg_w (w); 841: \ fputc('\n', vm_out); 842: \ } 843: \ #endif 844: \ { 845: \ #line 136 "./prim" 846: \ } 847: \ _x_sp1 = (Cell)w; 848: \ } 849: \ I_plus: /* + ( n1 n2 -- n ) */ 850: \ /* */ 851: \ NAME("+") 852: \ { 853: \ DEF_CA 854: \ Cell n1; 855: \ Cell n2; 856: \ Cell n; 857: \ NEXT_P0; 858: \ n1 = (Cell) _x_sp0; 859: \ n2 = (Cell) _x_sp1; 860: \ #ifdef VM_DEBUG 861: \ if (vm_debug) { 862: \ fputs(" n1=", vm_out); printarg_n (n1); 863: \ fputs(" n2=", vm_out); printarg_n (n2); 864: \ fputc('\n', vm_out); 865: \ } 866: \ #endif 867: \ { 868: \ #line 516 "./prim" 869: \ n = n1+n2; 870: \ } 871: \ NEXT_P1; 872: \ _x_sp0 = (Cell)n; 873: \ NEXT_P2; 874: \ } 875: \ NEXT_P1; 876: \ spTOS = (Cell)_x_sp0; 877: \ NEXT_P2; 878: 879: : init-combined ( -- ) 880: prim to combined 881: 0 num-combined ! 882: current-depth max-stacks cells erase 883: max-depth max-stacks cells erase 884: min-depth max-stacks cells erase 885: prim prim-effect-in prim prim-effect-in-end ! 886: prim prim-effect-out prim prim-effect-out-end ! ; 887: 888: : max! ( n addr -- ) 889: tuck @ max swap ! ; 890: 891: : min! ( n addr -- ) 892: tuck @ min swap ! ; 893: 894: : add-depths { p -- } 895: \ combine stack effect of p with *-depths 896: max-stacks 0 ?do 897: current-depth i th @ 898: p prim-stacks-in i th @ + 899: dup max-depth i th max! 900: p prim-stacks-out i th @ - 901: dup min-depth i th min! 902: current-depth i th ! 903: loop ; 904: 905: : add-prim ( addr u -- ) 906: \ add primitive given by "addr u" to combined-prims 907: primitives search-wordlist s" unknown primitive" ?print-error 908: execute { p } 909: p combined-prims num-combined @ th ! 910: 1 num-combined +! 911: p add-depths ; 912: 913: : compute-effects { q -- } 914: \ compute the stack effects of q from the depths 915: max-stacks 0 ?do 916: max-depth i th @ dup 917: q prim-stacks-in i th ! 918: current-depth i th @ - 919: q prim-stacks-out i th ! 920: loop ; 921: 922: : make-effect-items { stack# items effect-endp -- } 923: \ effect-endp points to a pointer to the end of the current item-array 924: \ and has to be updated 925: stacks stack# th @ { stack } 926: items 0 +do 927: effect-endp @ { item } 928: i 0 <# #s stack stack-pointer 2@ holds [char] _ hold #> save-mem 929: item item-name 2! 930: stack item item-stack ! 931: stack stack-type @ item item-type ! 932: i item item-offset ! 933: item item-first on 934: item% %size effect-endp +! 935: loop ; 936: 937: : init-effects { q -- } 938: \ initialize effects field for FETCHES and STORES 939: max-stacks 0 ?do 940: i q prim-stacks-in i th @ q prim-effect-in-end make-effect-items 941: i q prim-stacks-out i th @ q prim-effect-out-end make-effect-items 942: loop ; 943: 944: : process-combined ( -- ) 945: combined combined-prims num-combined @ cells 946: combinations ['] constant insert-wordlist 947: combined-prims num-combined @ 1- th ( last-part ) 948: @ prim-c-code 2@ prim prim-c-code 2! \ used by output-super-end 949: prim compute-effects 950: prim init-effects 951: output-combined perform ; 952: 953: \ C output 954: 955: : print-item { n stack -- } 956: \ print nth stack item name 957: stack stack-type @ type-c-name 2@ type space 958: ." _" stack stack-pointer 2@ type n 0 .r ; 959: 960: : print-declarations-combined ( -- ) 961: max-stacks 0 ?do 962: max-depth i th @ min-depth i th @ - 0 +do 963: i stacks j th @ print-item ." ;" cr 964: loop 965: loop ; 966: 967: : part-fetches ( -- ) 968: fetches ; 969: 970: : part-output-c-tail ( -- ) 971: print-debug-results 972: stores ; 973: 974: : output-combined-tail ( -- ) 975: part-output-c-tail 976: prim >r combined to prim 977: in-part @ >r in-part off 978: output-c-tail 979: r> in-part ! r> to prim ; 980: 981: : output-part ( p -- ) 982: to prim 983: ." /* " prim prim-name 2@ type ." ( " prim prim-stack-string 2@ type ." ) */" cr 984: ." NAME(" quote prim prim-name 2@ type quote ." )" cr \ debugging 985: ." {" cr 986: print-declarations 987: part-fetches 988: print-debug-args 989: prim add-depths \ !! right place? 990: ." {" cr 991: ." #line " c-line @ . quote c-filename 2@ type quote cr 992: prim prim-c-code 2@ ['] output-combined-tail type-c-code 993: ." }" cr 994: part-output-c-tail 995: ." }" cr ; 996: 997: : output-parts ( -- ) 998: prim >r in-part on 999: current-depth max-stacks cells erase 1000: num-combined @ 0 +do 1001: combined-prims i th @ output-part 1002: loop 1003: in-part off 1004: r> to prim ; 1005: 1006: : output-c-combined ( -- ) 1007: print-entry cr 1008: \ debugging messages just in parts 1009: ." {" cr 1010: ." DEF_CA" cr 1011: print-declarations-combined 1012: ." NEXT_P0;" cr 1013: flush-tos 1014: fetches 1015: \ print-debug-args 1016: stack-pointer-updates 1017: output-parts 1018: output-c-tail 1019: ." }" cr 1020: cr ; 1021: 1022: : output-forth-combined ( -- ) 1023: ; 1024: 1025: 1026: \ peephole optimization rules 1027: 1028: \ in order for this to work as intended, shorter combinations for each 1029: \ length must be present, and the longer combinations must follow 1030: \ shorter ones (this restriction may go away in the future). 1031: 1032: : output-peephole ( -- ) 1033: combined-prims num-combined @ 1- cells combinations search-wordlist 1034: s" the prefix for this combination must be defined earlier" ?print-error 1035: ." {" 1036: execute prim-num @ 5 .r ." ," 1037: combined-prims num-combined @ 1- th @ prim-num @ 5 .r ." ," 1038: combined prim-num @ 5 .r ." }, /* " 1039: combined prim-c-name 2@ type ." */" 1040: cr ; 1041: 1042: : output-forth-peephole ( -- ) 1043: combined-prims num-combined @ 1- cells combinations search-wordlist 1044: s" the prefix for this combination must be defined earlier" ?print-error 1045: execute prim-num @ 5 .r 1046: combined-prims num-combined @ 1- th @ prim-num @ 5 .r 1047: combined prim-num @ 5 .r ." prim, \ " 1048: combined prim-c-name 2@ type 1049: cr ; 1050: 1051: 1052: \ the parser 1053: 1054: eof-char max-member \ the whole character set + EOF 1055: 1056: : getinput ( -- n ) 1057: rawinput @ endrawinput @ = 1058: if 1059: eof-char 1060: else 1061: cookedinput @ c@ 1062: endif ; 1063: 1064: :noname ( n -- ) 1065: dup bl > if 1066: emit space 1067: else 1068: . 1069: endif ; 1070: print-token ! 1071: 1072: : testchar? ( set -- f ) 1073: getinput member? ; 1074: ' testchar? test-vector ! 1075: 1076: : checksyncline ( -- ) 1077: \ when input points to a newline, check if the next line is a 1078: \ sync line. If it is, perform the appropriate actions. 1079: rawinput @ >r 1080: s" #line " r@ over compare 0<> if 1081: rdrop 1 line +! EXIT 1082: endif 1083: 0. r> 6 chars + 20 >number drop >r drop line ! r> ( c-addr ) 1084: dup c@ bl = if 1085: char+ dup c@ [char] " <> 0= s" sync line syntax" ?print-error 1086: char+ dup 100 [char] " scan drop swap 2dup - save-mem filename 2! 1087: char+ 1088: endif 1089: dup c@ nl-char <> 0= s" sync line syntax" ?print-error 1090: skipsynclines @ if 1091: dup char+ rawinput ! 1092: rawinput @ c@ cookedinput @ c! 1093: endif 1094: drop ; 1095: 1096: : ?nextchar ( f -- ) 1097: s" syntax error, wrong char" ?print-error 1098: rawinput @ endrawinput @ <> if 1099: rawinput @ c@ 1100: 1 chars rawinput +! 1101: 1 chars cookedinput +! 1102: nl-char = if 1103: checksyncline 1104: rawinput @ line-start ! 1105: endif 1106: rawinput @ c@ cookedinput @ c! 1107: endif ; 1108: 1109: : charclass ( set "name" -- ) 1110: ['] ?nextchar terminal ; 1111: 1112: : .. ( c1 c2 -- set ) 1113: ( creates a set that includes the characters c, c1<=c<=c2 ) 1114: empty copy-set 1115: swap 1+ rot do 1116: i over add-member 1117: loop ; 1118: 1119: : ` ( -- terminal ) ( use: ` c ) 1120: ( creates anonymous terminal for the character c ) 1121: char singleton ['] ?nextchar make-terminal ; 1122: 1123: char a char z .. char A char Z .. union char _ singleton union charclass letter 1124: char 0 char 9 .. charclass digit 1125: bl singleton tab-char over add-member charclass white 1126: nl-char singleton eof-char over add-member complement charclass nonl 1127: nl-char singleton eof-char over add-member 1128: char : over add-member complement charclass nocolonnl 1129: bl 1+ maxchar .. char \ singleton complement intersection 1130: charclass nowhitebq 1131: bl 1+ maxchar .. charclass nowhite 1132: char " singleton eof-char over add-member complement charclass noquote 1133: nl-char singleton charclass nl 1134: eof-char singleton charclass eof 1135: nl-char singleton eof-char over add-member charclass nleof 1136: 1137: (( letter (( letter || digit )) ** 1138: )) <- c-ident ( -- ) 1139: 1140: (( ` # ?? (( letter || digit || ` : )) ** 1141: )) <- stack-ident ( -- ) 1142: 1143: (( nowhitebq nowhite ** )) 1144: <- forth-ident ( -- ) 1145: 1146: Variable forth-flag 1147: Variable c-flag 1148: 1149: (( (( ` e || ` E )) {{ start }} nonl ** 1150: {{ end evaluate }} 1151: )) <- eval-comment ( ... -- ... ) 1152: 1153: (( (( ` f || ` F )) {{ start }} nonl ** 1154: {{ end forth-flag @ IF type cr ELSE 2drop THEN }} 1155: )) <- forth-comment ( -- ) 1156: 1157: (( (( ` c || ` C )) {{ start }} nonl ** 1158: {{ end c-flag @ IF type cr ELSE 2drop THEN }} 1159: )) <- c-comment ( -- ) 1160: 1161: (( ` - nonl ** {{ 1162: forth-flag @ IF ." [ELSE]" cr THEN 1163: c-flag @ IF ." #else" cr THEN }} 1164: )) <- else-comment 1165: 1166: (( ` + {{ start }} nonl ** {{ end 1167: dup 1168: IF c-flag @ 1169: IF ." #ifdef HAS_" bounds ?DO I c@ toupper emit LOOP cr 1170: THEN 1171: forth-flag @ 1172: IF ." has? " type ." [IF]" cr THEN 1173: ELSE 2drop 1174: c-flag @ IF ." #endif" cr THEN 1175: forth-flag @ IF ." [THEN]" cr THEN 1176: THEN }} 1177: )) <- if-comment 1178: 1179: (( (( ` g || ` G )) {{ start }} nonl ** 1180: {{ end 1181: forth-flag @ IF ." group " type cr THEN 1182: c-flag @ IF ." GROUP(" type ." )" cr THEN }} 1183: )) <- group-comment 1184: 1185: (( (( eval-comment || forth-comment || c-comment || else-comment || if-comment || group-comment )) ?? nonl ** )) <- comment-body 1186: 1187: (( ` \ comment-body nleof )) <- comment ( -- ) 1188: 1189: (( {{ start }} stack-ident {{ end 2 pick init-item item% %size + }} white ** )) ** 1190: <- stack-items 1191: 1192: (( {{ prim prim-effect-in }} stack-items {{ prim prim-effect-in-end ! }} 1193: ` - ` - white ** 1194: {{ prim prim-effect-out }} stack-items {{ prim prim-effect-out-end ! }} 1195: )) <- stack-effect ( -- ) 1196: 1197: (( {{ prim create-prim }} 1198: ` ( white ** {{ start }} stack-effect {{ end prim prim-stack-string 2! }} ` ) white ** 1199: (( {{ start }} forth-ident {{ end prim prim-wordset 2! }} white ** 1200: (( {{ start }} c-ident {{ end prim prim-c-name 2! }} )) ?? 1201: )) ?? nleof 1202: (( ` " ` " {{ start }} (( noquote ++ ` " )) ++ {{ end 1- prim prim-doc 2! }} ` " white ** nleof )) ?? 1203: {{ skipsynclines off line @ c-line ! filename 2@ c-filename 2! start }} (( nocolonnl nonl ** nleof white ** )) ** {{ end prim prim-c-code 2! skipsynclines on }} 1204: (( ` : white ** nleof 1205: {{ start }} (( nonl ++ nleof white ** )) ++ {{ end prim prim-forth-code 2! }} 1206: )) ?? {{ process-simple }} 1207: nleof 1208: )) <- simple-primitive ( -- ) 1209: 1210: (( {{ init-combined }} 1211: ` = white ** (( {{ start }} forth-ident {{ end add-prim }} white ** )) ++ 1212: nleof {{ process-combined }} 1213: )) <- combined-primitive 1214: 1215: (( {{ make-prim to prim 0 to combined 1216: line @ name-line ! filename 2@ name-filename 2! 1217: function-number @ prim prim-num ! 1218: start }} forth-ident {{ end 2dup prim prim-name 2! prim prim-c-name 2! }} white ++ 1219: (( simple-primitive || combined-primitive )) {{ 1 function-number +! }} 1220: )) <- primitive ( -- ) 1221: 1222: (( (( comment || primitive || nl white ** )) ** eof )) 1223: parser primitives2something 1224: warnings @ [IF] 1225: .( parser generated ok ) cr 1226: [THEN] 1227: 1228: 1229: \ run with gforth-0.5.0 (slurp-file is missing) 1230: [IFUNDEF] slurp-file 1231: : slurp-file ( c-addr1 u1 -- c-addr2 u2 ) 1232: \ c-addr1 u1 is the filename, c-addr2 u2 is the file's contents 1233: r/o bin open-file throw >r 1234: r@ file-size throw abort" file too large" 1235: dup allocate throw swap 1236: 2dup r@ read-file throw over <> abort" could not read whole file" 1237: r> close-file throw ; 1238: [THEN] 1239: 1240: : primfilter ( addr u -- ) 1241: \ process the string at addr u 1242: over dup rawinput ! dup line-start ! cookedinput ! 1243: + endrawinput ! 1244: checksyncline 1245: primitives2something ; 1246: 1247: : process-file ( addr u xt-simple x-combined -- ) 1248: output-combined ! output ! 1249: save-mem 2dup filename 2! 1250: slurp-file 1251: warnings @ if 1252: ." ------------ CUT HERE -------------" cr endif 1253: primfilter ; 1254: 1255: \ : process ( xt -- ) 1256: \ bl word count rot 1257: \ process-file ;