lisp.s 104 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414
  1. ; Copyright (C) 2016 Jeremiah Orians
  2. ; This file is part of stage0.
  3. ;
  4. ; stage0 is free software: you can redistribute it and/or modify
  5. ; it under the terms of the GNU General Public License as published by
  6. ; the Free Software Foundation, either version 3 of the License, or
  7. ; (at your option) any later version.
  8. ;
  9. ; stage0 is distributed in the hope that it will be useful,
  10. ; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ; GNU General Public License for more details.
  13. ;
  14. ; You should have received a copy of the GNU General Public License
  15. ; along with stage0. If not, see <http://www.gnu.org/licenses/>.
  16. ;; A simple lisp with a precise garbage collector for cells
  17. ;; Cells are in the following form:
  18. ;; Type (0), CAR (4), CDR (8), ENV (12)
  19. ;; Each being the length of a register [32bits]
  20. ;;
  21. ;; Type maps to the following values
  22. ;; FREE = 1, MARKED = (1 << 1),INT = (1 << 2),SYM = (1 << 3),
  23. ;; CONS = (1 << 4),PROC = (1 << 5),PRIMOP = (1 << 6),CHAR = (1 << 7), STRING = (1 << 8)
  24. ;; CONS space: End of program -> 1MB (0x100000)
  25. ;; HEAP space: 1MB -> 1.5MB (0x180000)
  26. ;; STACK space: 1.5MB -> End of Memory (2MB (0x200000))
  27. ;; Start function
  28. :start
  29. ;; Check if we are going to hit outside the world
  30. HAL_MEM ; Get total amount of Memory
  31. LOADR R1 @MINIMAL_MEMORY ; Get our Minimal Value
  32. CMPSKIP.GE R0 R1 ; Check if we have enough
  33. JUMP @FAILED_INITIALIZATION ; If not fail gracefully
  34. LOADR R15 @stack_start ; Put stack after CONS and HEAP
  35. ;; We will be using R14 for our condition codes
  36. ;; We will be using R13 for which Input we will be using
  37. ;; We will be using R12 for which Output we will be using
  38. ;; Ensure a known good state
  39. FALSE R0 ; Reset R0
  40. FALSE R1 ; Reset R1
  41. ;; Initialize
  42. CALLI R15 @garbage_init
  43. CALLI R15 @init_sl3
  44. ;; Prep TAPE_01
  45. LOADUI R0 0x1100
  46. FOPEN_READ
  47. ;; We first read Tape_01 until completion
  48. LOADUI R13 0x1100
  49. ;; Prep TAPE_02
  50. LOADUI R0 0x1101
  51. FOPEN_WRITE
  52. ;; Main loop
  53. :main
  54. CALLI R15 @garbage_collect ; Clean up unused cells
  55. CALLI R15 @Readline ; Read another S-expression
  56. JUMP.Z R1 @main ; Don't allow empty strings
  57. CALLI R15 @parse ; Convert into tokens
  58. LOADR R1 @top_env ; Get TOP_ENV
  59. CALLI R15 @eval ; Evaluate tokens
  60. CALLI R15 @writeobj ; Print result
  61. LOADUI R0 10 ; Use LF
  62. COPY R1 R12 ; And desired Output
  63. FPUTC ; Write Line Feed
  64. FALSE R0 ; Clear R0
  65. FALSE R1 ; Clear R1
  66. JUMP @main ; Loop forever
  67. HALT ; If broken get the fuck out now
  68. :stack_start
  69. '00180000'
  70. ;; How much memory is too little
  71. :MINIMAL_MEMORY
  72. '00180000'
  73. ;; Halt the machine in the event of insufficient Memory
  74. :FAILED_INITIALIZATION
  75. FALSE R1 ; Set output to TTY
  76. LOADUI R0 $FAILED_STRING ; Prepare our Message
  77. CALLI R15 @Print_String ; Print it
  78. HALT ; Prevent any further damage
  79. :FAILED_STRING
  80. "Please provide 1600KB of Memory for this Lisp to run (More is recommended for large programs)
  81. "
  82. ;; Append_Cell
  83. ;; Adds a cell to the end of a CDR chain
  84. ;; Receives HEAD in R0 and Tail in R1
  85. ;; Returns HEAD if not NULL
  86. :append_Cell
  87. CMPSKIPI.NE R0 0 ; If HEAD is NULL
  88. MOVE R0 R1 ; Swap TAIL and HEAD
  89. PUSHR R3 R15 ; Protect R3
  90. PUSHR R0 R15 ; Preserve HEAD
  91. :append_Cell_loop
  92. LOAD32 R3 R0 8 ; Load HEAD->CDR
  93. CMPSKIPI.NE R3 0 ; If HEAD->CDR is NULL
  94. JUMP @append_Cell_done ; Append and call it done
  95. ;; Walk down list
  96. MOVE R0 R3 ; Make HEAD->CDR the new HEAD
  97. JUMP @append_Cell_loop ; And try again
  98. :append_Cell_done
  99. STORE32 R1 R0 8 ; Store HEAD->CDR = Tail
  100. POPR R0 R15 ; Ensure we are returning HEAD of list
  101. POPR R3 R15 ; Restore R3
  102. RET R15
  103. ;; Tokenize
  104. ;; Converts a string into a list of tokens
  105. ;; Receives HEAD in R0, Pointer to String in R1 and Size of string in R2
  106. ;; Returns HEAD of list in R0
  107. :tokenize
  108. ;; Deal with Edge case
  109. CMPSKIPI.NE R2 0 ; If remaining is 0
  110. RET R15 ; Just return
  111. PUSHR R3 R15 ; Protect R3
  112. PUSHR R4 R15 ; Protect R4
  113. FALSE R4 ; Set Counter to 0
  114. ;; Try to find whitespace Char
  115. :tokenize_loop
  116. LOADXU8 R3 R1 R4 ; Get char
  117. CMPSKIPI.G R3 32 ; If control character or SPACE
  118. JUMP @tokenize_append ; Stop
  119. CMPSKIPI.NE R3 34 ; If raw string
  120. JUMP @tokenize_string ; Process that whole thing
  121. ;; Walk further down string
  122. ADDUI R4 R4 1 ; Next char
  123. JUMP @tokenize_loop ; And try again
  124. :tokenize_string
  125. ;; Walk further down string
  126. ADDUI R4 R4 1 ; Next char
  127. LOADXU8 R3 R1 R4 ; Get char
  128. CMPSKIPI.NE R3 34 ; If Found matching quote
  129. JUMP @tokenize_append ; Stop
  130. JUMP @tokenize_string ; And try again
  131. :tokenize_append
  132. FALSE R3 ; NULL terminate
  133. STOREX8 R3 R1 R4 ; Found Token
  134. COPY R3 R1 ; Preserve pointer to string
  135. CMPSKIPI.NE R4 0 ; If empty
  136. JUMP @tokenize_iterate ; Don't bother to append
  137. ;; Make string token and append
  138. SWAP R0 R1 ; Need to send string in R0 for call
  139. CALLI R15 @make_sym ; Convert string to token
  140. SWAP R0 R1 ; Put HEAD and Tail in proper order
  141. CALLI R15 @append_Cell ; Append Token to HEAD
  142. ;; Loop down string until end, appending tokens along the way
  143. :tokenize_iterate
  144. ADDUI R4 R4 1 ; Move past NULL
  145. ADD R1 R3 R4 ; Update string pointer
  146. SUB R2 R2 R4 ; Decrement by size used
  147. FALSE R4 ; Reset Counter
  148. CMPSKIPI.LE R2 0 ; If NOT end of string
  149. JUMP @tokenize_loop ; try to append another token
  150. ;; Clean up
  151. POPR R4 R15 ; Restore R4
  152. POPR R3 R15 ; Restore R3
  153. RET R15
  154. ;; is_integer
  155. ;; Receives pointer to string in R0
  156. ;; Returns TRUE or FALSE in R0
  157. :is_integer
  158. PUSHR R1 R15 ; Protect R1
  159. LOADU8 R1 R0 0 ; Read first Char
  160. CMPSKIPI.NE R1 45 ; If starts with -
  161. LOADU8 R1 R0 1 ; Get Second Char
  162. FALSE R0 ; Assume FALSE
  163. CMPSKIPI.GE R1 48 ; If below '0'
  164. JUMP @is_integer_done ; Return FALSE
  165. CMPSKIPI.G R1 57 ; If 0 to 9
  166. TRUE R0 ; Set to TRUE
  167. :is_integer_done
  168. POPR R1 R15 ; Restore R1
  169. RET R15
  170. ;; numerate_string function
  171. ;; Receives pointer To string in R0
  172. ;; Returns number in R0 equal to value of string
  173. ;; Or Zero in the event of invalid string
  174. :numerate_string
  175. ;; Preserve Registers
  176. PUSHR R1 R15
  177. PUSHR R2 R15
  178. PUSHR R3 R15
  179. PUSHR R4 R15
  180. ;; Initialize
  181. MOVE R1 R0 ; Get Text pointer out of the way
  182. FALSE R2 ; Set Negative flag to false
  183. FALSE R3 ; Set current count to Zero
  184. LOAD8 R0 R1 1 ; Get second byte
  185. CMPSKIPI.NE R0 120 ; If the second byte is x
  186. JUMP @numerate_string_hex ; treat string like hex
  187. ;; Deal with Decimal input
  188. LOADUI R4 10 ; Multiply by 10
  189. LOAD8 R0 R1 0 ; Get a byte
  190. CMPSKIPI.NE R0 45 ; If - toggle flag
  191. TRUE R2 ; So that we know to negate
  192. CMPSKIPI.E R2 0 ; If toggled
  193. ADDUI R1 R1 1 ; Move to next
  194. :numerate_string_dec
  195. LOAD8 R0 R1 0 ; Get a byte
  196. CMPSKIPI.NE R0 0 ; If NULL
  197. JUMP @numerate_string_done ; Be done
  198. MUL R3 R3 R4 ; Shift counter by 10
  199. SUBI R0 R0 48 ; Convert ascii to number
  200. CMPSKIPI.GE R0 0 ; If less than a number
  201. JUMP @numerate_string_done ; Terminate NOW
  202. CMPSKIPI.L R0 10 ; If more than a number
  203. JUMP @numerate_string_done ; Terminate NOW
  204. ADDU R3 R3 R0 ; Don't add to the count
  205. ADDUI R1 R1 1 ; Move onto next byte
  206. JUMP @numerate_string_dec
  207. ;; Deal with Hex input
  208. :numerate_string_hex
  209. LOAD8 R0 R1 0 ; Get a byte
  210. CMPSKIPI.E R0 48 ; All hex strings start with 0x
  211. JUMP @numerate_string_done ; Be done if not a match
  212. ADDUI R1 R1 2 ; Move to after leading 0x
  213. :numerate_string_hex_0
  214. LOAD8 R0 R1 0 ; Get a byte
  215. CMPSKIPI.NE R0 0 ; If NULL
  216. JUMP @numerate_string_done ; Be done
  217. SL0I R3 4 ; Shift counter by 16
  218. SUBI R0 R0 48 ; Convert ascii number to number
  219. CMPSKIPI.L R0 10 ; If A-F
  220. SUBI R0 R0 7 ; Shove into Range
  221. CMPSKIPI.L R0 16 ; If a-f
  222. SUBI R0 R0 32 ; Shove into Range
  223. ADDU R3 R3 R0 ; Add to the count
  224. ADDUI R1 R1 1 ; Get next Hex
  225. JUMP @numerate_string_hex_0
  226. ;; Clean up
  227. :numerate_string_done
  228. CMPSKIPI.E R2 0 ; If Negate flag has been set
  229. NEG R3 R3 ; Make the number negative
  230. MOVE R0 R3 ; Put number in R0
  231. ;; Restore Registers
  232. POPR R4 R15
  233. POPR R3 R15
  234. POPR R2 R15
  235. POPR R1 R15
  236. RET R15
  237. ;; atom
  238. ;; Converts tokens into native forms
  239. ;; Aka numbers become numbers and everything else is a symbol
  240. ;; Receives a pointer to Token in R0
  241. ;; Returns a pointer to a Cell in R0
  242. :atom
  243. PUSHR R1 R15 ; Protect R1
  244. PUSHR R2 R15 ; Protect R2
  245. PUSHR R3 R15 ; Protect R3
  246. LOAD32 R1 R0 4 ; Get CAR
  247. LOADU8 R2 R1 0 ; Get first Char
  248. CMPSKIPI.E R2 39 ; If Not Quote Char
  249. JUMP @atom_string ; Move to next type
  250. ;; When dealing with a quote
  251. ADDUI R1 R1 1 ; Move past quote Char
  252. STORE32 R1 R0 4 ; And write to CAR
  253. LOADUI R1 $NIL ; Using NIL
  254. CALLI R15 @make_cons ; Make a cons with the token
  255. MOVE R1 R0 ; Put the resulting CONS in R1
  256. LOADUI R0 $s_quote ; Using S_QUOTE
  257. CALLI R15 @make_cons ; Make a CONS with the CONS
  258. MOVE R1 R0 ; Put What is being returned into R1
  259. JUMP @atom_done ; We are done
  260. :atom_string
  261. CMPSKIPI.E R2 34 ; If Not Double quote
  262. JUMP @atom_integer ; Move to next type
  263. ;; a->string = a->string + 1
  264. ADDUI R1 R1 1 ; Move past quote Char
  265. STORE32 R1 R0 4 ; And write to CAR
  266. ;; a->type = STRING
  267. LOADUI R1 256 ; Using STRING
  268. STORE32 R1 R0 0 ; Set type to Integer
  269. COPY R1 R0 ; Put the cell we were given in the right place
  270. JUMP @atom_done ; We are done
  271. :atom_integer
  272. COPY R2 R1 ; Preserve String pointer
  273. SWAP R0 R1 ; Put string Pointer in R0
  274. CALLI R15 @is_integer ; Determine if it is an integer
  275. JUMP.Z R0 @atom_functions ; If Not an integer move on
  276. LOADUI R0 4 ; Using INT
  277. STORE32 R0 R1 0 ; Set type to Integer
  278. MOVE R0 R2 ; Using String pointer
  279. CALLI R15 @numerate_string ; Convert to Number
  280. STORE32 R0 R1 4 ; Store result in CAR
  281. JUMP @atom_done ; We are done (Result is in R1)
  282. :atom_functions
  283. COPY R0 R2 ; Using String pointer
  284. CALLI R15 @findsym ; Lookup Symbol
  285. LOADUI R3 $NIL ; Using NIL
  286. CMPSKIP.NE R0 R3 ; If NIL was Returned
  287. JUMP @atom_new ; Make a new Symbol
  288. LOAD32 R1 R0 4 ; Make OP->CAR our result
  289. JUMP @atom_done ; We are done (Result is in R1)
  290. :atom_new
  291. LOADR32 R0 @all_symbols ; Get pointer to all symbols
  292. SWAP R0 R1 ; Put pointers in correct order
  293. COPY R3 R0 ; Protect A
  294. CALLI R15 @make_cons ; Make a CONS out of Token and all_symbols
  295. STORER32 R0 @all_symbols ; Update all_symbols
  296. MOVE R1 R3 ; Put result in correct register
  297. :atom_done
  298. MOVE R0 R1 ; Put our result in R0
  299. POPR R3 R15 ; Restore R3
  300. POPR R2 R15 ; Restore R2
  301. POPR R1 R15 ; Restore R1
  302. RET R15
  303. :token_stack
  304. NOP ; Pointer to Unparsed Tokens
  305. ;; readobj
  306. ;; Breaks up tokens on the token_stack until its empty
  307. ;; Receives Nothing
  308. ;; Returns a Cell in R0
  309. :readobj
  310. PUSHR R1 R15 ; Protect R1
  311. PUSHR R2 R15 ; Protect R2
  312. LOADR32 R0 @token_stack ; Get HEAD
  313. LOAD32 R1 R0 8 ; Get HEAD->CDR
  314. STORER32 R1 @token_stack ; Update Token Stack
  315. FALSE R1 ; Using NULL
  316. STORE32 R1 R0 8 ; Set HEAD->CDR
  317. LOAD32 R1 R0 4 ; Get HEAD->CAR
  318. LOADU8 R1 R1 0 ; Get First Char of HEAD->CAR
  319. CMPSKIPI.E R1 40 ; If NOT (
  320. JUMP @readobj_0 ; Atomize HEAD
  321. CALLI R15 @readlist ; Otherwise we want the result of readlist
  322. JUMP @readobj_done
  323. :readobj_0
  324. CALLI R15 @atom ; Let Atom process HEAD for us
  325. :readobj_done
  326. POPR R2 R15 ; Restore R2
  327. POPR R1 R15 ; Restore R1
  328. RET R15
  329. ;; readlist
  330. ;; CONS up Rest of elements until ) is found
  331. ;; Receives nothing
  332. ;; Returns A Cell in R0
  333. :readlist
  334. PUSHR R1 R15 ; Protect R1
  335. LOADR32 R0 @token_stack ; Get HEAD
  336. LOAD32 R1 R0 4 ; Get HEAD->CAR
  337. LOADU8 R1 R1 0 ; Get first Char of HEAD->CAR
  338. CMPSKIPI.E R1 41 ; If NOT )
  339. JUMP @readlist_0 ; CONS up elements
  340. LOAD32 R1 R0 8 ; Get HEAD->CDR
  341. STORER32 R1 @token_stack ; Update token stack
  342. LOADUI R0 $NIL ; Use NIL (Result in R0)
  343. JUMP @readlist_done
  344. :readlist_0
  345. CALLI R15 @readobj ; Have readobj do its work
  346. MOVE R1 R0 ; Put the result in a safe place
  347. CALLI R15 @readlist ; Recursively call self
  348. SWAP R0 R1 ; Put results in proper order
  349. CALLI R15 @make_cons ; Make into a CONS (Result in R0)
  350. :readlist_done
  351. POPR R1 R15 ; Restore R1
  352. RET R15
  353. ;; parse
  354. ;; Starts the recursive tokenizing and atomizing of input
  355. ;; Receives a string in R0 and its length in R1
  356. ;; Returns a list of Cells in R0
  357. :parse
  358. PUSHR R2 R15 ; Protect R2
  359. MOVE R2 R1 ; Put Size in the correct place
  360. MOVE R1 R0 ; Put string pointer in the correct place
  361. CALLI R15 @tokenize ; Get a list of tokens from string
  362. STORER32 R0 @token_stack ; Shove list to token_stack
  363. JUMP.NZ R0 @parse_0 ; If not a NULL list atomize
  364. LOADUI R0 $NIL ; Otherwise we return NIL
  365. JUMP @parse_done ; Result in R0
  366. :parse_0
  367. CALLI R15 @readobj ; Start the atomization (Result in R0)
  368. :parse_done
  369. POPR R2 R15 ; Restore R2
  370. RET R15
  371. ;; Our simple malloc function
  372. ;; Receives A number of bytes to allocate in R0
  373. ;; Returns a pointer to Segment in R0
  374. :malloc
  375. PUSHR R1 R15 ; Protect R1
  376. LOADR R1 @malloc_pointer ; Get current malloc pointer
  377. ;; update malloc pointer
  378. SWAP R0 R1
  379. ADD R1 R0 R1
  380. STORER R1 @malloc_pointer
  381. ;; Done
  382. POPR R1 R15 ; Restore R1
  383. RET R15
  384. ;; Our static value for malloc pointer
  385. ;; Starting at 1MB
  386. :malloc_pointer
  387. '00100000'
  388. ;; Switch_Input
  389. ;; If R13 is TTY, HALT
  390. ;; Else Set input to TTY
  391. :Switch_Input
  392. CMPSKIPI.NE R13 0 ; IF TTY
  393. HALT ; Simply Done
  394. FALSE R13 ; Otherwise switch to TTY
  395. RET R15
  396. ;; Readline
  397. ;; Using IO source in R13 read a FULL S-expression
  398. ;; Returns String pointer in R0 and Length in R1
  399. :Readline
  400. PUSHR R2 R15 ; Protect R2
  401. PUSHR R3 R15 ; Protect R3
  402. PUSHR R4 R15 ; Protect R4
  403. PUSHR R5 R15 ; Protect R5
  404. FALSE R0 ; Get where space is free
  405. CALLI R15 @malloc
  406. MOVE R2 R0 ; Preserve pointer
  407. FALSE R3 ; Set index to 0
  408. FALSE R4 ; Set Depth to 0
  409. COPY R1 R13 ; Set desired IO
  410. LOADUI R5 32 ; Keep SPACE for ()
  411. ;; Main Loop
  412. :Readline_loop
  413. FGETC ; Get a Byte
  414. CMPSKIPI.G R0 4 ; If EOF
  415. CALLI R15 @Switch_Input ; Do the correct thing
  416. CMPSKIPI.NE R0 13 ; If CR
  417. LOADUI R0 10 ; Replace with LF
  418. CMPSKIPI.NE R13 0 ; Don't display unless TTY
  419. FPUTC ; Display the Char we just pressed
  420. CMPSKIPI.G R0 32 ; If SPACE or below
  421. JUMP @Readline_1
  422. CMPSKIPI.NE R0 34 ; Look for double quote
  423. JUMP @Readline_string ; Keep looping until then
  424. CMPSKIPI.NE R0 59 ; If LINE Comment (;)
  425. JUMP @Readline_0 ; Drop until the end of Line
  426. CMPSKIPI.NE R0 40 ; If (
  427. JUMP @Readline_2 ; Deal with depth and spacing
  428. CMPSKIPI.NE R0 41 ; If )
  429. JUMP @Readline_2 ; Deal with depth and spacing
  430. STOREX8 R0 R2 R3 ; Append to String
  431. ADDUI R3 R3 1 ; Increment Size
  432. JUMP @Readline_loop ; Keep Reading
  433. ;; Deal with Line comments
  434. :Readline_0
  435. FGETC ; Get another Byte
  436. CMPSKIPI.NE R0 13 ; Deal with CR
  437. LOADUI R0 10 ; Convert to LF
  438. CMPSKIPI.NE R0 10 ; If LF
  439. JUMP @Readline_loop ; Resume
  440. JUMP @Readline_0 ; Otherwise Keep Looping
  441. ;; Deal with strings
  442. :Readline_string
  443. STOREX8 R0 R2 R3 ; Append to String
  444. ADDUI R3 R3 1 ; Increment Size
  445. FGETC ; Get a Byte
  446. CMPSKIPI.NE R0 13 ; Deal with CR
  447. LOADUI R0 10 ; Convert to LF
  448. CMPSKIPI.NE R13 0 ; Don't display unless TTY
  449. FPUTC ; Display the Char we just pressed
  450. CMPSKIPI.E R0 34 ; Look for double quote
  451. JUMP @Readline_string ; Keep looping until then
  452. STOREX8 R0 R2 R3 ; Append to String
  453. ADDUI R3 R3 1 ; Increment Size
  454. JUMP @Readline_loop ; Resume
  455. ;; Deal with Whitespace and Control Chars
  456. :Readline_1
  457. CMPSKIPI.NE R4 0 ; IF Depth 0
  458. JUMP @Readline_done ; We made it to the end
  459. LOADUI R0 32 ; Otherwise convert to SPACE
  460. STOREX8 R0 R2 R3 ; Append to String
  461. ADDUI R3 R3 1 ; Increment Size
  462. JUMP @Readline_loop ; Keep Looping
  463. ;; Deal with ()
  464. :Readline_2
  465. CMPSKIPI.NE R0 40 ; If (
  466. ADDUI R4 R4 1 ; Increment Depth
  467. CMPSKIPI.NE R0 41 ; If )
  468. SUBUI R4 R4 1 ; Decrement Depth
  469. STOREX8 R5 R2 R3 ; Put in leading SPACE
  470. ADDUI R3 R3 1 ; Increment Size
  471. STOREX8 R0 R2 R3 ; Put in Char
  472. ADDUI R3 R3 1 ; Increment Size
  473. STOREX8 R5 R2 R3 ; Put in Trailing SPACE
  474. ADDUI R3 R3 1 ; Increment Size
  475. JUMP @Readline_loop ; Resume
  476. ;; Clean up
  477. :Readline_done
  478. ADDUI R0 R3 4 ; Pad with 4 NULLs
  479. CALLI R15 @malloc ; Correct Malloc
  480. MOVE R1 R3 ; Put Size in R1
  481. POPR R5 R15 ; Restore R5
  482. POPR R4 R15 ; Restore R4
  483. POPR R3 R15 ; Restore R3
  484. POPR R2 R15 ; Restore R2
  485. RET R15
  486. ;; Write_Int
  487. ;; Writes desired integer to desired IO
  488. ;; Receives Integer in R0 and IO in R1
  489. ;; Returns Nothing
  490. :Max_Decimal
  491. '3B9ACA00'
  492. :Write_Int
  493. PUSHR R0 R15 ; Preserve R0
  494. PUSHR R1 R15 ; Preserve R1
  495. PUSHR R2 R15 ; Preserve R2
  496. PUSHR R3 R15 ; Preserve R3
  497. PUSHR R4 R15 ; Preserve R4
  498. PUSHR R5 R15 ; Preserve R5
  499. MOVE R3 R0 ; Move Integer out of the way
  500. JUMP.Z R3 @Write_Int_ZERO ; Deal with Special case of ZERO
  501. JUMP.P R3 @Write_Int_Positive
  502. LOADUI R0 45 ; Using -
  503. FPUTC ; Display leading -
  504. NOT R3 R3 ; Flip into positive
  505. ADDUI R3 R3 1 ; Adjust twos
  506. :Write_Int_Positive
  507. LOADR R2 @Max_Decimal ; Starting from the Top
  508. LOADUI R5 10 ; We move down by 10
  509. FALSE R4 ; Flag leading Zeros
  510. :Write_Int_0
  511. DIVIDE R0 R3 R3 R2 ; Break off top 10
  512. CMPSKIPI.E R0 0 ; If Not Zero
  513. TRUE R4 ; Flip the Flag
  514. JUMP.Z R4 @Write_Int_1 ; Skip leading Zeros
  515. ADDUI R0 R0 48 ; Shift into ASCII
  516. FPUTC ; Print Top
  517. :Write_Int_1
  518. DIV R2 R2 R5 ; Look at next 10
  519. CMPSKIPI.E R2 0 ; If we reached the bottom STOP
  520. JUMP @Write_Int_0 ; Otherwise keep looping
  521. :Write_Int_done
  522. ;; Cleanup
  523. POPR R5 R15 ; Restore R5
  524. POPR R4 R15 ; Restore R4
  525. POPR R3 R15 ; Restore R3
  526. POPR R2 R15 ; Restore R2
  527. POPR R1 R15 ; Restore R1
  528. POPR R0 R15 ; Restore R0
  529. RET R15
  530. :Write_Int_ZERO
  531. LOADUI R0 48 ; Using Zero
  532. FPUTC ; Display
  533. JUMP @Write_Int_done ; Be done
  534. ;; Print_String
  535. ;; Prints the string pointed in R0 to IO in R1
  536. ;; Receives string pointer in R0 and IO in R1
  537. ;; Returns nothing
  538. :Print_String
  539. PUSHR R0 R15 ; Protect R0
  540. PUSHR R2 R15 ; Protect R2
  541. MOVE R2 R0 ; Get pointer out of the way
  542. :Print_String_loop
  543. LOADU8 R0 R2 0 ; Get Char
  544. CMPSKIPI.NE R0 0 ; If NULL
  545. JUMP @Print_String_done ; Call it done
  546. FPUTC ; Otherwise write the Char
  547. ADDUI R2 R2 1 ; Increment to next Char
  548. JUMP @Print_String_loop ; And Keep looping
  549. :Print_String_done
  550. POPR R2 R15 ; Restore R2
  551. POPR R0 R15 ; Restore R0
  552. RET R15
  553. ;; writeobj
  554. ;; Outputs to the IO in R12
  555. ;; Receives a Cell list in R0
  556. ;; Returns nothing
  557. :writeobj
  558. PUSHR R0 R15 ; Protect R0
  559. PUSHR R1 R15 ; Protect R1
  560. PUSHR R2 R15 ; Protect R2
  561. PUSHR R3 R15 ; Protect R3
  562. COPY R3 R0 ; Protect HEAD
  563. LOAD32 R2 R0 0 ; Load HEAD->Type
  564. COPY R1 R12 ; Using desired output
  565. CMPSKIPI.NE R2 4 ; If INT
  566. JUMP @writeobj_INT ; Print it and be done
  567. CMPSKIPI.NE R2 8 ; If SYM
  568. JUMP @writeobj_SYM ; Print its string
  569. CMPSKIPI.NE R2 16 ; If CONS
  570. JUMP @writeobj_CONS ; Print it all recursively
  571. CMPSKIPI.NE R2 32 ; If PROC
  572. JUMP @writeobj_PROC ; Print Label
  573. CMPSKIPI.NE R2 64 ; If PRIMOP
  574. JUMP @writeobj_PRIMOP ; Print Label
  575. CMPSKIPI.NE R2 128 ; If CHAR
  576. JUMP @writeobj_CHAR ; Print the Char
  577. CMPSKIPI.NE R2 256 ; If STRING
  578. JUMP @writeobj_STRING ; Print the String
  579. ;; What the hell is that???
  580. LOADUI R0 $writeobj_Error
  581. FALSE R1
  582. CALLI R15 @Print_String
  583. HALT
  584. :writeobj_Error
  585. "What the fuck was that?"
  586. :writeobj_INT
  587. LOAD32 R0 R0 4 ; Get HEAD->CAR
  588. CALLI R15 @Write_Int ; Write it output
  589. JUMP @writeobj_done ; Be done
  590. :writeobj_CONS
  591. LOADUI R0 40 ; Using (
  592. FPUTC ; Write to desired output
  593. :writeobj_CONS_0
  594. LOAD32 R0 R3 4 ; Get HEAD->CAR
  595. CALLI R15 @writeobj ; Recurse on HEAD->CAR
  596. LOAD32 R3 R3 8 ; Set HEAD to HEAD->CDR
  597. LOADUI R0 $NIL ; Using NIL
  598. CMPJUMPI.E R0 R3 @writeobj_CONS_1
  599. LOAD32 R0 R3 0 ; Get HEAD->type
  600. CMPSKIPI.E R0 16 ; if Not CONS
  601. JUMP @writeobj_CONS_2 ; Deal with inner case
  602. LOADUI R0 32 ; Using SPACE
  603. FPUTC ; Write out desired space
  604. JUMP @writeobj_CONS_0 ; Keep looping
  605. ;; Deal with case of op->cdr == nil
  606. :writeobj_CONS_1
  607. LOADUI R0 41 ; Using )
  608. FPUTC ; Write to desired output
  609. JUMP @writeobj_done ; Be Done
  610. :writeobj_CONS_2
  611. COPY R0 R3 ; Using HEAD
  612. CALLI R15 @writeobj ; Recurse
  613. LOADUI R0 41 ; Using )
  614. FPUTC ; Write to desired output
  615. JUMP @writeobj_done ; Be Done
  616. :writeobj_SYM
  617. LOAD32 R0 R3 4 ; Get HEAD->CAR
  618. CALLI R15 @Print_String ; Write it to output
  619. JUMP @writeobj_done ; Be Done
  620. :PRIMOP_String
  621. "#<PRIMOP>"
  622. :writeobj_PRIMOP
  623. LOADUI R0 $PRIMOP_String ; Using the desired string
  624. CALLI R15 @Print_String ; Write it to output
  625. JUMP @writeobj_done ; Be Done
  626. :PROC_String
  627. "#<PROC>"
  628. :writeobj_PROC
  629. LOADUI R0 $PROC_String ; Using the desired string
  630. CALLI R15 @Print_String ; Write it to output
  631. JUMP @writeobj_done ; Be Done
  632. :writeobj_STRING
  633. LOAD32 R0 R3 4 ; Get HEAD->CAR
  634. CALLI R15 @Print_String ; Write it to output
  635. JUMP @writeobj_done ; Be Done
  636. :writeobj_CHAR
  637. LOADU8 R0 R3 7 ; Using bottom 8 bits of HEAD->CAR
  638. FPUTC ; We write our desired output
  639. :writeobj_done
  640. POPR R3 R15 ; Restore R3
  641. POPR R2 R15 ; Restore R2
  642. POPR R1 R15 ; Restore R1
  643. POPR R0 R15 ; Restore R0
  644. RET R15
  645. ;; strcmp
  646. ;; A simple string compare function
  647. ;; Receives string pointers in R0 and R1
  648. ;; Returns result of comparision in R0
  649. :strcmp
  650. ;; Preserve registers
  651. PUSHR R2 R15
  652. PUSHR R3 R15
  653. PUSHR R4 R15
  654. ;; Setup registers
  655. MOVE R2 R0
  656. MOVE R3 R1
  657. LOADUI R4 0
  658. :cmpbyte
  659. LOADXU8 R0 R2 R4 ; Get a byte of our first string
  660. LOADXU8 R1 R3 R4 ; Get a byte of our second string
  661. ADDUI R4 R4 1 ; Prep for next loop
  662. CMP R1 R0 R1 ; Compare the bytes
  663. CMPSKIPI.E R0 0 ; Stop if byte is NULL
  664. JUMP.E R1 @cmpbyte ; Loop if bytes are equal
  665. ;; Done
  666. MOVE R0 R1 ; Prepare for return
  667. ;; Restore registers
  668. POPR R4 R15
  669. POPR R3 R15
  670. POPR R2 R15
  671. RET R15
  672. ;; findsym
  673. ;; Attempts to find a symbol in a CONS list
  674. ;; Receives a string in R0
  675. ;; Returns Cell or NIL in R0
  676. :findsym
  677. PUSHR R1 R15 ; Protect R1
  678. PUSHR R2 R15 ; Protect R2
  679. PUSHR R3 R15 ; Protect R3
  680. COPY R3 R0 ; Protect String
  681. LOADR R2 @all_symbols ; Get all_symbols
  682. :findsym_loop
  683. LOADUI R0 $NIL ; Using NIL
  684. CMPSKIP.NE R0 R2 ; Check if we reached the end
  685. JUMP @findsym_done ; Use NIL as our result
  686. LOAD32 R0 R2 4 ; Get symlist->CAR
  687. LOAD32 R0 R0 4 ; Get symlist->CAR->CAR
  688. COPY R1 R3 ; Prepare string to find
  689. CALLI R15 @strcmp ; See if we have a match
  690. JUMP.E R0 @findsym_found ; We have a match
  691. LOAD32 R2 R2 8 ; symlist = symlist->CDR
  692. JUMP @findsym_loop ; Keep looping
  693. :findsym_found
  694. MOVE R0 R2 ; We want symlist as our result
  695. :findsym_done
  696. POPR R3 R15 ; Restore R3
  697. POPR R2 R15 ; Restore R2
  698. POPR R1 R15 ; Restore R1
  699. RET R15
  700. ;; intern
  701. ;; Either find symbol or make it
  702. ;; Receives string pointer in R0
  703. ;; Returns a Cell pointer in R0
  704. :intern
  705. PUSHR R1 R15 ; Protect R1
  706. PUSHR R2 R15 ; Protect R2
  707. COPY R1 R0 ; Protect String
  708. CALLI R15 @findsym ; Lookup Symbol
  709. CMPSKIPI.NE R0 $NIL ; Determine if Symbol was found
  710. JUMP @intern_found ; And if so, use it
  711. MOVE R0 R1 ; Using our string
  712. CALLI R15 @make_sym ; Make a SYM
  713. COPY R2 R0 ; Protect Cell
  714. LOADR32 R1 @all_symbols ; Get all_symbols
  715. CALLI R15 @make_cons ; CONS together
  716. STORER32 R0 @all_symbols ; Update all_symbols
  717. MOVE R0 R2 ; Restore Cell
  718. JUMP @intern_done ; R0 has our result
  719. :intern_found
  720. LOAD32 R0 R0 4 ; Use op->CAR as our result
  721. :intern_done
  722. POPR R2 R15 ; Restore R2
  723. POPR R1 R15 ; Restore R1
  724. RET R15
  725. ;; extend
  726. ;; CONS up symbols with an environment
  727. ;; Receives an environment in R0, symbol in R1 and Value in R2
  728. ;; Returns a CONS of CONS in R0
  729. :extend
  730. PUSHR R1 R15 ; Protect R1
  731. PUSHR R2 R15 ; Protect R2
  732. PUSHR R3 R15 ; Protect R3
  733. SWAP R2 R0 ; Protect the env until we need it
  734. SWAP R0 R1 ; Put Symbol and Value in Correct Order
  735. CALLI R15 @make_cons ; Make inner CONS
  736. MOVE R1 R2 ; Get env now that we need it
  737. CALLI R15 @make_cons ; Make outter CONS
  738. POPR R3 R15 ; Restore R3
  739. POPR R2 R15 ; Restore R2
  740. POPR R1 R15 ; Restore R1
  741. RET R15
  742. ;; multiple_extend
  743. ;; Receives an environment in R0, symbol in R1 and Values in R2
  744. ;; Returns an extended environment in R0
  745. :multiple_extend
  746. PUSHR R1 R15 ; Protect R1
  747. PUSHR R2 R15 ; Protect R2
  748. PUSHR R3 R15 ; Protect R3
  749. PUSHR R4 R15 ; Protect R4
  750. PUSHR R5 R15 ; Protect R5
  751. LOADUI R5 $NIL ; We will need NIL
  752. :multiple_extend_0
  753. CMPJUMPI.E R1 R5 @multiple_extend_done
  754. LOAD32 R3 R1 8 ; Protect SYMS->CDR
  755. LOAD32 R4 R2 8 ; Protect VALS->CDR
  756. LOAD32 R1 R1 4 ; Using SYMS->CAR
  757. LOAD32 R2 R2 4 ; Using VALS->CAR
  758. CALLI R15 @extend ; Extend Environment
  759. MOVE R1 R3 ; USING SYMS->CDR
  760. MOVE R2 R4 ; VALS->CDR
  761. JUMP @multiple_extend_0 ; Iterate until fully extended
  762. :multiple_extend_done
  763. POPR R5 R15 ; Restore R5
  764. POPR R4 R15 ; Restore R4
  765. POPR R3 R15 ; Restore R3
  766. POPR R2 R15 ; Restore R2
  767. POPR R1 R15 ; Restore R1
  768. RET R15
  769. ;; extend_env
  770. ;; Receives a Symbol in R0, a Value in R1 and an environment pointer in R2
  771. ;; Returns Value in R0 after extending top
  772. :extend_env
  773. PUSHR R1 R15 ; Protect Val
  774. PUSHR R2 R15 ; Protect R2
  775. PUSHR R3 R15 ; Protect R3
  776. PUSHR R4 R15 ; Protect R4
  777. CALLI R15 @make_cons ; Make a cons of SYM and VAL
  778. MOVE R3 R0 ; Put safely out of way
  779. LOAD32 R0 R2 4 ; Using ENV->CAR
  780. LOAD32 R1 R2 8 ; And ENV->CDR
  781. CALLI R15 @make_cons ; Make a cons of old environment
  782. STORE32 R0 R2 8 ; SET ENV->CDR to old environment
  783. STORE32 R3 R2 4 ; SET ENV->CAR to new CONS
  784. POPR R4 R15 ; Restore R4
  785. POPR R3 R15 ; Restore R3
  786. POPR R2 R15 ; Restore R2
  787. POPR R1 R15 ; Restore Val
  788. COPY R0 R1 ; Return Val
  789. RET R15
  790. ;; assoc
  791. ;; Receives a Key in R0 and an alist in R1
  792. ;; Returns Value if Found or NIL in R0
  793. :assoc
  794. PUSHR R1 R15 ; Protect R1
  795. PUSHR R2 R15 ; Protect R2
  796. PUSHR R3 R15 ; Protect R3
  797. PUSHR R4 R15 ; Protect R4
  798. LOADUI R4 $NIL ; Using NIL
  799. LOAD32 R0 R0 4 ; Using KEY->CAR
  800. :assoc_0
  801. CMPJUMPI.E R1 R4 @assoc_done
  802. LOAD32 R2 R1 4 ; ALIST->CAR
  803. LOAD32 R3 R2 4 ; ALIST->CAR->CAR
  804. LOAD32 R3 R3 4 ; ALIST->CAR->CAR->CAR
  805. LOAD32 R1 R1 8 ; ALIST = ALIST->CDR
  806. CMPSKIP.E R0 R3 ; If ALIST->CAR->CAR->CAR != KEY->CAR
  807. JUMP @assoc_0 ; Iterate using ALIST->CDR
  808. ;; Found KEY
  809. MOVE R4 R2 ; Set ALIST->CAR as our return value
  810. :assoc_done
  811. MOVE R0 R4 ; Use whatever in R4 as our return
  812. POPR R4 R15 ; Restore R4
  813. POPR R3 R15 ; Restore R3
  814. POPR R2 R15 ; Restore R2
  815. POPR R1 R15 ; Restore R1
  816. RET R15
  817. ;; evlis
  818. ;; Receives Expressions in R0 and an Environment in R1
  819. ;; Returns the result of Evaluation of those Expressions
  820. ;; in respect to the given Environment in R0
  821. :evlis
  822. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  823. RET R15 ; Just get the Hell out
  824. PUSHR R1 R15 ; Protect R1
  825. PUSHR R2 R15 ; Protect R2
  826. PUSHR R3 R15 ; Protect R3
  827. COPY R3 R1 ; Protect ENV
  828. LOAD32 R2 R0 4 ; Protect EXPRS->CAR
  829. LOAD32 R0 R0 8 ; Using EXPRS->CDR
  830. CALLI R15 @evlis ; Recursively Call self Down Expressions
  831. SWAP R0 R2 ; Using EXPRS->CDR
  832. MOVE R1 R3 ; Restore ENV
  833. CALLI R15 @eval ; EVAL
  834. MOVE R1 R2 ; Using result of EVAL and EVLIS
  835. CALLI R15 @make_cons ; Make a CONS of it all
  836. POPR R3 R15 ; Restore R3
  837. POPR R2 R15 ; Restore R2
  838. POPR R1 R15 ; Restore R1
  839. RET R15
  840. ;; progn
  841. ;; Receives Expressions in R0 and an Environment in R1
  842. ;; Returns the result of Evaluation of those Expressions
  843. ;; in respect to the given Environment in R0
  844. :progn
  845. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  846. RET R15 ; Just get the Hell out
  847. PUSHR R1 R15 ; Protect R1
  848. PUSHR R2 R15 ; Protect R2
  849. PUSHR R3 R15 ; Protect R3
  850. LOADUI R3 $NIL ; Using NIL
  851. :progn_0
  852. LOAD32 R2 R0 8 ; Protect EXPS->CDR
  853. LOAD32 R0 R0 4 ; Using EXPS->CAR
  854. CALLI R15 @eval ; EVAL
  855. CMPSKIP.E R2 R3 ; If EXPS->CDR NOT NIL
  856. MOVE R0 R2 ; Use EXPS->CDR for next loop
  857. JUMP.Z R2 @progn_0 ; Keep looping if EXPS->CDR isn't NIL
  858. ;; Finally broke out of loop
  859. ;; Desired result is in R0
  860. POPR R3 R15 ; Restore R3
  861. POPR R2 R15 ; Restore R2
  862. POPR R1 R15 ; Restore R1
  863. RET R15
  864. ;; Apply
  865. ;; Receives a Procedure in R0 and Values in R1
  866. ;; Applies the procedure to the values and returns the result in R0
  867. :apply
  868. PUSHR R1 R15 ; Protect R1
  869. PUSHR R2 R15 ; Protect R2
  870. PUSHR R3 R15 ; Protect R3
  871. LOAD32 R3 R0 0 ; Get PROC->TYPE
  872. ;; Deal with PRIMOPs
  873. CMPSKIPI.E R3 64 ; If Not PRIMOP
  874. JUMP @apply_0 ; Check NEXT
  875. LOAD32 R3 R0 4 ; Using PROC->CAR
  876. MOVE R0 R1 ; Apply to VALs
  877. CALL R3 R15 ; Call PROC->CAR with VALs
  878. JUMP @apply_done ; Simply Pass the results
  879. ;; Deal with Procedures
  880. :apply_0
  881. CMPSKIPI.E R3 32 ; If Not PROC
  882. JUMP @apply_1 ; Abort with FIRE
  883. MOVE R2 R1 ; Protect VALUE and put in future correct place
  884. MOVE R3 R0 ; Protect PROC
  885. LOAD32 R0 R3 12 ; Get PROC->ENV
  886. LOAD32 R1 R0 8 ; Get PROC->ENV->CDR
  887. LOAD32 R0 R0 4 ; Get PROC->ENV->CAR
  888. CALLI R15 @make_cons ; ENV = MAKE_CONS(PROC->ENV->CAR, PROC->ENV->CDR)
  889. LOAD32 R1 R3 4 ; Get PROC->CAR
  890. CALLI R15 @multiple_extend ; R0 = MULTIPLE_EXTEND(ENV, PROC->CAR, VALS)
  891. MOVE R1 R0 ; Put Extended_Env in the right place
  892. LOAD32 R0 R3 8 ; Get PROC->CDR
  893. CALLI R15 @progn ; PROGN(PROC->CDR, R0)
  894. JUMP @apply_done ; Simply Pass the results
  895. ;; Deal with unknown shit
  896. :apply_1
  897. LOADUI R0 $apply_error ; Using designated Error Message
  898. FALSE R1 ; Using TTY
  899. CALLI R15 @Print_String ; Write Message
  900. HALT ; And bring the FIRE
  901. :apply_error
  902. "Bad argument to apply"
  903. ;; Clean up and return
  904. :apply_done
  905. POPR R3 R15 ; Restore R3
  906. POPR R2 R15 ; Restore R2
  907. POPR R1 R15 ; Restore R1
  908. RET R15
  909. ;; evcond
  910. ;; Receives an Expression in R0 and an Environment in R1
  911. ;; Walks down conditions until true one is found and return
  912. ;; Desired expression's result in R0
  913. ;; if none of the conditions are true, and the result of
  914. ;; the COND is undefined
  915. :evcond
  916. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  917. RET R15 ; Just get the Hell out
  918. PUSHR R1 R15 ; Protect R1
  919. PUSHR R2 R15 ; Protect R2
  920. PUSHR R3 R15 ; Protect R3
  921. PUSHR R4 R15 ; Protect R4
  922. LOADUI R4 $TEE ; Using TEE
  923. ;; Truth Evaluation
  924. :evcond_0
  925. LOAD32 R3 R0 8 ; Protect EXP->CDR
  926. LOAD32 R2 R0 4 ; Protect EXP->CAR
  927. LOAD32 R0 R2 4 ; Using EXP->CAR->CAR
  928. CALLI R15 @eval ; EVAL
  929. CMPJUMPI.E R0 R4 @evcond_1 ; Its true !
  930. MOVE R0 R3 ; Using EXP->CDR
  931. CALLI R15 @evcond ; Recurse
  932. JUMP @evcond_done ; Bail with just NIL
  933. ;; Expression Evaluation
  934. :evcond_1
  935. LOAD32 R0 R2 8 ; Get EXP->CAR->CDR
  936. LOAD32 R0 R0 4 ; Using EXP->CAR->CDR->CAR
  937. CALLI R15 @eval ; EVAL
  938. ;; Clean up and return
  939. :evcond_done
  940. POPR R4 R15 ; Restore R4
  941. POPR R3 R15 ; Restore R3
  942. POPR R2 R15 ; Restore R2
  943. POPR R1 R15 ; Restore R1
  944. RET R15
  945. ;; eval
  946. ;; Receives an Expression in R0 and an Environment in R1
  947. ;; Evaluates the expression in the given environment and returns
  948. ;; The result in R0
  949. :eval
  950. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  951. RET R15 ; Just get the Hell out
  952. PUSHR R1 R15 ; Protect R1
  953. PUSHR R2 R15 ; Protect R2
  954. PUSHR R3 R15 ; Protect R3
  955. PUSHR R4 R15 ; Protect R4
  956. LOAD32 R4 R0 0 ; Get EXP->TYPE
  957. ;; Deal with special case of Integers
  958. CMPSKIPI.NE R4 4 ; If EXP->TYPE is Integer
  959. JUMP @eval_done ; Simply return what was given
  960. ;; Deal with special case of Symbols
  961. CMPSKIPI.E R4 8 ; If EXP->TYPE is NOT Symbol
  962. JUMP @eval_cons ; Move onto next Case
  963. CALLI R15 @process_sym ; process the symbol
  964. JUMP @eval_done ; Return it
  965. ;; Deal with special cases of CONS
  966. :eval_cons
  967. CMPSKIPI.E R4 16 ; If EXP->TYPE is NOT CONS
  968. JUMP @eval_proc ; Move onto next Case
  969. CALLI R15 @process_cons ; Deal with all CONS
  970. JUMP @eval_done ; Simply return the result
  971. :eval_proc
  972. CMPSKIPI.E R4 32 ; If EXP->TYPE is NOT PROC
  973. JUMP @eval_primop ; Move onto next Case
  974. JUMP @eval_done
  975. :eval_primop
  976. CMPSKIPI.E R4 64 ; If EXP->TYPE is NOT PRIMOP
  977. JUMP @eval_char ; Move onto next Case
  978. :eval_char
  979. CMPSKIPI.E R4 128 ; If EXP->TYPE is NOT CHAR
  980. JUMP @eval_string ; Move onto next Case
  981. JUMP @eval_done
  982. :eval_string
  983. CMPSKIPI.E R4 256 ; If EXP->TYPE is NOT STRING
  984. JUMP @eval_error ; Move onto next Case
  985. JUMP @eval_done
  986. :eval_error
  987. LOADUI R0 $eval_error_Message ; Use a specific message to aid debugging
  988. FALSE R1 ; Written to TTY
  989. CALLI R15 @Print_String ; Write NOW
  990. HALT
  991. :eval_error_Message
  992. "EVAL Received unknown Object"
  993. ;; Result must be in R0 by this point
  994. ;; Simply Clean up and return result in R0
  995. :eval_done
  996. POPR R4 R15 ; Restore R4
  997. POPR R3 R15 ; Restore R3
  998. POPR R2 R15 ; Restore R2
  999. POPR R1 R15 ; Restore R1
  1000. RET R15
  1001. ;; process_sym
  1002. ;; Receives Expression in R0 and an Environment in R1
  1003. ;; Returns symbol in R0
  1004. :process_sym
  1005. CALLI R15 @assoc ; ASSOC to get tmp
  1006. CMPSKIPI.NE R0 $NIL ; If NIL is returned
  1007. JUMP @process_bad_Symbol ; Burn with FIRE
  1008. LOAD32 R0 R0 8 ; Return tmp->CDR
  1009. RET R15
  1010. :process_bad_Symbol
  1011. LOADUI R0 $sym_unbound ; Using the designated Error message
  1012. FALSE R1 ; Using TTY
  1013. CALLI R15 @Print_String ; Written for the user
  1014. HALT ; Simply toss the rest into the fire
  1015. :sym_unbound
  1016. "Unbound symbol"
  1017. ;; process_if
  1018. ;; Receives Expression in R0 and an Environment in R1
  1019. ;; Returns the evaluation of the expression if true in R0
  1020. ;; Or the evaluation of the CDR of the expression
  1021. :process_if
  1022. PUSHR R2 R15 ; Protect R2
  1023. LOAD32 R2 R0 8 ; Protect EXP->CDR
  1024. LOAD32 R0 R2 4 ; Using EXP->CDR->CAR
  1025. CALLI R15 @eval ; Recurse to get truth
  1026. CMPSKIPI.NE R0 $NIL ; If Result was NOT NIL
  1027. LOAD32 R2 R2 8 ; Update to EXP->CDR->CDR
  1028. LOAD32 R0 R2 8 ; Get EXP->CDR->CDR
  1029. LOAD32 R0 R0 4 ; Using EXP->CDR->CDR->CAR
  1030. CALLI R15 @eval ; Recurse to get result
  1031. POPR R2 R15 ; Restore R2
  1032. RET R15
  1033. ;; process_setb
  1034. ;; Receives Expression in R0 and an Environment in R1
  1035. ;; Sets the desired variable to desired value/type
  1036. ;; Returns the value/type in R0
  1037. :process_setb
  1038. PUSHR R2 R15 ; Protect R2
  1039. LOAD32 R2 R0 8 ; Protect EXP->CDR
  1040. LOAD32 R0 R2 8 ; Get EXP->CDR->CDR
  1041. LOAD32 R0 R0 4 ; Using EXP->CDR->CDR->CAR
  1042. CALLI R15 @eval ; Recurse to get New value
  1043. SWAP R0 R2 ; Protect New Value
  1044. LOAD32 R0 R0 4 ; Using EXP->CDR->CAR
  1045. CALLI R15 @assoc ; Get the associated Symbol
  1046. STORE32 R2 R0 8 ; SET Pair->CDR to New Value
  1047. MOVE R0 R2 ; Using New Value
  1048. POPR R2 R15 ; Restore R2
  1049. RET R15
  1050. ;; process_let
  1051. ;; Receives Expression in R0 and an Environment in R1
  1052. ;; Creates lexical closure and evaluates inside of it
  1053. ;; Returns the value/type in R0
  1054. :process_let
  1055. PUSHR R1 R15 ; Protect R1
  1056. PUSHR R2 R15 ; Protect R2
  1057. PUSHR R3 R15 ; Protect R3
  1058. PUSHR R4 R15 ; Protect R4
  1059. PUSHR R5 R15 ; Protect R5
  1060. LOADUI R4 $NIL ; Get NIL
  1061. MOVE R3 R1 ; Get ENV out of the way
  1062. MOVE R2 R0 ; Protect EXP
  1063. LOAD32 R5 R2 8 ; Get EXP->CDR
  1064. LOAD32 R5 R5 4 ; LETS = EXP->CDR->CAR
  1065. :process_let_0
  1066. CMPJUMPI.E R5 R4 @process_let_1
  1067. LOAD32 R0 R5 4 ; Get LETS->CAR
  1068. LOAD32 R0 R0 8 ; Get LETS->CAR->CDR
  1069. LOAD32 R0 R0 4 ; Get LETS->CAR->CDR->CAR
  1070. COPY R1 R3 ; Using ENV
  1071. CALLI R15 @eval ; CELL = EVAL(LETS->CAR->CDR->CAR, ENV)
  1072. MOVE R1 R0 ; Put CELL in the right place
  1073. LOAD32 R0 R5 4 ; Get LETS->CAR
  1074. LOAD32 R0 R0 4 ; Get LETS->CAR->CAR
  1075. CALLI R15 @make_cons ; CELL = MAKE_CONS(LETS->CAR->CAR, CELL)
  1076. COPY R1 R3 ; Using ENV
  1077. CALLI R15 @make_cons ; CELL = MAKE_CONS(CELL, ENV)
  1078. MOVE R3 R0 ; ENV = CELL
  1079. LOAD32 R5 R5 8 ; LETS = LETS->CDR
  1080. JUMP @process_let_0 ; Iterate through bindings
  1081. :process_let_1
  1082. MOVE R1 R3 ; Using ENV
  1083. LOAD32 R0 R2 8 ; Get EXP->CDR
  1084. LOAD32 R0 R0 8 ; Using EXP->CDR->CDR
  1085. CALLI R15 @progn ; Process inside of Closure
  1086. ;; Cleanup
  1087. POPR R5 R15 ; Restore R5
  1088. POPR R4 R15 ; Restore R4
  1089. POPR R3 R15 ; Restore R3
  1090. POPR R2 R15 ; Restore R2
  1091. POPR R1 R15 ; Restore R1
  1092. RET R15
  1093. ;; process_cons
  1094. ;; Receives Expression in R0 and an Environment in R1
  1095. ;; Returns the evaluation of whatever special used or
  1096. ;; The application of the evaluation in R0
  1097. :process_cons
  1098. PUSHR R2 R15 ; Protect R2
  1099. PUSHR R3 R15 ; Protect R3
  1100. PUSHR R4 R15 ; Protect R4
  1101. LOAD32 R4 R0 4 ; Using EXP->CAR
  1102. LOADUI R3 $s_if ; Using s_if
  1103. CMPJUMPI.NE R4 R3 @process_cons_cond
  1104. CALLI R15 @process_if ; deal with special case of If statements
  1105. JUMP @process_cons_done ; Return it
  1106. :process_cons_cond
  1107. LOADUI R3 $s_cond ; Using s_cond
  1108. CMPJUMPI.NE R4 R3 @process_cons_begin
  1109. ;; Deal with special case of COND statements
  1110. LOAD32 R0 R0 8 ; Using EXP->CDR
  1111. CALLI R15 @evcond ; EVCOND
  1112. JUMP @process_cons_done ; Simply use it's result
  1113. :process_cons_begin
  1114. LOADUI R3 $s_begin ; Using s_begin
  1115. CMPJUMPI.NE R4 R3 @process_cons_lambda
  1116. ;; Deal with special case of BEGIN statements
  1117. LOAD32 R0 R0 8 ; Using EXP->CDR
  1118. CALLI R15 @progn ; PROGN
  1119. JUMP @process_cons_done ; Simply use it's result
  1120. :process_cons_lambda
  1121. LOADUI R3 $s_lambda ; Using s_lambda
  1122. CMPJUMPI.NE R4 R3 @process_cons_quote
  1123. ;; Deal with special case of lambda statements
  1124. MOVE R2 R1 ; Put ENV in the right place
  1125. LOAD32 R1 R0 8 ; Get EXP->CDR
  1126. LOAD32 R0 R1 4 ; Using EXP->CDR->CAR
  1127. LOAD32 R1 R1 8 ; Using EXP->CDR->CDR
  1128. CALLI R15 @make_proc ; MAKE_PROC
  1129. JUMP @process_cons_done ; Simply return its result
  1130. :process_cons_quote
  1131. LOADUI R3 $s_quote ; Using s_quote
  1132. CMPJUMPI.NE R4 R3 @process_cons_define
  1133. ;; Deal with special case of quote statements
  1134. LOAD32 R0 R0 8 ; Get EXP->CDR
  1135. LOAD32 R0 R0 4 ; Using EXP->CDR->CAR
  1136. JUMP @process_cons_done ; Simply use it as the result
  1137. :process_cons_define
  1138. LOADUI R3 $s_define ; Using s_define
  1139. CMPJUMPI.NE R4 R3 @process_cons_set
  1140. ;; Deal with special case of Define statements
  1141. LOAD32 R2 R0 8 ; Using EXP->CDR
  1142. LOAD32 R0 R2 8 ; Get EXP->CDR->CDR
  1143. LOAD32 R0 R0 4 ; Using EXP->CDR->CDR->CAR
  1144. CALLI R15 @eval ; Recurse to figure out what it is
  1145. SWAP R2 R1 ; Put Environment in the right place
  1146. SWAP R1 R0 ; Put Evaluation in the right place
  1147. LOAD32 R0 R0 4 ; Using EXP->CDR->CAR
  1148. CALLI R15 @extend_env ; EXTEND_ENV
  1149. JUMP @process_cons_done ; Simply use what was returned
  1150. :process_cons_set
  1151. LOADUI R3 $s_setb ; Using s_setb
  1152. CMPJUMPI.NE R4 R3 @process_cons_let
  1153. CALLI R15 @process_setb ; Deal with special case of SET statements
  1154. JUMP @process_cons_done ; Simply Return Result
  1155. :process_cons_let
  1156. LOADUI R3 $s_let ; Using s_let
  1157. CMPJUMPI.NE R4 R3 @process_cons_apply
  1158. CALLI R15 @process_let ; Deal with special case of LET statements
  1159. JUMP @process_cons_done ; Simply Return Result
  1160. :process_cons_apply
  1161. ;; Deal with the last option for a CONS, APPLY
  1162. LOAD32 R2 R0 4 ; Protect EXP->CAR
  1163. LOAD32 R0 R0 8 ; Using EXP->CDR
  1164. CALLI R15 @evlis ; EVLIS
  1165. SWAP R0 R2 ; Protect EVLIS result
  1166. CALLI R15 @eval ; Recurse to figure out what to APPLY
  1167. MOVE R1 R2 ; Put EVLIS result in right place
  1168. CALLI R15 @apply ; Apply what was found to the EVLIS result
  1169. :process_cons_done
  1170. POPR R4 R15 ; Restore R2
  1171. POPR R3 R15 ; Restore R2
  1172. POPR R2 R15 ; Restore R2
  1173. RET R15
  1174. ;; prim_apply
  1175. ;; Receives arglist in R0
  1176. ;; Returns result of applying ARGS->CAR to ARGS->CDR->CAR
  1177. :prim_apply_String
  1178. "apply"
  1179. :prim_apply
  1180. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1181. RET R15 ; Just get the Hell out
  1182. PUSHR R1 R15 ; Protect R1
  1183. LOAD32 R1 R0 8 ; Get ARGS->CDR
  1184. LOAD32 R1 R1 4 ; Get ARGS->CDR->CAR
  1185. LOAD32 R0 R0 4 ; Get ARGS->CAR
  1186. CALLI R15 @apply ; Use backing function
  1187. ;; Cleanup
  1188. POPR R1 R15 ; Restore R1
  1189. RET R15
  1190. ;; nullp
  1191. ;; Receives a CELL in R0
  1192. ;; Returns NIL if not NIL or TEE if NIL
  1193. :nullp_String
  1194. "null?"
  1195. :nullp
  1196. PUSHR R1 R15 ; Protect R1
  1197. LOAD32 R0 R0 4 ; Get ARGS->CAR
  1198. LOADUI R1 $NIL ; Using NIL
  1199. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1200. LOADUI R1 $TEE ; Return TEE
  1201. MOVE R0 R1 ; Put result in correct register
  1202. POPR R1 R15 ; Restore R1
  1203. RET R15
  1204. ;; prim_sum
  1205. ;; Receives a list in R0
  1206. ;; Adds all values and returns a Cell with result in R0
  1207. :prim_sum_String
  1208. "+"
  1209. :prim_sum
  1210. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1211. RET R15 ; Just get the Hell out
  1212. PUSHR R1 R15 ; Protect R1
  1213. PUSHR R2 R15 ; Protect R2
  1214. PUSHR R3 R15 ; Protect R3
  1215. LOADUI R3 $NIL ; Using NIL
  1216. FALSE R2 ; Initialize our SUM at 0
  1217. :prim_sum_0
  1218. CMPJUMPI.E R0 R3 @prim_sum_done
  1219. LOAD32 R1 R0 4 ; Get ARGS->CAR
  1220. LOAD32 R1 R1 4 ; Get ARGS->CAR->CAR
  1221. LOAD32 R0 R0 8 ; Set ARGS to ARGS->CDR
  1222. ADD R2 R2 R1 ; sum = sum + value
  1223. JUMP @prim_sum_0 ; Go to next list item
  1224. :prim_sum_done
  1225. MOVE R0 R2 ; Put SUM in right spot
  1226. CALLI R15 @make_int ; Get our Cell
  1227. POPR R3 R15 ; Restore R3
  1228. POPR R2 R15 ; Restore R2
  1229. POPR R1 R15 ; Restore R1
  1230. RET R15
  1231. ;; prim_sub
  1232. ;; Receives a list in R0
  1233. ;; Subtracts all of the values and returns a Cell with the result in R0
  1234. :prim_sub_String
  1235. "-"
  1236. :prim_sub
  1237. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1238. RET R15 ; Just get the Hell out
  1239. PUSHR R1 R15 ; Protect R1
  1240. PUSHR R2 R15 ; Protect R2
  1241. PUSHR R3 R15 ; Protect R3
  1242. LOADUI R3 $NIL ; Using NIL
  1243. LOAD32 R2 R0 4 ; Get ARGS->CAR
  1244. LOAD32 R2 R2 4 ; Using ARGS->CAR->CAR as starting SUM
  1245. LOAD32 R0 R0 8 ; Using ARGS->CDR as args
  1246. :prim_sub_0
  1247. CMPJUMPI.E R0 R3 @prim_sub_done
  1248. LOAD32 R1 R0 4 ; Get ARGS->CAR
  1249. LOAD32 R1 R1 4 ; Get ARGS->CAR->CAR
  1250. LOAD32 R0 R0 8 ; Set ARGS to ARGS->CDR
  1251. SUB R2 R2 R1 ; sum = sum - value
  1252. JUMP @prim_sub_0 ; Go to next list item
  1253. :prim_sub_done
  1254. MOVE R0 R2 ; Put SUM in right spot
  1255. CALLI R15 @make_int ; Get our Cell
  1256. POPR R3 R15 ; Restore R3
  1257. POPR R2 R15 ; Restore R2
  1258. POPR R1 R15 ; Restore R1
  1259. RET R15
  1260. ;; prim_prod
  1261. ;; Receives a list in R0
  1262. ;; Multiplies all of the values and returns a Cell with the result in R0
  1263. :prim_prod_String
  1264. "*"
  1265. :prim_prod
  1266. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1267. RET R15 ; Just get the Hell out
  1268. PUSHR R1 R15 ; Protect R1
  1269. PUSHR R2 R15 ; Protect R2
  1270. PUSHR R3 R15 ; Protect R3
  1271. LOADUI R3 $NIL ; Using NIL
  1272. LOADUI R2 1 ; Initialize our Product at 1
  1273. :prim_prod_0
  1274. CMPJUMPI.E R0 R3 @prim_prod_done
  1275. LOAD32 R1 R0 4 ; Get ARGS->CAR
  1276. LOAD32 R1 R1 4 ; Get ARGS->CAR->CAR
  1277. LOAD32 R0 R0 8 ; Set ARGS to ARGS->CDR
  1278. MUL R2 R2 R1 ; sum = sum + value
  1279. JUMP @prim_prod_0 ; Go to next list item
  1280. :prim_prod_done
  1281. MOVE R0 R2 ; Put SUM in right spot
  1282. CALLI R15 @make_int ; Get our Cell
  1283. POPR R3 R15 ; Restore R3
  1284. POPR R2 R15 ; Restore R2
  1285. POPR R1 R15 ; Restore R1
  1286. RET R15
  1287. ;; prim_div
  1288. ;; Receives a list in R0
  1289. ;; Divides all of the values and returns a Cell with the result in R0
  1290. :prim_div_String
  1291. "/"
  1292. :prim_div
  1293. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1294. RET R15 ; Just get the Hell out
  1295. PUSHR R1 R15 ; Protect R1
  1296. PUSHR R2 R15 ; Protect R2
  1297. PUSHR R3 R15 ; Protect R3
  1298. LOADUI R3 $NIL ; Using NIL
  1299. LOAD32 R2 R0 4 ; Get ARGS->CAR
  1300. LOAD32 R2 R2 4 ; Using ARGS->CAR->CAR as starting SUM
  1301. LOAD32 R0 R0 8 ; Using ARGS->CDR as args
  1302. :prim_div_0
  1303. CMPJUMPI.E R0 R3 @prim_div_done
  1304. LOAD32 R1 R0 4 ; Get ARGS->CAR
  1305. LOAD32 R1 R1 4 ; Get ARGS->CAR->CAR
  1306. LOAD32 R0 R0 8 ; Set ARGS to ARGS->CDR
  1307. DIV R2 R2 R1 ; sum = sum - value
  1308. JUMP @prim_div_0 ; Go to next list item
  1309. :prim_div_done
  1310. MOVE R0 R2 ; Put result in right spot
  1311. CALLI R15 @make_int ; Get our Cell
  1312. POPR R3 R15 ; Restore R3
  1313. POPR R2 R15 ; Restore R2
  1314. POPR R1 R15 ; Restore R1
  1315. RET R15
  1316. ;; prim_mod
  1317. ;; Receives a list in R0
  1318. ;; Remainders all of the values and returns a Cell with the result in R0
  1319. :prim_mod_String
  1320. "mod"
  1321. :prim_mod
  1322. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1323. RET R15 ; Just get the Hell out
  1324. PUSHR R1 R15 ; Protect R1
  1325. PUSHR R2 R15 ; Protect R2
  1326. PUSHR R3 R15 ; Protect R3
  1327. LOADUI R3 $NIL ; Using NIL
  1328. LOAD32 R2 R0 4 ; Get ARGS->CAR
  1329. LOAD32 R2 R2 4 ; Using ARGS->CAR->CAR as starting SUM
  1330. LOAD32 R0 R0 8 ; Using ARGS->CDR as args
  1331. :prim_mod_0
  1332. CMPJUMPI.E R0 R3 @prim_mod_done
  1333. LOAD32 R1 R0 4 ; Get ARGS->CAR
  1334. LOAD32 R1 R1 4 ; Get ARGS->CAR->CAR
  1335. LOAD32 R0 R0 8 ; Set ARGS to ARGS->CDR
  1336. MOD R2 R2 R1 ; sum = sum - value
  1337. JUMP @prim_mod_0 ; Go to next list item
  1338. :prim_mod_done
  1339. MOVE R0 R2 ; Put result in right spot
  1340. CALLI R15 @make_int ; Get our Cell
  1341. POPR R3 R15 ; Restore R3
  1342. POPR R2 R15 ; Restore R2
  1343. POPR R1 R15 ; Restore R1
  1344. RET R15
  1345. ;; prim_and
  1346. ;; Receives a list in R0
  1347. ;; ANDs all of the values and returns a Cell with the result in R0
  1348. :prim_and_String
  1349. "and"
  1350. :prim_and
  1351. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1352. RET R15 ; Just get the Hell out
  1353. PUSHR R1 R15 ; Protect R1
  1354. PUSHR R2 R15 ; Protect R2
  1355. PUSHR R3 R15 ; Protect R3
  1356. PUSHR R4 R15 ; Protect R4
  1357. LOADUI R4 $TEE ; Using TEE
  1358. LOADUI R3 $NIL ; Using NIL
  1359. :prim_and_0
  1360. CMPJUMPI.E R0 R3 @prim_and_done
  1361. LOAD32 R2 R0 4 ; Get ARGS->CAR
  1362. CMPJUMPI.NE R2 R4 @prim_and_1
  1363. LOAD32 R0 R0 8 ; Get ARGS->CDR
  1364. JUMP @prim_and_0 ; Go to next list item
  1365. :prim_and_1
  1366. COPY R2 R3 ; Return NIL
  1367. :prim_and_done
  1368. MOVE R0 R2 ; Put result in correct location
  1369. POPR R4 R15 ; Restore R4
  1370. POPR R3 R15 ; Restore R3
  1371. POPR R2 R15 ; Restore R2
  1372. POPR R1 R15 ; Restore R1
  1373. RET R15
  1374. ;; prim_or
  1375. ;; Receives a list in R0
  1376. ;; ORs all of the values and returns a Cell with the result in R0
  1377. :prim_or_String
  1378. "or"
  1379. :prim_or
  1380. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1381. RET R15 ; Just get the Hell out
  1382. PUSHR R1 R15 ; Protect R1
  1383. PUSHR R2 R15 ; Protect R2
  1384. PUSHR R3 R15 ; Protect R3
  1385. PUSHR R4 R15 ; Protect R4
  1386. LOADUI R4 $TEE ; Using TEE
  1387. LOADUI R3 $NIL ; Using NIL
  1388. :prim_or_0
  1389. CMPJUMPI.E R0 R3 @prim_or_1
  1390. LOAD32 R2 R0 4 ; Get ARGS->CAR
  1391. CMPJUMPI.E R2 R4 @prim_or_done
  1392. LOAD32 R0 R0 8 ; Get ARGS->CDR
  1393. JUMP @prim_or_0 ; Go to next list item
  1394. :prim_or_1
  1395. COPY R2 R3 ; Couldn't find a true
  1396. :prim_or_done
  1397. MOVE R0 R2 ; Put result in correct location
  1398. POPR R4 R15 ; Restore R4
  1399. POPR R3 R15 ; Restore R3
  1400. POPR R2 R15 ; Restore R2
  1401. POPR R1 R15 ; Restore R1
  1402. RET R15
  1403. ;; prim_not
  1404. ;; Receives a list in R0
  1405. ;; NOTs first of the values and returns a Cell with the result in R0
  1406. :prim_not_String
  1407. "not"
  1408. :prim_not
  1409. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1410. RET R15 ; Just get the Hell out
  1411. LOAD32 R0 R0 4 ; Get ARGS->CAR
  1412. CMPSKIPI.E R0 $TEE ; If not TEE
  1413. JUMP @prim_not_0 ; Return TEE
  1414. LOADUI R0 $NIL ; Otherwise return NIL
  1415. JUMP @prim_not_done ; Return our NIL
  1416. :prim_not_0
  1417. LOADUI R0 $TEE ; Make TEE
  1418. :prim_not_done
  1419. RET R15
  1420. ;; prim_numgt
  1421. ;; Receives a list in R0
  1422. ;; Compares values and returns a Cell with the result in R0
  1423. :prim_numgt_String
  1424. ">"
  1425. :prim_numgt
  1426. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1427. RET R15 ; Just get the Hell out
  1428. PUSHR R1 R15 ; Protect R1
  1429. PUSHR R2 R15 ; Protect R2
  1430. PUSHR R3 R15 ; Protect R3
  1431. LOADUI R3 $NIL ; Using NIL
  1432. LOAD32 R2 R0 4 ; Get ARGS->CAR
  1433. LOAD32 R2 R2 4 ; Using ARGS->CAR->CAR as starting Value
  1434. LOAD32 R0 R0 8 ; Using ARGS->CDR as args
  1435. :prim_numgt_0
  1436. CMPJUMPI.E R0 R3 @prim_numgt_1
  1437. LOAD32 R1 R0 4 ; Get ARGS->CAR
  1438. LOAD32 R1 R1 4 ; Get ARGS->CAR->CAR
  1439. LOAD32 R0 R0 8 ; Set ARGS to ARGS->CDR
  1440. CMPJUMPI.LE R2 R1 @prim_numgt_2
  1441. MOVE R2 R1 ; Prepare for next loop
  1442. JUMP @prim_numgt_0 ; Go to next list item
  1443. :prim_numgt_1
  1444. LOADUI R0 $TEE ; Return TEE
  1445. JUMP @prim_numgt_done ; Be done
  1446. :prim_numgt_2
  1447. LOADUI R0 $NIL ; Return NIL
  1448. :prim_numgt_done
  1449. POPR R3 R15 ; Restore R3
  1450. POPR R2 R15 ; Restore R2
  1451. POPR R1 R15 ; Restore R1
  1452. RET R15
  1453. ;; prim_numge
  1454. ;; Receives a list in R0
  1455. ;; Compares values and returns a Cell with the result in R0
  1456. :prim_numge_String
  1457. ">="
  1458. :prim_numge
  1459. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1460. RET R15 ; Just get the Hell out
  1461. PUSHR R1 R15 ; Protect R1
  1462. PUSHR R2 R15 ; Protect R2
  1463. PUSHR R3 R15 ; Protect R3
  1464. LOADUI R3 $NIL ; Using NIL
  1465. LOAD32 R2 R0 4 ; Get ARGS->CAR
  1466. LOAD32 R2 R2 4 ; Using ARGS->CAR->CAR as starting Value
  1467. LOAD32 R0 R0 8 ; Using ARGS->CDR as args
  1468. :prim_numge_0
  1469. CMPJUMPI.E R0 R3 @prim_numge_1
  1470. LOAD32 R1 R0 4 ; Get ARGS->CAR
  1471. LOAD32 R1 R1 4 ; Get ARGS->CAR->CAR
  1472. LOAD32 R0 R0 8 ; Set ARGS to ARGS->CDR
  1473. CMPJUMPI.L R2 R1 @prim_numge_2
  1474. MOVE R2 R1 ; Prepare for next loop
  1475. JUMP @prim_numge_0 ; Go to next list item
  1476. :prim_numge_1
  1477. LOADUI R0 $TEE ; Return TEE
  1478. JUMP @prim_numge_done ; Be done
  1479. :prim_numge_2
  1480. LOADUI R0 $NIL ; Return NIL
  1481. :prim_numge_done
  1482. POPR R3 R15 ; Restore R3
  1483. POPR R2 R15 ; Restore R2
  1484. POPR R1 R15 ; Restore R1
  1485. RET R15
  1486. ;; prim_numeq
  1487. ;; Receives a list in R0
  1488. ;; Compares values and returns a Cell with the result in R0
  1489. :prim_numeq_String
  1490. "="
  1491. :prim_numeq
  1492. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1493. RET R15 ; Just get the Hell out
  1494. PUSHR R1 R15 ; Protect R1
  1495. PUSHR R2 R15 ; Protect R2
  1496. PUSHR R3 R15 ; Protect R3
  1497. LOADUI R3 $NIL ; Using NIL
  1498. LOAD32 R2 R0 4 ; Get ARGS->CAR
  1499. LOAD32 R2 R2 4 ; Using ARGS->CAR->CAR as starting Value
  1500. LOAD32 R0 R0 8 ; Using ARGS->CDR as args
  1501. :prim_numeq_0
  1502. CMPJUMPI.E R0 R3 @prim_numeq_1
  1503. LOAD32 R1 R0 4 ; Get ARGS->CAR
  1504. LOAD32 R1 R1 4 ; Get ARGS->CAR->CAR
  1505. LOAD32 R0 R0 8 ; Set ARGS to ARGS->CDR
  1506. CMPJUMPI.NE R2 R1 @prim_numeq_2
  1507. MOVE R2 R1 ; Prepare for next loop
  1508. JUMP @prim_numeq_0 ; Go to next list item
  1509. :prim_numeq_1
  1510. LOADUI R0 $TEE ; Return TEE
  1511. JUMP @prim_numge_done ; Be done
  1512. :prim_numeq_2
  1513. LOADUI R0 $NIL ; Return NIL
  1514. :prim_numeq_done
  1515. POPR R3 R15 ; Restore R3
  1516. POPR R2 R15 ; Restore R2
  1517. POPR R1 R15 ; Restore R1
  1518. RET R15
  1519. ;; prim_numle
  1520. ;; Receives a list in R0
  1521. ;; Compares values and returns a Cell with the result in R0
  1522. :prim_numle_String
  1523. "<="
  1524. :prim_numle
  1525. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1526. RET R15 ; Just get the Hell out
  1527. PUSHR R1 R15 ; Protect R1
  1528. PUSHR R2 R15 ; Protect R2
  1529. PUSHR R3 R15 ; Protect R3
  1530. LOADUI R3 $NIL ; Using NIL
  1531. LOAD32 R2 R0 4 ; Get ARGS->CAR
  1532. LOAD32 R2 R2 4 ; Using ARGS->CAR->CAR as starting Value
  1533. LOAD32 R0 R0 8 ; Using ARGS->CDR as args
  1534. :prim_numle_0
  1535. CMPJUMPI.E R0 R3 @prim_numle_1
  1536. LOAD32 R1 R0 4 ; Get ARGS->CAR
  1537. LOAD32 R1 R1 4 ; Get ARGS->CAR->CAR
  1538. LOAD32 R0 R0 8 ; Set ARGS to ARGS->CDR
  1539. CMPJUMPI.G R2 R1 @prim_numle_2
  1540. MOVE R2 R1 ; Prepare for next loop
  1541. JUMP @prim_numle_0 ; Go to next list item
  1542. :prim_numle_1
  1543. LOADUI R0 $TEE ; Return TEE
  1544. JUMP @prim_numle_done ; Be done
  1545. :prim_numle_2
  1546. LOADUI R0 $NIL ; Return NIL
  1547. :prim_numle_done
  1548. POPR R3 R15 ; Restore R3
  1549. POPR R2 R15 ; Restore R2
  1550. POPR R1 R15 ; Restore R1
  1551. RET R15
  1552. ;; prim_numlt
  1553. ;; Receives a list in R0
  1554. ;; Compares values and returns a Cell with the result in R0
  1555. :prim_numlt_String
  1556. "<"
  1557. :prim_numlt
  1558. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1559. RET R15 ; Just get the Hell out
  1560. PUSHR R1 R15 ; Protect R1
  1561. PUSHR R2 R15 ; Protect R2
  1562. PUSHR R3 R15 ; Protect R3
  1563. LOADUI R3 $NIL ; Using NIL
  1564. LOAD32 R2 R0 4 ; Get ARGS->CAR
  1565. LOAD32 R2 R2 4 ; Using ARGS->CAR->CAR as starting Value
  1566. LOAD32 R0 R0 8 ; Using ARGS->CDR as args
  1567. :prim_numlt_0
  1568. CMPJUMPI.E R0 R3 @prim_numlt_1
  1569. LOAD32 R1 R0 4 ; Get ARGS->CAR
  1570. LOAD32 R1 R1 4 ; Get ARGS->CAR->CAR
  1571. LOAD32 R0 R0 8 ; Set ARGS to ARGS->CDR
  1572. CMPJUMPI.GE R2 R1 @prim_numlt_2
  1573. MOVE R2 R1 ; Prepare for next loop
  1574. JUMP @prim_numlt_0 ; Go to next list item
  1575. :prim_numlt_1
  1576. LOADUI R0 $TEE ; Return TEE
  1577. JUMP @prim_numlt_done ; Be done
  1578. :prim_numlt_2
  1579. LOADUI R0 $NIL ; Return NIL
  1580. :prim_numlt_done
  1581. POPR R3 R15 ; Restore R3
  1582. POPR R2 R15 ; Restore R2
  1583. POPR R1 R15 ; Restore R1
  1584. RET R15
  1585. ;; prim_listp
  1586. ;; Receives a list in R0
  1587. ;; Compares values and returns a Cell with the result in R0
  1588. :prim_listp_String
  1589. "list?"
  1590. :prim_listp
  1591. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1592. RET R15 ; Just get the Hell out
  1593. LOAD32 R0 R0 4 ; Get ARGS->CAR
  1594. LOAD32 R0 R0 0 ; Get ARGS->CAR->TYPE
  1595. CMPSKIPI.NE R0 16 ; If CONS
  1596. JUMP @prim_listp_0 ; Return TEE
  1597. LOADUI R0 $NIL ; Otherwise return NIL
  1598. JUMP @prim_listp_done ; Return our NIL
  1599. :prim_listp_0
  1600. LOADUI R0 $TEE ; Make TEE
  1601. :prim_listp_done
  1602. RET R15
  1603. ;; prim_charp
  1604. ;; Receives argslist in R0
  1605. ;; Returns #t if CHAR else NIL
  1606. :prim_charp_String
  1607. "char?"
  1608. :prim_charp
  1609. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1610. RET R15 ; Just get the Hell out
  1611. LOAD32 R0 R0 4 ; Get ARGS->CAR
  1612. LOAD32 R0 R0 0 ; Get ARGS->CAR->TYPE
  1613. CMPSKIPI.NE R0 128 ; If CHAR
  1614. JUMP @prim_charp_0 ; Return TEE
  1615. LOADUI R0 $NIL ; Otherwise return NIL
  1616. JUMP @prim_charp_done
  1617. :prim_charp_0
  1618. LOADUI R0 $TEE ; Make TEE
  1619. :prim_charp_done
  1620. RET R15
  1621. ;; prim_numberp
  1622. ;; Receives argslist in R0
  1623. ;; Returns #t if NUMBER else NIL
  1624. :prim_numberp_String
  1625. "number?"
  1626. :prim_numberp
  1627. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1628. RET R15 ; Just get the Hell out
  1629. LOAD32 R0 R0 4 ; Get ARGS->CAR
  1630. LOAD32 R0 R0 0 ; Get ARGS->CAR->TYPE
  1631. CMPSKIPI.NE R0 4 ; If NUMBER
  1632. JUMP @prim_numberp_0 ; Return TEE
  1633. LOADUI R0 $NIL ; Otherwise return NIL
  1634. JUMP @prim_numberp_done
  1635. :prim_numberp_0
  1636. LOADUI R0 $TEE ; Make TEE
  1637. :prim_numberp_done
  1638. RET R15
  1639. ;; prim_symbolp
  1640. ;; Receives argslist in R0
  1641. ;; Returns #t if SYMBOL else NIL
  1642. :prim_symbolp_String
  1643. "symbol?"
  1644. :prim_symbolp
  1645. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1646. RET R15 ; Just get the Hell out
  1647. LOAD32 R0 R0 4 ; Get ARGS->CAR
  1648. LOAD32 R0 R0 0 ; Get ARGS->CAR->TYPE
  1649. CMPSKIPI.NE R0 8 ; If SYMBOL
  1650. JUMP @prim_symbolp_0 ; Return TEE
  1651. LOADUI R0 $NIL ; Otherwise return NIL
  1652. JUMP @prim_symbolp_done
  1653. :prim_symbolp_0
  1654. LOADUI R0 $TEE ; Make TEE
  1655. :prim_symbolp_done
  1656. RET R15
  1657. ;; prim_stringp
  1658. ;; Receives argslist in R0
  1659. ;; Returns #t if CHAR else NIL
  1660. :prim_stringp_String
  1661. "string?"
  1662. :prim_stringp
  1663. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1664. RET R15 ; Just get the Hell out
  1665. LOAD32 R0 R0 4 ; Get ARGS->CAR
  1666. LOAD32 R0 R0 0 ; Get ARGS->CAR->TYPE
  1667. CMPSKIPI.NE R0 256 ; If CHAR
  1668. JUMP @prim_stringp_0 ; Return TEE
  1669. LOADUI R0 $NIL ; Otherwise return NIL
  1670. JUMP @prim_stringp_done
  1671. :prim_stringp_0
  1672. LOADUI R0 $TEE ; Make TEE
  1673. :prim_stringp_done
  1674. RET R15
  1675. ;; prim_output
  1676. ;; Receives argslist in R0
  1677. ;; Outputs to whatever is specified in R12 and returns TEE
  1678. :prim_output
  1679. PUSHR R1 R15 ; Protect R1
  1680. PUSHR R2 R15 ; Protect R2
  1681. PUSHR R3 R15 ; Protect R3
  1682. PUSHR R4 R15 ; Protect R4
  1683. LOADUI R4 $NIL ; Using NIL
  1684. COPY R1 R12 ; Set to use desired output
  1685. :prim_output_0
  1686. CMPJUMPI.E R0 R4 @prim_output_done
  1687. LOAD32 R3 R0 4 ; Get ARGS->CAR
  1688. LOAD32 R2 R3 0 ; Get ARGS->CAR->TYPE
  1689. SWAP R0 R3 ; Protect ARGS
  1690. CMPSKIPI.NE R2 4 ; If INT
  1691. CALLI R15 @prim_output_INT ; Print the value
  1692. CMPSKIPI.NE R2 8 ; If SYM
  1693. CALLI R15 @prim_output_SYM ; Print the string
  1694. CMPSKIPI.NE R2 16 ; If CONS
  1695. CALLI R15 @prim_output ; Recurse
  1696. CMPSKIPI.NE R2 128 ; If CHAR
  1697. CALLI R15 @prim_output_CHAR ; Just print the last Char
  1698. LOAD32 R0 R3 8 ; Get ARGS->CDR
  1699. JUMP @prim_output_0 ; Loop until we hit NIL
  1700. :prim_output_done
  1701. POPR R4 R15 ; Restore R4
  1702. POPR R3 R15 ; Restore R3
  1703. POPR R2 R15 ; Restore R2
  1704. POPR R1 R15 ; Restore R1
  1705. LOADUI R0 $TEE ; Return TEE
  1706. RET R15
  1707. ;; prim_output_INT
  1708. ;; Receives an INT CELL in R0 and desired Output in R1
  1709. ;; Outputs value and returns
  1710. :prim_output_INT
  1711. PUSHR R0 R15 ; Protect R0
  1712. PUSHR R1 R15 ; Protect R1
  1713. LOAD32 R0 R0 4 ; Get ARG->CAR
  1714. CALLI R15 @Write_Int ; Write it
  1715. POPR R1 R15 ; Restore R1
  1716. POPR R0 R15 ; Restore R0
  1717. RET R15
  1718. ;; prim_output_SYM
  1719. ;; Receives a SYM CELL in R0 and desired Output in R1
  1720. ;; Outputs string and returns
  1721. :prim_output_SYM
  1722. PUSHR R0 R15 ; Protect R0
  1723. PUSHR R1 R15 ; Protect R1
  1724. LOAD32 R0 R0 4 ; Get ARG->CAR
  1725. CALLI R15 @Print_String ; Print the string
  1726. POPR R1 R15 ; Restore R1
  1727. POPR R0 R15 ; Restore R0
  1728. RET R15
  1729. ;; prim_output_CHAR
  1730. ;; Receives an CHAR CELL in R0 and desired Output in R1
  1731. ;; Outputs Last CHAR and returns
  1732. :prim_output_CHAR
  1733. PUSHR R0 R15 ; Protect R0
  1734. PUSHR R1 R15 ; Protect R1
  1735. LOADU8 R0 R0 7 ; Get ARG->CAR [bottom 8 bits]
  1736. FPUTC ; Display desired CHAR
  1737. POPR R1 R15 ; Restore R1
  1738. POPR R0 R15 ; Restore R0
  1739. RET R15
  1740. ;; prim_stringeq
  1741. ;; Receives a list in R0
  1742. ;; Compares strings and returns a Cell with the result in R0
  1743. :prim_stringeq_String
  1744. "string=?"
  1745. :prim_stringeq
  1746. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1747. RET R15 ; Just get the Hell out
  1748. PUSHR R1 R15 ; Protect R1
  1749. PUSHR R2 R15 ; Protect R2
  1750. PUSHR R3 R15 ; Protect R3
  1751. PUSHR R4 R15 ; Protect R4
  1752. LOADUI R3 $NIL ; Using NIL
  1753. LOAD32 R1 R0 4 ; Get ARGS->CAR
  1754. LOAD32 R4 R1 4 ; Using ARGS->CAR->CAR as TEMP
  1755. LOAD32 R2 R0 8 ; Using ARGS->CDR as args
  1756. :prim_stringeq_0
  1757. CMPJUMPI.E R2 R3 @prim_stringeq_1
  1758. LOAD32 R0 R2 4 ; Get ARGS->CAR
  1759. LOAD32 R0 R0 4 ; Get ARGS->CAR->CAR
  1760. COPY R1 R4 ; Restore TEMP for string comparison
  1761. CALLI R15 @strcmp ; Compare the strings
  1762. JUMP.NE R0 @prim_stringeq_2 ; Stop if not equal
  1763. LOAD32 R2 R2 8 ; Set ARGS to ARGS->CDR
  1764. JUMP @prim_stringeq_0 ; Go to next list item
  1765. :prim_stringeq_1
  1766. LOADUI R0 $TEE ; Return TEE
  1767. JUMP @prim_stringeq_done ; Be done
  1768. :prim_stringeq_2
  1769. LOADUI R0 $NIL ; Return NIL
  1770. :prim_stringeq_done
  1771. POPR R4 R15 ; Restore R4
  1772. POPR R3 R15 ; Restore R3
  1773. POPR R2 R15 ; Restore R2
  1774. POPR R1 R15 ; Restore R1
  1775. RET R15
  1776. ;; prim_display
  1777. ;; Receives argslist in R0
  1778. ;; Outputs to TTY R12 and returns TEE
  1779. :prim_display_String
  1780. "display"
  1781. :prim_display
  1782. CALLI R15 @prim_output
  1783. RET R15
  1784. ;; prim_write
  1785. ;; Receives argslist in R0
  1786. ;; Write to Tape_02 and returns TEE
  1787. :prim_write_String
  1788. "write"
  1789. :prim_write
  1790. LOADUI R12 0x1101 ; Write to Tape_02
  1791. CALLI R15 @prim_output ; Use shared prim_output
  1792. FALSE R12 ; Revert to TTY
  1793. RET R15
  1794. ;; prim_freecell
  1795. ;; Receives either NIL or a list in R0
  1796. ;; If NIL displays header, otherwise just returns number of free cells in R0
  1797. :prim_freecell_String
  1798. "free_mem"
  1799. :prim_freecell
  1800. PUSHR R1 R15 ; Protect R1
  1801. CMPSKIPI.E R0 $NIL ; If NOT NIL
  1802. JUMP @prim_freecell_0 ; Skip message
  1803. LOADUI R0 $prim_freecell_Message
  1804. COPY R1 R12 ; Using Selected Output
  1805. CALLI R15 @Print_String ; Display our header
  1806. :prim_freecell_0
  1807. CALLI R15 @cells_remaining ; Get number of remaining Cells
  1808. CALLI R15 @make_int ; Convert integer in R0 to a Cell
  1809. :prim_freecell_done
  1810. POPR R1 R15 ; Restore R1
  1811. RET R15
  1812. :prim_freecell_Message
  1813. "Remaining Cells: "
  1814. ;; prim_integer_to_char
  1815. ;; Receives a list in R0
  1816. ;; Converts INT to CHAR
  1817. :prim_integer_to_char_String
  1818. "integer->char"
  1819. :prim_integer_to_char
  1820. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1821. RET R15 ; Just get the Hell out
  1822. PUSHR R1 R15 ; Protect R1
  1823. PUSHR R2 R15 ; Protect R2
  1824. LOADUI R2 128 ; Using Type CHAR
  1825. LOAD32 R0 R0 4 ; Get ARGS->CAR
  1826. LOAD32 R1 R0 0 ; Get ARGS->CAR->TYPE
  1827. CMPSKIPI.NE R1 4 ; If Type INT
  1828. STORE32 R2 R0 0 ; Update ARGS->CAR->TYPE
  1829. POPR R2 R15 ; Restore R2
  1830. POPR R1 R15 ; Restore R1
  1831. RET R15
  1832. ;; prim_char_to_integer
  1833. ;; Receives a list in R0
  1834. ;; Converts CHAR to INT
  1835. :prim_char_to_integer_String
  1836. "char->integer"
  1837. :prim_char_to_integer
  1838. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1839. RET R15 ; Just get the Hell out
  1840. PUSHR R1 R15 ; Protect R1
  1841. PUSHR R2 R15 ; Protect R2
  1842. LOADUI R2 4 ; Using Type INT
  1843. LOAD32 R0 R0 4 ; Get ARGS->CAR
  1844. LOAD32 R1 R0 0 ; Get ARGS->CAR->TYPE
  1845. CMPSKIPI.NE R1 128 ; If Type CHAR
  1846. STORE32 R2 R0 0 ; Update ARGS->CAR->TYPE
  1847. POPR R2 R15 ; Restore R2
  1848. POPR R1 R15 ; Restore R1
  1849. RET R15
  1850. ;; string_to_list
  1851. ;; Receives a pointer to string in R0
  1852. ;; Returns a list of chars
  1853. :string_to_list
  1854. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1855. RET R15 ; Just get the Hell out
  1856. PUSHR R1 R15 ; Protect R1
  1857. PUSHR R2 R15 ; Protect R2
  1858. MOVE R1 R0 ; Put string safely out of the way
  1859. LOAD8 R0 R1 0 ; Get string[0]
  1860. JUMP.Z R0 @string_to_list_null
  1861. CALLI R15 @make_char ; Make seperate CHAR
  1862. SWAP R0 R1 ; Protect RESULT
  1863. ADDUI R0 R0 1 ; Increment to next iteration
  1864. CALLI R15 @string_to_list ; Recurse down STRING
  1865. SWAP R0 R1 ; Put RESULT and TAIL in right spot
  1866. CALLI R15 @make_cons ; Combine into a Cons
  1867. JUMP @string_to_list_done ; And simply return result
  1868. :string_to_list_null
  1869. LOADUI R0 $NIL ; Nil terminate list
  1870. :string_to_list_done
  1871. POPR R2 R15 ; Restore R2
  1872. POPR R1 R15 ; Restore R1
  1873. RET R15
  1874. ;; prim_string_to_list
  1875. ;; Receives a pointer to a CONS whose CAR should be a STRING
  1876. ;; Returns a list of CHARs in R0
  1877. :prim_string_to_list_String
  1878. "string->list"
  1879. :prim_string_to_list
  1880. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1881. RET R15 ; Just get the Hell out
  1882. PUSHR R1 R15 ; Protect R1
  1883. LOAD32 R0 R0 4 ; Get ARGS->CAR
  1884. LOAD32 R1 R0 0 ; Get ARGS->CAR->TYPE
  1885. CMPSKIPI.E R1 256 ; If Not Type STRING
  1886. JUMP @prim_string_to_list_fail
  1887. LOAD32 R0 R0 4 ; Get ARGS->CAR->STRING
  1888. CALLI R15 @string_to_list ; Convert to List
  1889. JUMP @prim_string_to_list_done
  1890. :prim_string_to_list_fail
  1891. LOADUI R0 $NIL ; Nil terminate list
  1892. :prim_string_to_list_done
  1893. POPR R1 R15 ; Restore R1
  1894. RET R15
  1895. ;; list_to_string
  1896. ;; Receives an index in R0, a String pointer in R1
  1897. ;; And a list of arguments in R2
  1898. ;; Alters only R0
  1899. :list_to_string
  1900. CMPSKIPI.NE R2 $NIL ; If NIL Expression
  1901. RET R15 ; Just get the Hell out
  1902. PUSHR R1 R15 ; Protect R1
  1903. PUSHR R2 R15 ; Protect R2
  1904. PUSHR R3 R15 ; Protect R3
  1905. PUSHR R4 R15 ; Protect R4
  1906. :list_to_string_0
  1907. CMPSKIPI.NE R2 $NIL ; If NIL Expression
  1908. JUMP @list_to_string_done ; We are done
  1909. LOAD32 R4 R2 4 ; Get ARGS->CAR
  1910. LOAD32 R3 R4 0 ; Get ARGS->CAR->TYPE
  1911. CMPSKIPI.NE R3 128 ; If Type CHAR
  1912. CALLI R15 @list_to_string_CHAR ; Process
  1913. ;; Guess CONS
  1914. SWAP R2 R4 ; Put i->CAR in i's spot
  1915. CMPSKIPI.NE R3 16 ; If Type CONS
  1916. CALLI R15 @list_to_string ; Recurse
  1917. SWAP R2 R4 ; Undo the Guess
  1918. ;; Everything else just iterate
  1919. LOAD32 R2 R2 8 ; i = i->CDR
  1920. JUMP @list_to_string_0 ; Lets go again
  1921. :list_to_string_CHAR
  1922. LOAD32 R3 R4 4 ; Get ARGS->CAR->VALUE
  1923. STOREX8 R3 R0 R1 ; STRING[INDEX] = i->CAR->VALUE
  1924. ADDUI R0 R0 1 ; INDEX = INDEX + 1
  1925. RET R15 ; Get back in there
  1926. :list_to_string_done
  1927. POPR R4 R15 ; Restore R4
  1928. POPR R3 R15 ; Restore R3
  1929. POPR R2 R15 ; Restore R2
  1930. POPR R1 R15 ; Restore R1
  1931. RET R15
  1932. ;; prim_list_to_string
  1933. ;; Receives a list in R0
  1934. ;; Returns a String CELL in R0
  1935. :prim_list_to_string_String
  1936. "list->string"
  1937. :prim_list_to_string
  1938. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1939. RET R15 ; Just get the Hell out
  1940. PUSHR R1 R15 ; Protect R1
  1941. PUSHR R2 R15 ; Protect R2
  1942. MOVE R2 R0 ; Put Args in correct location and Zero R0
  1943. CALLI R15 @malloc ; Get where space is free
  1944. MOVE R1 R0 ; Put String pointer in correct location and Zero R0
  1945. CALLI R15 @list_to_string ; Call backing function
  1946. ADDUI R0 R0 1 ; NULL Terminate string
  1947. CALLI R15 @malloc ; Correct malloc
  1948. CALLI R15 @make_string ; Use pointer to make our string CELL
  1949. POPR R2 R15 ; Restore R2
  1950. POPR R1 R15 ; Restore R1
  1951. RET R15
  1952. ;; prim_halt
  1953. ;; Simply HALTS
  1954. :prim_halt_String
  1955. "HALT"
  1956. :prim_halt
  1957. LOADUI R0 0x1101 ; Clean up after ourselves
  1958. FCLOSE ; Close our write tape
  1959. HALT
  1960. ;; prim_list
  1961. ;; Simply returns the argument list passed to it in R0
  1962. :prim_list_String
  1963. "list"
  1964. :prim_list
  1965. RET R15
  1966. ;; prim_cons
  1967. ;; Receives an arglist in R0 and returns a CONS in R0
  1968. :prim_cons_String
  1969. "cons"
  1970. :prim_cons
  1971. PUSHR R1 R15 ; Protect R1
  1972. LOAD32 R1 R0 8 ; Get ARGS->CDR
  1973. LOAD32 R1 R1 4 ; Use ARGS->CDR->CAR
  1974. LOAD32 R0 R0 4 ; Use ARGS->CAR
  1975. CALLI R15 @make_cons ; MAKE_CONS
  1976. POPR R1 R15 ; Restore R1
  1977. RET R15
  1978. ;; prim_car
  1979. ;; Receives an arglist in R0 and returns the CAR in R0
  1980. :prim_car_String
  1981. "car"
  1982. :prim_car
  1983. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1984. RET R15 ; Just get the Hell out
  1985. LOAD32 R0 R0 4 ; Get ARGS->CAR
  1986. LOAD32 R0 R0 4 ; Using ARGS->CAR->CAR
  1987. RET R15
  1988. ;; prim_cdr
  1989. ;; Receives an arglist in R0 and returns the CDR in R0
  1990. :prim_cdr_String
  1991. "cdr"
  1992. :prim_cdr
  1993. CMPSKIPI.NE R0 $NIL ; If NIL Expression
  1994. RET R15 ; Just get the Hell out
  1995. LOAD32 R0 R0 4 ; Get ARGS->CAR
  1996. LOAD32 R0 R0 8 ; Using ARGS->CAR->CDR
  1997. RET R15
  1998. ;; spinup
  1999. ;; Receives a symbol in R0 and a primitive in R1
  2000. ;; Returns nothing but CONS both to all_symbols and top_env
  2001. :spinup
  2002. PUSHR R0 R15 ; Protect R0
  2003. PUSHR R1 R15 ; Protect R1
  2004. PUSHR R2 R15 ; Protect R2
  2005. PUSHR R3 R15 ; Protect R3
  2006. COPY R3 R0 ; Protect SYM
  2007. MOVE R2 R1 ; Put PRIM in right Spot
  2008. LOADR R1 @all_symbols ; Get ALL_SYMBOLS
  2009. CALLI R15 @make_cons ; MAKE_CONS
  2010. STORER R0 @all_symbols ; Update ALL_SYMBOLS
  2011. MOVE R1 R3 ; Restore SYM
  2012. LOADR R0 @top_env ; Get TOP_ENV
  2013. CALLI R15 @extend ; EXTEND
  2014. STORER R0 @top_env ; Update TOP_ENV
  2015. POPR R3 R15 ; Restore R3
  2016. POPR R2 R15 ; Restore R2
  2017. POPR R1 R15 ; Restore R1
  2018. POPR R0 R15 ; Restore R0
  2019. RET R15
  2020. ;; Special symbols
  2021. ;; NIL Object
  2022. :NIL
  2023. '00000008' ; A Symbol
  2024. &NIL_String ; Pointer to string
  2025. '00000000' ; NUL CDR
  2026. '00000000' ; NUL ENV
  2027. :NIL_String
  2028. "nil"
  2029. ;; TEE Object
  2030. :TEE
  2031. '00000008' ; A Symbol
  2032. &TEE_String ; Pointer to string
  2033. '00000000' ; NUL CDR
  2034. '00000000' ; NUL ENV
  2035. :TEE_String
  2036. "#t"
  2037. ;; Quote Object
  2038. :s_quote
  2039. '00000008' ; A Symbol
  2040. &s_quote_String ; Pointer to string
  2041. '00000000' ; NUL CDR
  2042. '00000000' ; NUL ENV
  2043. :s_quote_String
  2044. "quote"
  2045. ;; IF Object
  2046. :s_if
  2047. '00000008' ; A Symbol
  2048. &s_if_String ; Pointer to string
  2049. '00000000' ; NUL CDR
  2050. '00000000' ; NUL ENV
  2051. :s_if_String
  2052. "if"
  2053. ;; COND Object
  2054. :s_cond
  2055. '00000008' ; A Symbol
  2056. &s_cond_String ; Pointer to string
  2057. '00000000' ; NUL CDR
  2058. '00000000' ; NUL ENV
  2059. :s_cond_String
  2060. "cond"
  2061. ;; Lambda Object
  2062. :s_lambda
  2063. '00000008' ; A Symbol
  2064. &s_lambda_String ; Pointer to string
  2065. '00000000' ; NUL CDR
  2066. '00000000' ; NUL ENV
  2067. :s_lambda_String
  2068. "lambda"
  2069. ;; Define Object
  2070. :s_define
  2071. '00000008' ; A Symbol
  2072. &s_define_String ; Pointer to string
  2073. '00000000' ; NUL CDR
  2074. '00000000' ; NUL ENV
  2075. :s_define_String
  2076. "define"
  2077. ;; SET Object
  2078. :s_setb
  2079. '00000008' ; A Symbol
  2080. &s_setb_String ; Pointer to string
  2081. '00000000' ; NUL CDR
  2082. '00000000' ; NUL ENV
  2083. :s_setb_String
  2084. "set!"
  2085. ;; LET Object
  2086. :s_let
  2087. '00000008' ; A Symbol
  2088. &s_let_String ; Pointer to string
  2089. '00000000' ; NUL CDR
  2090. '00000000' ; NUL ENV
  2091. :s_let_String
  2092. "let"
  2093. ;; Begin Object
  2094. :s_begin
  2095. '00000008' ; A Symbol
  2096. &s_begin_String ; Pointer to string
  2097. '00000000' ; NUL CDR
  2098. '00000000' ; NUL ENV
  2099. :s_begin_String
  2100. "begin"
  2101. ;; Globals of interest
  2102. :all_symbols
  2103. &all_symbols_init
  2104. :all_symbols_init
  2105. '00000010' ; A CONS
  2106. &NIL ; Pointer to NIL
  2107. &NIL ; Pointer to NIL
  2108. '00000000' ; NULL
  2109. :top_env
  2110. &top_env_init_1
  2111. :top_env_init_0
  2112. '00000010' ; A CONS
  2113. &NIL ; Pointer to NIL
  2114. &NIL ; Pointer to NIL
  2115. '00000000' ; NULL
  2116. :top_env_init_1
  2117. '00000010' ; A CONS
  2118. &top_env_init_0 ; Pointer to CONS of NIL
  2119. &NIL ; Pointer to NIL
  2120. '00000000' ; NULL
  2121. :free_cells
  2122. NOP ; Start with NULL
  2123. ;; Global init function
  2124. ;; Receives nothing
  2125. ;; Returns nothing
  2126. ;; sets up all_symbols and top_env
  2127. :init_sl3
  2128. PUSHR R0 R15 ; Protect R0
  2129. PUSHR R1 R15 ; Protect R1
  2130. ;; Add Eval Specials
  2131. LOADUI R0 $TEE ; Get TEE
  2132. COPY R1 R0 ; Duplicate TEE
  2133. CALLI R15 @spinup ; SPINUP
  2134. LOADUI R0 $s_quote ; Get s_quote
  2135. COPY R1 R0 ; Duplicate s_quote
  2136. CALLI R15 @spinup ; SPINUP
  2137. LOADUI R0 $s_if ; Get s_if
  2138. COPY R1 R0 ; Duplicate s_if
  2139. CALLI R15 @spinup ; SPINUP
  2140. LOADUI R0 $s_cond ; Get s_cond
  2141. COPY R1 R0 ; Duplicate s_cond
  2142. CALLI R15 @spinup ; SPINUP
  2143. LOADUI R0 $s_lambda ; Get s_lambda
  2144. COPY R1 R0 ; Duplicate s_lambda
  2145. CALLI R15 @spinup ; SPINUP
  2146. LOADUI R0 $s_define ; Get s_define
  2147. COPY R1 R0 ; Duplicate s_define
  2148. CALLI R15 @spinup ; SPINUP
  2149. LOADUI R0 $s_setb ; Get s_setb
  2150. COPY R1 R0 ; Duplicate s_setb
  2151. CALLI R15 @spinup ; SPINUP
  2152. LOADUI R0 $s_let ; Get s_let
  2153. COPY R1 R0 ; Duplicate s_let
  2154. CALLI R15 @spinup ; SPINUP
  2155. LOADUI R0 $s_begin ; Get s_begin
  2156. COPY R1 R0 ; Duplicate s_if
  2157. CALLI R15 @spinup ; SPINUP
  2158. ;; Add Primitive Specials
  2159. LOADUI R0 $prim_apply ; Using PRIM_APPLY
  2160. CALLI R15 @make_prim ; MAKE_PRIM
  2161. MOVE R1 R0 ; Put Primitive in correct location
  2162. LOADUI R0 $prim_apply_String ; Using PRIM_APPLY_STRING
  2163. CALLI R15 @make_sym ; MAKE_SYM
  2164. CALLI R15 @spinup ; SPINUP
  2165. LOADUI R0 $nullp ; Using NULLP
  2166. CALLI R15 @make_prim ; MAKE_PRIM
  2167. MOVE R1 R0 ; Put Primitive in correct location
  2168. LOADUI R0 $nullp_String ; Using NULLP_STRING
  2169. CALLI R15 @make_sym ; MAKE_SYM
  2170. CALLI R15 @spinup ; SPINUP
  2171. LOADUI R0 $prim_sum ; Using PRIM_SUM
  2172. CALLI R15 @make_prim ; MAKE_PRIM
  2173. MOVE R1 R0 ; Put Primitive in correct location
  2174. LOADUI R0 $prim_sum_String ; Using PRIM_SUM_STRING
  2175. CALLI R15 @make_sym ; MAKE_SYM
  2176. CALLI R15 @spinup ; SPINUP
  2177. LOADUI R0 $prim_sub ; Using PRIM_SUB
  2178. CALLI R15 @make_prim ; MAKE_PRIM
  2179. MOVE R1 R0 ; Put Primitive in correct location
  2180. LOADUI R0 $prim_sub_String ; Using PRIM_SUB_STRING
  2181. CALLI R15 @make_sym ; MAKE_SYM
  2182. CALLI R15 @spinup ; SPINUP
  2183. LOADUI R0 $prim_prod ; Using PRIM_PROD
  2184. CALLI R15 @make_prim ; MAKE_PRIM
  2185. MOVE R1 R0 ; Put Primitive in correct location
  2186. LOADUI R0 $prim_prod_String ; Using PRIM_PROD_STRING
  2187. CALLI R15 @make_sym ; MAKE_SYM
  2188. CALLI R15 @spinup ; SPINUP
  2189. LOADUI R0 $prim_div ; Using PRIM_DIV
  2190. CALLI R15 @make_prim ; MAKE_PRIM
  2191. MOVE R1 R0 ; Put Primitive in correct location
  2192. LOADUI R0 $prim_div_String ; Using PRIM_DIV_STRING
  2193. CALLI R15 @make_sym ; MAKE_SYM
  2194. CALLI R15 @spinup ; SPINUP
  2195. LOADUI R0 $prim_mod ; Using PRIM_MOD
  2196. CALLI R15 @make_prim ; MAKE_PRIM
  2197. MOVE R1 R0 ; Put Primitive in correct location
  2198. LOADUI R0 $prim_mod_String ; Using PRIM_MOD_STRING
  2199. CALLI R15 @make_sym ; MAKE_SYM
  2200. CALLI R15 @spinup ; SPINUP
  2201. LOADUI R0 $prim_and ; Using PRIM_AND
  2202. CALLI R15 @make_prim ; MAKE_PRIM
  2203. MOVE R1 R0 ; Put Primitive in correct location
  2204. LOADUI R0 $prim_and_String ; Using PRIM_AND_STRING
  2205. CALLI R15 @make_sym ; MAKE_SYM
  2206. CALLI R15 @spinup ; SPINUP
  2207. LOADUI R0 $prim_or ; Using PRIM_OR
  2208. CALLI R15 @make_prim ; MAKE_PRIM
  2209. MOVE R1 R0 ; Put Primitive in correct location
  2210. LOADUI R0 $prim_or_String ; Using PRIM_OR_STRING
  2211. CALLI R15 @make_sym ; MAKE_SYM
  2212. CALLI R15 @spinup ; SPINUP
  2213. LOADUI R0 $prim_not ; Using PRIM_NOT
  2214. CALLI R15 @make_prim ; MAKE_PRIM
  2215. MOVE R1 R0 ; Put Primitive in correct location
  2216. LOADUI R0 $prim_not_String ; Using PRIM_NOT_STRING
  2217. CALLI R15 @make_sym ; MAKE_SYM
  2218. CALLI R15 @spinup ; SPINUP
  2219. LOADUI R0 $prim_numgt ; Using PRIM_NUMGT
  2220. CALLI R15 @make_prim ; MAKE_PRIM
  2221. MOVE R1 R0 ; Put Primitive in correct location
  2222. LOADUI R0 $prim_numgt_String ; Using PRIM_NUMGT_STRING
  2223. CALLI R15 @make_sym ; MAKE_SYM
  2224. CALLI R15 @spinup ; SPINUP
  2225. LOADUI R0 $prim_numge ; Using PRIM_NUMGE
  2226. CALLI R15 @make_prim ; MAKE_PRIM
  2227. MOVE R1 R0 ; Put Primitive in correct location
  2228. LOADUI R0 $prim_numge_String ; Using PRIM_NUMGE_STRING
  2229. CALLI R15 @make_sym ; MAKE_SYM
  2230. CALLI R15 @spinup ; SPINUP
  2231. LOADUI R0 $prim_numeq ; Using PRIM_NUMEQ
  2232. CALLI R15 @make_prim ; MAKE_PRIM
  2233. MOVE R1 R0 ; Put Primitive in correct location
  2234. LOADUI R0 $prim_numeq_String ; Using PRIM_NUMEQ_STRING
  2235. CALLI R15 @make_sym ; MAKE_SYM
  2236. CALLI R15 @spinup ; SPINUP
  2237. LOADUI R0 $prim_numle ; Using PRIM_NUMLE
  2238. CALLI R15 @make_prim ; MAKE_PRIM
  2239. MOVE R1 R0 ; Put Primitive in correct location
  2240. LOADUI R0 $prim_numle_String ; Using PRIM_NUMLE_STRING
  2241. CALLI R15 @make_sym ; MAKE_SYM
  2242. CALLI R15 @spinup ; SPINUP
  2243. LOADUI R0 $prim_numlt ; Using PRIM_NUMLT
  2244. CALLI R15 @make_prim ; MAKE_PRIM
  2245. MOVE R1 R0 ; Put Primitive in correct location
  2246. LOADUI R0 $prim_numlt_String ; Using PRIM_NUMLT_STRING
  2247. CALLI R15 @make_sym ; MAKE_SYM
  2248. CALLI R15 @spinup ; SPINUP
  2249. LOADUI R0 $prim_listp ; Using PRIM_LISTP
  2250. CALLI R15 @make_prim ; MAKE_PRIM
  2251. MOVE R1 R0 ; Put Primitive in correct location
  2252. LOADUI R0 $prim_listp_String ; Using PRIM_LISTP_STRING
  2253. CALLI R15 @make_sym ; MAKE_SYM
  2254. CALLI R15 @spinup ; SPINUP
  2255. LOADUI R0 $prim_charp ; Using PRIM_CHARP
  2256. CALLI R15 @make_prim ; MAKE_PRIM
  2257. MOVE R1 R0 ; Put Primitive in correct location
  2258. LOADUI R0 $prim_charp_String ; Using PRIM_CHARP_STRING
  2259. CALLI R15 @make_sym ; MAKE_SYM
  2260. CALLI R15 @spinup ; SPINUP
  2261. LOADUI R0 $prim_numberp ; Using PRIM_NUMBERP
  2262. CALLI R15 @make_prim ; MAKE_PRIM
  2263. MOVE R1 R0 ; Put Primitive in correct location
  2264. LOADUI R0 $prim_numberp_String ; Using PRIM_NUMBERP_STRING
  2265. CALLI R15 @make_sym ; MAKE_SYM
  2266. CALLI R15 @spinup ; SPINUP
  2267. LOADUI R0 $prim_symbolp ; Using PRIM_SYMBOLP
  2268. CALLI R15 @make_prim ; MAKE_PRIM
  2269. MOVE R1 R0 ; Put Primitive in correct location
  2270. LOADUI R0 $prim_symbolp_String ; Using PRIM_SYMBOLP_STRING
  2271. CALLI R15 @make_sym ; MAKE_SYM
  2272. CALLI R15 @spinup ; SPINUP
  2273. LOADUI R0 $prim_stringp ; Using PRIM_STRINGP
  2274. CALLI R15 @make_prim ; MAKE_PRIM
  2275. MOVE R1 R0 ; Put Primitive in correct location
  2276. LOADUI R0 $prim_stringp_String ; Using PRIM_STRINGP_STRING
  2277. CALLI R15 @make_sym ; MAKE_SYM
  2278. CALLI R15 @spinup ; SPINUP
  2279. LOADUI R0 $prim_display ; Using PRIM_DISPLAY
  2280. CALLI R15 @make_prim ; MAKE_PRIM
  2281. MOVE R1 R0 ; Put Primitive in correct location
  2282. LOADUI R0 $prim_display_String ; Using PRIM_DISPLAY_STRING
  2283. CALLI R15 @make_sym ; MAKE_SYM
  2284. CALLI R15 @spinup ; SPINUP
  2285. LOADUI R0 $prim_write ; Using PRIM_WRITE
  2286. CALLI R15 @make_prim ; MAKE_PRIM
  2287. MOVE R1 R0 ; Put Primitive in correct location
  2288. LOADUI R0 $prim_write_String ; Using PRIM_WRITE_STRING
  2289. CALLI R15 @make_sym ; MAKE_SYM
  2290. CALLI R15 @spinup ; SPINUP
  2291. LOADUI R0 $prim_freecell ; Using PRIM_FREECELL
  2292. CALLI R15 @make_prim ; MAKE_PRIM
  2293. MOVE R1 R0 ; Put Primitive in correct location
  2294. LOADUI R0 $prim_freecell_String ; Using PRIM_FREECELL_STRING
  2295. CALLI R15 @make_sym ; MAKE_SYM
  2296. CALLI R15 @spinup ; SPINUP
  2297. LOADUI R0 $prim_integer_to_char ; Using PRIM_INTEGER_TO_CHAR
  2298. CALLI R15 @make_prim ; MAKE_PRIM
  2299. MOVE R1 R0 ; Put Primitive in correct location
  2300. LOADUI R0 $prim_integer_to_char_String ; Using PRIM_INTEGER_TO_CHAR_STRING
  2301. CALLI R15 @make_sym ; MAKE_SYM
  2302. CALLI R15 @spinup ; SPINUP
  2303. LOADUI R0 $prim_char_to_integer ; Using PRIM_CHAR_TO_INTEGER
  2304. CALLI R15 @make_prim ; MAKE_PRIM
  2305. MOVE R1 R0 ; Put Primitive in correct location
  2306. LOADUI R0 $prim_char_to_integer_String ; Using PRIM_CHAR_TO_INTEGER_STRING
  2307. CALLI R15 @make_sym ; MAKE_SYM
  2308. CALLI R15 @spinup ; SPINUP
  2309. LOADUI R0 $prim_string_to_list ; Using PRIM_STRING_TO_LIST
  2310. CALLI R15 @make_prim ; MAKE_PRIM
  2311. MOVE R1 R0 ; Put Primitive in correct location
  2312. LOADUI R0 $prim_string_to_list_String ; Using PRIM_STRING_TO_LIST_STRING
  2313. CALLI R15 @make_sym ; MAKE_SYM
  2314. CALLI R15 @spinup ; SPINUP
  2315. LOADUI R0 $prim_list_to_string ; Using PRIM_LIST_TO_STRING
  2316. CALLI R15 @make_prim ; MAKE_PRIM
  2317. MOVE R1 R0 ; Put Primitive in correct location
  2318. LOADUI R0 $prim_list_to_string_String ; Using PRIM_LIST_TO_STRING_STRING
  2319. CALLI R15 @make_sym ; MAKE_SYM
  2320. CALLI R15 @spinup ; SPINUP
  2321. LOADUI R0 $prim_halt ; Using PRIM_HALT
  2322. CALLI R15 @make_prim ; MAKE_PRIM
  2323. MOVE R1 R0 ; Put Primitive in correct location
  2324. LOADUI R0 $prim_halt_String ; Using PRIM_HALT_STRING
  2325. CALLI R15 @make_sym ; MAKE_SYM
  2326. CALLI R15 @spinup ; SPINUP
  2327. LOADUI R0 $prim_list ; Using PRIM_list
  2328. CALLI R15 @make_prim ; MAKE_PRIM
  2329. MOVE R1 R0 ; Put Primitive in correct location
  2330. LOADUI R0 $prim_list_String ; Using PRIM_LIST_STRING
  2331. CALLI R15 @make_sym ; MAKE_SYM
  2332. CALLI R15 @spinup ; SPINUP
  2333. LOADUI R0 $prim_stringeq ; Using PRIM_STRINGEQ
  2334. CALLI R15 @make_prim ; MAKE_PRIM
  2335. MOVE R1 R0 ; Put Primitive in correct location
  2336. LOADUI R0 $prim_stringeq_String ; Using PRIM_STRINGEQ_STRING
  2337. CALLI R15 @make_sym ; MAKE_SYM
  2338. CALLI R15 @spinup ; SPINUP
  2339. LOADUI R0 $prim_cons ; Using PRIM_CONS
  2340. CALLI R15 @make_prim ; MAKE_PRIM
  2341. MOVE R1 R0 ; Put Primitive in correct location
  2342. LOADUI R0 $prim_cons_String ; Using PRIM_CONS_STRING
  2343. CALLI R15 @make_sym ; MAKE_SYM
  2344. CALLI R15 @spinup ; SPINUP
  2345. LOADUI R0 $prim_car ; Using PRIM_CAR
  2346. CALLI R15 @make_prim ; MAKE_PRIM
  2347. MOVE R1 R0 ; Put Primitive in correct location
  2348. LOADUI R0 $prim_car_String ; Using PRIM_CAR_STRING
  2349. CALLI R15 @make_sym ; MAKE_SYM
  2350. CALLI R15 @spinup ; SPINUP
  2351. LOADUI R0 $prim_cdr ; Using PRIM_CDR
  2352. CALLI R15 @make_prim ; MAKE_PRIM
  2353. MOVE R1 R0 ; Put Primitive in correct location
  2354. LOADUI R0 $prim_cdr_String ; Using PRIM_CDR_STRING
  2355. CALLI R15 @make_sym ; MAKE_SYM
  2356. CALLI R15 @spinup ; SPINUP
  2357. ;; Clean up
  2358. POPR R1 R15 ; Restore R1
  2359. POPR R0 R15 ; Restore R0
  2360. RET R15
  2361. ;; Left_to_take
  2362. ;; The number of cells_remaining
  2363. :left_to_take
  2364. NOP
  2365. ;; cells_remaining
  2366. ;; Receives nothing and returns number of remaining cells in R0
  2367. :cells_remaining
  2368. LOADR R0 @left_to_take ; Get number of cells left
  2369. RET R15
  2370. ;; update_remaining
  2371. ;; Receives nothing
  2372. ;; Returns nothing
  2373. ;; Updates left_to_take via counting
  2374. :update_remaining
  2375. PUSHR R0 R15 ; Protect R0
  2376. PUSHR R1 R15 ; Protect R1
  2377. LOADR R0 @free_cells ; Get FREE_CELLS
  2378. FALSE R1 ; Set Count to 0
  2379. :update_remaining_0
  2380. JUMP.Z R0 @update_remaining_done
  2381. ADDUI R1 R1 1 ; Increment by 1
  2382. LOAD32 R0 R0 8 ; get I->CDR
  2383. JUMP @update_remaining_0 ; Keep looping til NULL
  2384. :update_remaining_done
  2385. STORER R1 @left_to_take ; update left_to_take
  2386. POPR R1 R15 ; Restore R1
  2387. POPR R0 R15 ; Restore R0
  2388. RET R15
  2389. ;; gc_block_start
  2390. :gc_block_start
  2391. &Start_CONS
  2392. ;; top_allocated
  2393. :top_allocated
  2394. '000FFFF0'
  2395. ;; insert_ordered
  2396. ;; Receives a cell and a list of cells in R0 and R1
  2397. ;; Inserts cell into the list from lowest to highest
  2398. ;; Returns resulting list in R0
  2399. :insert_ordered
  2400. CMPSKIPI.NE R1 0 ; If List is NULL
  2401. RET R15 ; Just return CELL
  2402. CMPJUMPI.GE R0 R1 @insert_ordered_0
  2403. STORE32 R1 R0 8 ; Set I->CDR to LIST
  2404. RET R15 ; Simply return I
  2405. :insert_ordered_0
  2406. PUSHR R1 R15 ; Protect List from recursion
  2407. LOAD32 R1 R1 8 ; Using LIST->CDR
  2408. CALLI R15 @insert_ordered ; Recurse
  2409. POPR R1 R15 ; Restore LIST
  2410. STORE32 R0 R1 8 ; Set LIST->CDR to the result of recursion
  2411. MOVE R0 R1 ; Prepare for return
  2412. RET R15
  2413. ;; reclaim_marked
  2414. ;; Receives nothing
  2415. ;; Returns nothing
  2416. ;; Reclaims and updates free_cells
  2417. :reclaim_marked
  2418. PUSHR R0 R15 ; Protect R0
  2419. PUSHR R1 R15 ; Protect R1
  2420. PUSHR R2 R15 ; Protect R2
  2421. PUSHR R3 R15 ; Protect R3
  2422. LOADR R3 @gc_block_start ; Using GC_BLOCK_START
  2423. LOADR R2 @top_allocated ; Using TOP_ALLOCATED
  2424. :reclaim_marked_0
  2425. CMPJUMPI.LE R2 R3 @reclaim_marked_done
  2426. LOAD32 R1 R2 0 ; Get I->TYPE
  2427. ANDI R1 R1 2 ; AND with MARKED
  2428. JUMP.Z R1 @reclaim_marked_1 ; Deal with MARKED CELLS or jump on NULL
  2429. ;; Deal with Marked
  2430. LOADUI R0 1 ; Using FREE
  2431. STORE32 R0 R2 0 ; Set I->TYPE to FREE
  2432. FALSE R0 ; USING NULL
  2433. STORE32 R0 R2 4 ; SET I->CAR to NULL
  2434. STORE32 R0 R2 12 ; SET I->ENV to NULL
  2435. COPY R0 R2 ; Prepare for INSERT_ORDERED
  2436. LOADR R1 @free_cells ; Get FREE_CELLS
  2437. CALLI R15 @insert_ordered ; Get New FREE_CELLS Pointer
  2438. STORER R0 @free_cells ; Update FREE_CELLS to I
  2439. ;; Deal with unmarked
  2440. :reclaim_marked_1
  2441. SUBUI R2 R2 16 ; Decrement I by the size of a CELL
  2442. JUMP @reclaim_marked_0 ; Iterate on next CELL
  2443. :reclaim_marked_done
  2444. POPR R3 R15 ; Restore R3
  2445. POPR R2 R15 ; Restore R2
  2446. POPR R1 R15 ; Restore R1
  2447. POPR R0 R15 ; Restore R0
  2448. RET R15
  2449. ;; mark_all_cells
  2450. ;; Receives nothing
  2451. ;; Returns nothing
  2452. ;; Marks all unfree cells
  2453. :mark_all_cells
  2454. PUSHR R0 R15 ; Protect R0
  2455. PUSHR R1 R15 ; Protect R1
  2456. PUSHR R2 R15 ; Protect R2
  2457. PUSHR R3 R15 ; Protect R3
  2458. LOADR R0 @gc_block_start ; Using GC_BLOCK_START
  2459. LOADR R1 @top_allocated ; Using TOP_ALLOCATED
  2460. :mark_all_cells_0
  2461. CMPJUMPI.GE R0 R1 @mark_all_cells_done
  2462. LOAD32 R2 R0 0 ; Get I->TYPE
  2463. CMPSKIPI.NE R2 1 ; If NOT FREE
  2464. JUMP @mark_all_cells_1 ; Move onto the Next
  2465. ;; Mark non-free cell
  2466. ORI R2 R2 2 ; Add MARK
  2467. STORE32 R2 R0 0 ; Write out MARK
  2468. :mark_all_cells_1
  2469. ADDUI R0 R0 16 ; Increment I by the size of a CELL
  2470. JUMP @mark_all_cells_0 ; Iterate on next CELL
  2471. :mark_all_cells_done
  2472. POPR R3 R15 ; Restore R3
  2473. POPR R2 R15 ; Restore R2
  2474. POPR R1 R15 ; Restore R1
  2475. POPR R0 R15 ; Restore R0
  2476. RET R15
  2477. ;; unmark_cells
  2478. ;; Receives a List in R0 and R1 and a Count in R2
  2479. ;; Returns nothing
  2480. ;; Unmarks all connected Cells
  2481. :unmark_cells
  2482. CMPSKIPI.LE R2 2 ; If Greater than 1
  2483. RET R15 ; Just return
  2484. PUSHR R0 R15 ; Protect R0
  2485. PUSHR R1 R15 ; Protect R1
  2486. PUSHR R2 R15 ; Protect R2
  2487. PUSHR R3 R15 ; Protect R3
  2488. PUSHR R4 R15 ; Protect R4
  2489. LOADUI R4 2 ; GET MARKED
  2490. NOT R4 R4 ; Use ~MARKED
  2491. :unmark_cells_0
  2492. JUMP.Z R0 @unmark_cells_done
  2493. CMPSKIP.NE R0 R1 ; If LIST == STOP
  2494. ADDUI R2 R2 1 ; Increment Count
  2495. LOAD32 R3 R0 0 ; Get I->TYPE
  2496. AND R3 R3 R4 ; Remove MARK
  2497. STORE32 R3 R0 0 ; Store the cleaned type
  2498. ;; Deal with CONS
  2499. CMPSKIPI.NE R3 16 ; If A CONS
  2500. JUMP @unmark_cells_cons ; Deal with it
  2501. ;; Deal with PROC
  2502. CMPSKIPI.NE R3 32 ; If A PROC
  2503. JUMP @unmark_cells_proc ; Deal with it
  2504. ;; Everything else
  2505. JUMP @unmark_cells_1 ; Move onto NEXT
  2506. :unmark_cells_proc
  2507. LOAD32 R3 R0 12 ; Using list->ENV
  2508. CMPSKIPI.NE R3 0 ; If NULL
  2509. JUMP @unmark_cells_cons ; Skip
  2510. SWAP R0 R3 ; Protect list
  2511. CALLI R15 @unmark_cells ; Recurse until the ends
  2512. SWAP R0 R3 ; Put list back
  2513. :unmark_cells_cons
  2514. LOAD32 R3 R0 4 ; Using list->CAR
  2515. SWAP R0 R3 ; Protect list
  2516. CALLI R15 @unmark_cells ; Recurse until the ends
  2517. SWAP R0 R3 ; Put list back
  2518. :unmark_cells_1
  2519. LOAD32 R0 R0 8 ; Get list->CDR
  2520. JUMP @unmark_cells_0 ; Keep going down list
  2521. :unmark_cells_done
  2522. POPR R4 R15 ; Restore R4
  2523. POPR R3 R15 ; Restore R3
  2524. POPR R2 R15 ; Restore R2
  2525. POPR R1 R15 ; Restore R1
  2526. POPR R0 R15 ; Restore R0
  2527. RET R15
  2528. ;; relocate_cell
  2529. ;; Receives a current, target and List in R0, R1 and R2
  2530. ;; Returns nothing
  2531. ;; Relocate all references to a cell and walks down list
  2532. :relocate_cell
  2533. PUSHR R3 R15 ; Protect R3
  2534. :relocate_cell_0
  2535. JUMP.Z R2 @relocate_cell_done
  2536. ;; Fix CAR References
  2537. LOAD32 R3 R2 4 ; Get LIST->CAR
  2538. CMPSKIP.NE R0 R3 ; If match with Current
  2539. STORE32 R1 R2 4 ; Fix LIST->CAR
  2540. ;; Fix CDR References
  2541. LOAD32 R3 R2 8 ; Get LIST->CDR
  2542. CMPSKIP.NE R0 R3 ; If match with Current
  2543. STORE32 R1 R2 8 ; Fix LIST->CDR
  2544. ;; Fix ENV References
  2545. LOAD32 R3 R2 12 ; Get LIST->ENV
  2546. CMPSKIP.NE R0 R3 ; If match with Current
  2547. STORE32 R1 R2 12 ; Fix LIST->ENV
  2548. LOAD32 R3 R2 0 ; Get LIST->TYPE
  2549. ;; Deal with CONS
  2550. CMPSKIPI.NE R3 16 ; If A CONS
  2551. JUMP @relocate_cell_proc ; Deal with it
  2552. ;; Deal with PROC
  2553. CMPSKIPI.NE R3 32 ; If A PROC
  2554. JUMP @relocate_cell_proc ; Deal with it
  2555. ;; Everything else
  2556. JUMP @relocate_cell_1 ; Move onto NEXT
  2557. :relocate_cell_proc
  2558. PUSHR R2 R15 ; Protect LIST
  2559. LOAD32 R2 R2 4 ; Using list->CAR
  2560. CALLI R15 @relocate_cell ; Recurse until the ends
  2561. POPR R2 R15 ; Restore LIST
  2562. :relocate_cell_1
  2563. LOAD32 R2 R2 8 ; Get list->CDR
  2564. JUMP @relocate_cell_0 ; Keep going down list
  2565. :relocate_cell_done
  2566. POPR R3 R15 ; Restore R3
  2567. RET R15
  2568. ;; compact
  2569. ;; Receives a List in R0
  2570. ;; Returns nothing
  2571. ;; Finds cells to relocate and has all references updated
  2572. :compact
  2573. PUSHR R1 R15 ; Protect R1
  2574. PUSHR R2 R15 ; Protect R2
  2575. :compact_0
  2576. JUMP.Z R0 @compact_done
  2577. LOAD32 R2 R0 0 ; Get LIST->TYPE
  2578. CMPSKIPI.NE R2 1 ; If LIST->TYPE == FREE
  2579. JUMP @compact_1 ; Not worth relocating
  2580. LOADR R1 @free_cells ; Get FREE_CELLS
  2581. CMPJUMPI.LE R0 R1 @compact_1 ; Don't bother to relocate if Low
  2582. ;; Found a better place for cell
  2583. SWAP R0 R1 ; Get LIST out of the way
  2584. CALLI R15 @pop_cons ; Get our New location
  2585. SWAP R0 R1 ; Put in correct order
  2586. ;; Update temp to LIST
  2587. LOAD32 R2 R0 0 ; Get LIST->TYPE
  2588. STORE32 R2 R1 0 ; Set TEMP->TYPE
  2589. LOAD32 R2 R0 4 ; GET LIST->CAR
  2590. STORE32 R2 R1 4 ; Set TEMP->CAR
  2591. LOAD32 R2 R0 8 ; GET LIST->CDR
  2592. STORE32 R2 R1 8 ; Set TEMP->CDR
  2593. LOAD32 R2 R0 12 ; GET LIST->ENV
  2594. STORE32 R2 R1 12 ; Set TEMP->ENV
  2595. ;; Fix Reference in Symbols list
  2596. LOADR R2 @all_symbols
  2597. CALLI R15 @relocate_cell
  2598. ;; Fix References in Environment list
  2599. LOADR R2 @top_env
  2600. CALLI R15 @relocate_cell
  2601. LOAD32 R2 R0 0 ; Get LIST->TYPE
  2602. :compact_1
  2603. ;; Deal with CONS
  2604. CMPSKIPI.NE R2 16 ; If A CONS
  2605. JUMP @compact_proc ; Deal with it
  2606. ;; Deal with PROC
  2607. CMPSKIPI.NE R2 32 ; If A PROC
  2608. JUMP @compact_proc ; Deal with it
  2609. ;; Everything else
  2610. JUMP @compact_2 ; Move onto NEXT
  2611. :compact_proc
  2612. PUSHR R0 R15 ; Protect LIST
  2613. LOAD32 R0 R0 4 ; Using list->CAR
  2614. CALLI R15 @compact ; Recurse until the ends
  2615. POPR R0 R15 ; Restore LIST
  2616. :compact_2
  2617. LOAD32 R0 R0 8 ; Get list->CDR
  2618. JUMP @compact_0 ; Keep going down list
  2619. :compact_done
  2620. POPR R2 R15 ; Restore R2
  2621. POPR R1 R15 ; Restore R1
  2622. RET R15
  2623. ;; garbage_collect
  2624. ;; Receives nothing
  2625. ;; Returns nothing
  2626. ;; The Core of Garbage Collection
  2627. :garbage_collect
  2628. PUSHR R0 R15 ; Protect R0
  2629. PUSHR R1 R15 ; Protect R1
  2630. PUSHR R2 R15 ; Protect R2
  2631. CALLI R15 @mark_all_cells ; MARK_ALL_CELLS
  2632. LOADR R0 @all_symbols ; Using ALL_SYMBOLS
  2633. COPY R1 R0 ; Using it as STOP
  2634. FALSE R2 ; Setting Counter to 0
  2635. CALLI R15 @unmark_cells ; UNMARK ALL_SYMBOLS
  2636. LOADR R0 @top_env ; Using TOP_ENV
  2637. COPY R1 R0 ; Using it as STOP
  2638. FALSE R2 ; Setting Counter to 0
  2639. CALLI R15 @unmark_cells ; UNMARK TOP_ENV
  2640. CALLI R15 @reclaim_marked ; RECLAIM_MARKED
  2641. CALLI R15 @update_remaining ; Fix the Count
  2642. LOADR R0 @all_symbols ; Using Symbols list
  2643. CALLI R15 @compact ; Compact
  2644. LOADR R0 @top_env ; Using TOP_ENV
  2645. CALLI R15 @compact ; Compact
  2646. FALSE R0 ; Using NULL
  2647. STORER R0 @top_allocated ; Clear TOP_ALLOCATED
  2648. POPR R2 R15 ; Restore R
  2649. POPR R1 R15 ; Restore R1
  2650. POPR R0 R15 ; Restore R0
  2651. RET R15
  2652. ;; garbage_init
  2653. ;; Receives nothing
  2654. ;; Returns nothing
  2655. ;; Initializes Garbage Heap
  2656. :garbage_init
  2657. PUSHR R0 R15 ; Protect R0
  2658. PUSHR R1 R15 ; Protect R1
  2659. LOADR R0 @gc_block_start ; Get Starting Offset
  2660. ANDI R0 R0 0xF ; We only need the buttom 4 Bits
  2661. LOADR R1 @top_allocated ; Get End Address
  2662. ADD R1 R1 R0 ; Add the Offset
  2663. SUBUI R1 R1 16 ; Shift Back Down
  2664. STORER R1 @top_allocated ; Update Block End
  2665. CALLI R15 @mark_all_cells ; MARK_ALL_CELLS
  2666. CALLI R15 @reclaim_marked ; RECLAIM_MARKED
  2667. CALLI R15 @update_remaining ; Fix the Count
  2668. FALSE R0 ; Using NULL
  2669. STORER R0 @top_allocated ; Clear TOP_ALLOCATED
  2670. POPR R1 R15 ; Restore R1
  2671. POPR R0 R15 ; Restore R0
  2672. RET R15
  2673. ;; pop_cons
  2674. ;; Receives nothing
  2675. ;; Returns a Free CONS in R0
  2676. ;; Updates left_to_take
  2677. :pop_cons
  2678. PUSHR R1 R15 ; Protect R1
  2679. LOADR R0 @free_cells ; Get First Free Cell
  2680. JUMP.Z R0 @pop_cons_error ; If NULL BURN with FIRE
  2681. LOAD32 R1 R0 8 ; Get I->CDR
  2682. STORER R1 @free_cells ; Update FREE_CELLS
  2683. FALSE R1 ; Using NULL
  2684. STORE32 R1 R0 8 ; SET I->CDR to NULL
  2685. LOADR R1 @top_allocated ; Get top allocation
  2686. CMPSKIP.LE R0 R1 ; Skip if I <= TOP_ALLOCATED
  2687. STORER R0 @top_allocated ; Update TOP_ALLOCATED to new highest allocation
  2688. LOADR R1 @left_to_take ; Get LEFT_TO_TAKE
  2689. SUBUI R1 R1 1 ; Decrement by 1
  2690. STORER R1 @left_to_take ; Update LEFT_TO_TAKE
  2691. POPR R1 R15 ; Restore R1
  2692. RET R15
  2693. :pop_cons_error
  2694. LOADUI R0 $pop_cons_Message ; Using Message
  2695. FALSE R1 ; Using TTY
  2696. CALLI R15 @Print_String ; Display ERROR
  2697. HALT ; Burn with FIRE
  2698. :pop_cons_Message
  2699. "OOOPS we ran out of cells"
  2700. ;; make_int
  2701. ;; Receives an Integer in R0
  2702. ;; Returns a CELL in R0
  2703. :make_int
  2704. PUSHR R1 R15 ; Protect R1
  2705. MOVE R1 R0 ; Protect Integer
  2706. CALLI R15 @pop_cons ; Get a CELL
  2707. STORE32 R1 R0 4 ; Set C->CAR
  2708. LOADUI R1 4 ; Using INT
  2709. STORE32 R1 R0 0 ; Set C->TYPE
  2710. POPR R1 R15 ; Restore R1
  2711. RET R15
  2712. ;; make_char
  2713. ;; Receives a CHAR in R0
  2714. ;; Returns a CELL in R0
  2715. :make_char
  2716. PUSHR R1 R15 ; Protect R1
  2717. MOVE R1 R0 ; Protect Integer
  2718. CALLI R15 @pop_cons ; Get a CELL
  2719. STORE32 R1 R0 4 ; Set C->CAR
  2720. LOADUI R1 128 ; Using CHAR
  2721. STORE32 R1 R0 0 ; Set C->TYPE
  2722. POPR R1 R15 ; Restore R1
  2723. RET R15
  2724. ;; make_string
  2725. ;; Receives a string pointer in R0
  2726. ;; Returns a CELL in R0
  2727. :make_string
  2728. PUSHR R1 R15 ; Protect R1
  2729. MOVE R1 R0 ; Protect Integer
  2730. CALLI R15 @pop_cons ; Get a CELL
  2731. STORE32 R1 R0 4 ; Set C->CAR
  2732. LOADUI R1 256 ; Using STRING
  2733. STORE32 R1 R0 0 ; Set C->TYPE
  2734. POPR R1 R15 ; Restore R1
  2735. RET R15
  2736. ;; make_sym
  2737. ;; Receives a string pointer in R0
  2738. ;; Returns a Cell in R0
  2739. :make_sym
  2740. PUSHR R1 R15 ; Protect R1
  2741. MOVE R1 R0 ; Protect String Pointer
  2742. CALLI R15 @pop_cons ; Get a CELL
  2743. STORE32 R1 R0 4 ; Set C->CAR
  2744. LOADUI R1 8 ; Using SYM
  2745. STORE32 R1 R0 0 ; Set C->TYPE
  2746. POPR R1 R15 ; Restore R1
  2747. RET R15
  2748. ;; make_cons
  2749. ;; Receives a Cell in R0 and R1
  2750. ;; Returns a combined Cell in R0
  2751. :make_cons
  2752. PUSHR R2 R15 ; Protect R2
  2753. MOVE R2 R0 ; Protect CELL A
  2754. CALLI R15 @pop_cons ; Get a CELL
  2755. STORE32 R2 R0 4 ; Set C->CAR
  2756. STORE32 R1 R0 8 ; SET C->CDR
  2757. LOADUI R2 16 ; Using CONS
  2758. STORE32 R2 R0 0 ; Set C->TYPE
  2759. POPR R2 R15 ; Restore R2
  2760. RET R15
  2761. ;; make_proc
  2762. ;; Receives Cells in R0, R1 and R2
  2763. ;; Returns a combined Cell in R0
  2764. :make_proc
  2765. PUSHR R3 R15 ; Protect R3
  2766. MOVE R3 R0 ; Protect CELL
  2767. CALLI R15 @pop_cons ; Get a CELL
  2768. STORE32 R3 R0 4 ; Set C->CAR
  2769. STORE32 R1 R0 8 ; Set C->CDR
  2770. STORE32 R2 R0 12 ; Set C->ENV
  2771. LOADUI R3 32 ; Using PROC
  2772. STORE32 R3 R0 0 ; Set C->TYPE
  2773. POPR R3 R15 ; Restore R3
  2774. RET R15
  2775. ;; make_prim
  2776. ;; Receives pointer to function in R0
  2777. ;; Returns a Cell in R0
  2778. :make_prim
  2779. PUSHR R1 R15 ; Protect R1
  2780. MOVE R1 R0 ; Protect Function Pointer
  2781. CALLI R15 @pop_cons ; Get a CELL
  2782. STORE32 R1 R0 4 ; Set C->CAR
  2783. LOADUI R1 64 ; Using PRIMOP
  2784. STORE32 R1 R0 0 ; Set C->TYPE
  2785. POPR R1 R15 ; Restore R1
  2786. RET R15
  2787. ;; CONS starts at the end of the program
  2788. :Start_CONS