Basic: add read-file. Misc basicpp space savings.
authorJoel Martin <github@martintribe.org>
Mon, 24 Oct 2016 03:18:08 +0000 (22:18 -0500)
committerJoel Martin <github@martintribe.org>
Mon, 24 Oct 2016 03:18:08 +0000 (22:18 -0500)
- Add read-file which is similar to read-string but from a file name
  rather than a string. This allows steps 0-2 to load although each
  one eventuall crashes with out of memory after evaluating "123"
  a few times.
- basicpp:
    - Renumber the line numbers so they are ordinally increasing. This
      saves 150 or so bytes because GOTO/GOSUB calls have smaller line
      numbers.
    - Shrink 'IF 123' -> 'IF123' for almost 300 byte savings.[:w
    - Simplify PR_MEMORY_SUMMARY output. Save 75 bytes
- Add missing runtest.py change that allows basic tests to pass.

15 files changed:
basic/basicpp.py
basic/core.in.bas
basic/debug.in.bas
basic/reader.in.bas
basic/step4_if_fn_do.in.bas
basic/step5_tco.in.bas
basic/step6_file.in.bas
basic/step7_quote.in.bas
basic/step8_macros.in.bas
basic/step9_try.in.bas
basic/stepA_mal.in.bas
basic/types.in.bas
basic/variables.txt
core.mal
runtest.py

index 59d004f..fcfc864 100755 (executable)
@@ -81,7 +81,9 @@ def remove_indent(orig_lines):
 
 def misc_fixups(orig_lines):
     text = "\n".join(orig_lines)
-    text = re.sub(r"\bTHEN GOTO\b", r"THEN", text)
+    text = re.sub(r"\bTHEN GOTO\b", "THEN", text)
+    text = re.sub(r"\bPRINT \"", "PRINT\"", text)
+    text = re.sub(r"\bIF ", "IF", text)
     return text.split("\n")
 
 def finalize(lines, args):
@@ -103,47 +105,60 @@ def finalize(lines, args):
             lines.append("%s %s" % (lnum, line))
             lnum += 1
 
+    def update_labels_lines(text, a,b):
+        stext = ""
+        while stext != text:
+            stext = text
+            text = re.sub(r"(THEN) %s\b" % a, r"THEN %s" % b, stext)
+            #text = re.sub(r"(THEN)%s\b" % a, r"THEN%s" % b, stext)
+            text = re.sub(r"(ON [^:]* GOTO [^:\n]*)\b%s\b" % a, r"\g<1>%s" % b, text)
+            text = re.sub(r"(ON [^:]* GOSUB [^:\n]*)\b%s\b" % a, r"\g<2>%s" % b, text)
+            text = re.sub(r"(GOSUB) %s\b" % a, r"\1 %s" % b, text)
+            text = re.sub(r"(GOTO) %s\b" % a, r"\1 %s" % b, text)
+            #text = re.sub(r"(GOTO)%s\b" % a, r"\1%s" % b, text)
+        return text
+
     if not args.keep_labels:
         src_lines = lines
         text = "\n".join(lines)
         # search for and replace GOTO/GOSUBs
         for label, lnum in labels_lines.items():
-            stext = ""
-            while stext != text:
-                stext = text
-                text = re.sub(r"(THEN) %s\b" % label, r"THEN %s" % lnum, stext)
-                text = re.sub(r"(ON [^:]* GOTO [^:]*)\b%s\b" % label, r"\g<1>%s" % lnum, text)
-                text = re.sub(r"(ON [^:]* GOSUB [^:]*)\b%s\b" % label, r"\g<2>%s" % lnum, text)
-                text = re.sub(r"(GOSUB) %s\b" % label, r"\1 %s" % lnum, text)
-                text = re.sub(r"(GOTO) %s\b" % label, r"\1 %s" % lnum, text)
+            text = update_labels_lines(text, label, lnum)
         lines = text.split("\n")
 
     if args.combine_lines:
+        renumber = {}
         src_lines = lines
         lines = []
         pos = 0
         acc_line = ""
+        def renum(line):
+            lnum = len(lines)+1
+            renumber[old_num] = lnum
+            return "%s %s" % (lnum, line)
         while pos < len(src_lines):
             line = src_lines[pos]
             # TODO: handle args.keep_labels and (not args.number_lines)
             m = re.match(r"^([0-9]*) (.*)$", line)
-            lnum = int(m.group(1))
-            rest_line = m.group(2)
+            old_num = int(m.group(1))
+            line = m.group(2)
 
             if acc_line == "":
                 # Starting a new line
-                acc_line = line
-            elif lnum in lines_labels:
-                # This is a GOTO/GOSUB target line so it must be on
-                # a line by itself
+                acc_line = renum(line)
+            elif old_num in lines_labels or re.match(r"^ *FOR\b.*", line):
+                # This is a GOTO/GOSUB target or FOR loop so it must
+                # be on a line by itself
                 lines.append(acc_line)
-                acc_line = line
+                acc_line = renum(line)
             elif re.match(r".*\b(?:GOTO|THEN|RETURN)\b.*", acc_line):
+                # GOTO/THEN/RETURN are last thing on the line
                 lines.append(acc_line)
-                acc_line = line
-            elif len(acc_line) + 1 + len(rest_line) < 80:
+                acc_line = renum(line)
+            # TODO: not sure why this is 88 rather than 80
+            elif len(acc_line) + 1 + len(line) < 88:
                 # Continue building up the line
-                acc_line = acc_line + ":" + rest_line
+                acc_line = acc_line + ":" + line
                 # GOTO/IF/RETURN must be the last things on a line so
                 # start a new line
                 if re.match(r".*\b(?:GOTO|THEN|RETURN)\b.*", line):
@@ -152,11 +167,20 @@ def finalize(lines, args):
             else:
                 # Too long so start a new line
                 lines.append(acc_line)
-                acc_line = line
+                acc_line = renum(line)
             pos += 1
         if acc_line != "":
             lines.append(acc_line)
 
+        # Finally renumber GOTO/GOSUBS
+        src_lines = lines
+        text = "\n".join(lines)
+        # search for and replace GOTO/GOSUBs
+        for a in sorted(renumber.keys()):
+            b = renumber[a]
+            text = update_labels_lines(text, a, b)
+        lines = text.split("\n")
+
 
     return lines
 
index 3c4f242..0cff8dc 100644 (file)
@@ -9,7 +9,7 @@ DO_FUNCTION:
   R=Z%(AR,1)+1:GOSUB DEREF_R:AB=R
 
   REM Switch on the function number
-  IF FF>58 THEN ER=-1:ER$="unknown function"+STR$(FF):RETURN
+  IF FF>59 THEN ER=-1:ER$="unknown function"+STR$(FF):RETURN
   ON FF/10+1 GOTO DO_1_9,DO_10_19,DO_20_29,DO_30_39,DO_40_49,DO_50_59
 
   DO_1_9:
@@ -23,7 +23,7 @@ DO_FUNCTION:
   DO_40_49:
   ON FF-39 GOTO DO_CONS,DO_CONCAT,DO_NTH,DO_FIRST,DO_REST,DO_EMPTY_Q,DO_COUNT,DO_APPLY,DO_MAP,DO_THROW
   DO_50_59:
-  ON FF-49 GOTO DO_THROW,DO_WITH_META,DO_META,DO_ATOM,DO_ATOM_Q,DO_DEREF,DO_RESET_BANG,DO_SWAP_BANG,DO_EVAL
+  ON FF-49 GOTO DO_THROW,DO_WITH_META,DO_META,DO_ATOM,DO_ATOM_Q,DO_DEREF,DO_RESET_BANG,DO_SWAP_BANG,DO_EVAL,DO_READ_FILE
 
   DO_EQUAL_Q:
     A=AA:B=AB:GOSUB EQUAL_Q
@@ -448,6 +448,11 @@ DO_FUNCTION:
     A=AA:E=D:GOSUB EVAL
     RETURN
 
+  DO_READ_FILE:
+    A$=S$(Z%(AA,1))
+    GOSUB READ_FILE
+    RETURN
+
 INIT_CORE_SET_FUNCTION:
   GOSUB NATIVE_FUNCTION
   V=R:GOSUB ENV_SET_S
@@ -521,4 +526,6 @@ INIT_CORE_NS:
 
   K$="eval":A=58:GOSUB INIT_CORE_SET_FUNCTION
 
+  K$="read-file":A=59:GOSUB INIT_CORE_SET_FUNCTION
+
   RETURN
index cafc318..7f879e4 100644 (file)
@@ -14,15 +14,14 @@ CHECK_FREE_LIST:
     RETURN
 
 PR_MEMORY_SUMMARY:
-  GOSUB CHECK_FREE_LIST: REM get count in P2
   PRINT
-  PRINT "Free memory (FRE)      : "+STR$(FRE(0))
-  PRINT "Value memory (Z%)      : "+STR$(ZI-1)+" /"+STR$(Z1)
-  PRINT "                         ";
-  PRINT " used:"+STR$(ZI-1-P2)+", freed:"+STR$(P2);
-  PRINT ", post repl_env:"+STR$(ZT)
-  PRINT "String values (S$)    : "+STR$(S)+" /"+STR$(Z2)
-  PRINT "Call stack size (X%)  : "+STR$(X+1)+" /"+STR$(Z3)
+  PRINT "Free (FRE)   :"+STR$(FRE(0))
+  PRINT "Values (Z%)  :"+STR$(ZI-1)+" /"+STR$(Z1)
+  GOSUB CHECK_FREE_LIST: REM get count in P2
+  PRINT "               used:"+STR$(ZI-1-P2)+", freed:"+STR$(P2);
+  PRINT ", after repl_env:"+STR$(ZT)
+  PRINT "Strings (S$) :"+STR$(S)+" /"+STR$(Z2)
+  PRINT "Stack (X%)   :"+STR$(X+1)+" /"+STR$(Z3)
   RETURN
 
 REM REM PR_MEMORY(P1, P2) -> nil
index 2db435d..3779ea1 100644 (file)
@@ -1,42 +1,63 @@
-REM READ_TOKEN(A$, IDX) -> T$
+REM READ_TOKEN(A$, RI, RF) -> T$
 READ_TOKEN:
-  CUR=IDX
-  REM PRINT "READ_TOKEN: "+STR$(CUR)+", "+MID$(A$,CUR,1)
-  T$=MID$(A$,CUR,1)
+  RJ=RI
+  IF RF=1 THEN GOSUB READ_FILE_CHUNK
+  REM PRINT "READ_TOKEN: "+STR$(RJ)+", "+MID$(A$,RJ,1)
+  T$=MID$(A$,RJ,1)
   IF T$="(" OR T$=")" OR T$="[" OR T$="]" OR T$="{" OR T$="}" THEN RETURN
   IF T$="'" OR T$="`" OR T$="@" THEN RETURN
-  IF T$="~" AND NOT MID$(A$,CUR+1,1)="@" THEN RETURN
+  IF T$="~" AND NOT MID$(A$,RJ+1,1)="@" THEN RETURN
   S1=0:S2=0: REM S1: INSTRING?, S2: ESCAPED?
   IF T$=CHR$(34) THEN S1=1
-  CUR=CUR+1
+  RJ=RJ+1
   READ_TOKEN_LOOP:
-    IF CUR>LEN(A$) THEN RETURN
-    CH$=MID$(A$,CUR,1)
+    IF RF=1 THEN GOSUB READ_FILE_CHUNK
+    IF RJ>LEN(A$) THEN RETURN
+    CH$=MID$(A$,RJ,1)
     IF S2 THEN GOTO READ_TOKEN_CONT
     IF S1 THEN GOTO READ_TOKEN_CONT
     IF CH$=" " OR CH$="," THEN RETURN
+    IF CH$=" " OR CH$="," OR CH$=CHR$(13) OR CH$=CHR$(10) THEN RETURN
     IF CH$="(" OR CH$=")" OR CH$="[" OR CH$="]" OR CH$="{" OR CH$="}" THEN RETURN
     READ_TOKEN_CONT:
     T$=T$+CH$
     IF T$="~@" THEN RETURN
-    CUR=CUR+1
+    RJ=RJ+1
     IF S1 AND S2 THEN S2=0:GOTO READ_TOKEN_LOOP
     IF S1 AND S2=0 AND CH$=CHR$(92) THEN S2=1:GOTO READ_TOKEN_LOOP
     IF S1 AND S2=0 AND CH$=CHR$(34) THEN RETURN
     GOTO READ_TOKEN_LOOP
 
+READ_FILE_CHUNK:
+  IF RS=1 THEN RETURN
+  IF RI>1 THEN A$=MID$(A$,RI,LEN(A$)-RI+1):RI=1:RJ=RJ-RI+1
+  READ_FILE_CHUNK_LOOP:
+    IF LEN(A$)>RJ+9 THEN RETURN
+    GET#2,C$:A$=A$+C$
+    IF (ST AND 64) THEN RS=1:A$=A$+CHR$(10)+")":RETURN
+    IF (ST AND 255) THEN RS=1:ER=-1:ER$="File read error "+STR$(ST):RETURN
+    GOTO READ_FILE_CHUNK_LOOP
+
 SKIP_SPACES:
-  CH$=MID$(A$,IDX,1)
-  IF (CH$<>" ") AND (CH$<>",") AND (CH$<>CHR$(13)) AND (CH$<>CHR$(10)) THEN RETURN
-  IDX=IDX+1
+  IF RF=1 THEN GOSUB READ_FILE_CHUNK
+  CH$=MID$(A$,RI,1)
+  IF CH$<>" " AND CH$<>"," AND CH$<>CHR$(13) AND CH$<>CHR$(10) THEN RETURN
+  RI=RI+1
   GOTO SKIP_SPACES
 
+SKIP_TO_EOL:
+  IF RF=1 THEN GOSUB READ_FILE_CHUNK
+  CH$=MID$(A$,RI+1,1)
+  RI=RI+1
+  IF CH$="" OR CH$=CHR$(13) OR CH$=CHR$(10) THEN RETURN
+  GOTO SKIP_TO_EOL
+
 
 READ_ATOM:
   R=0
   RETURN
 
-REM READ_FORM(A$, IDX) -> R
+REM READ_FORM(A$, RI, RF) -> R
 READ_FORM:
   IF ER<>-2 THEN RETURN
   GOSUB SKIP_SPACES
@@ -55,7 +76,7 @@ READ_FORM:
   IF T$="@" THEN AS$="deref":GOTO READ_MACRO
   CH$=MID$(T$,1,1)
   REM PRINT "CH$: ["+CH$+"]("+STR$(ASC(CH$))+")"
-  IF (CH$=";") THEN R=0:GOTO READ_TO_EOL
+  IF (CH$=";") THEN R=0:GOSUB SKIP_TO_EOL:GOTO READ_FORM
   IF CH$>="0" AND CH$<="9" THEN GOTO READ_NUMBER
   IF CH$="-" THEN GOTO READ_SYMBOL_MAYBE
 
@@ -69,11 +90,6 @@ READ_FORM:
   IF CH$="}" THEN T=8:GOTO READ_SEQ_END
   GOTO READ_SYMBOL
 
-  READ_TO_EOL:
-    CH$=MID$(A$,IDX+1,1)
-    IDX=IDX+1
-    IF CH$="" OR CH$=CHR$(13) OR CH$=CHR$(10) THEN GOTO READ_FORM
-    GOTO READ_TO_EOL
   READ_NIL_BOOL:
     REM PRINT "READ_NIL_BOOL"
     R=T
@@ -84,7 +100,7 @@ READ_FORM:
     T=2:L=VAL(T$):GOSUB ALLOC
     GOTO READ_FORM_DONE
   READ_MACRO:
-    IDX=IDX+LEN(T$)
+    RI=RI+LEN(T$)
     REM to call READ_FORM recursively, SD needs to be saved, set to
     REM 0 for the call and then restored afterwards.
     X=X+2:X%(X-1)=(T$="^"):X%(X)=SD: REM push macro type and SD
@@ -156,7 +172,7 @@ READ_FORM:
     X=X+1
     X%(X)=R
 
-    IDX=IDX+LEN(T$)
+    RI=RI+LEN(T$)
     GOTO READ_FORM
 
   READ_SEQ_END:
@@ -171,7 +187,7 @@ READ_FORM:
 
 
   READ_FORM_DONE:
-    IDX=IDX+LEN(T$)
+    RI=RI+LEN(T$)
 
     T8=R: REM save previous value
 
@@ -211,7 +227,21 @@ READ_FORM:
 
 REM READ_STR(A$) -> R
 READ_STR:
-  IDX=1
+  RI=1: REM index into A$
+  RF=0: REM not reading from file
   SD=0: REM sequence read depth
   GOSUB READ_FORM
   RETURN
+
+REM READ_FILE(A$) -> R
+READ_FILE:
+  RI=1: REM index into A$
+  RJ=1: REM READ_TOKEN sub-index
+  RF=1: REM reading from file
+  RS=0: REM file read state (1: EOF)
+  SD=0: REM sequence read depth
+  OPEN 2,8,0,A$
+  REM READ_FILE_CHUNK adds terminating ")"
+  A$="(do ":GOSUB READ_FORM
+  CLOSE 2
+  RETURN
index 0421f8a..ed61505 100755 (executable)
@@ -337,11 +337,11 @@ RE:
   R1=0
   GOSUB MAL_READ
   R1=R
-  IF ER<>-2 THEN GOTO REP_DONE
+  IF ER<>-2 THEN GOTO RE_DONE
 
   A=R:E=D:GOSUB EVAL
 
-  REP_DONE:
+  RE_DONE:
     REM Release memory from MAL_READ
     IF R1<>0 THEN AY=R1:GOSUB RELEASE
     RETURN: REM caller must release result of EVAL
index 8ddce07..cc96817 100755 (executable)
@@ -346,11 +346,11 @@ RE:
   R1=0
   GOSUB MAL_READ
   R1=R
-  IF ER<>-2 THEN GOTO REP_DONE
+  IF ER<>-2 THEN GOTO RE_DONE
 
   A=R:E=D:GOSUB EVAL
 
-  REP_DONE:
+  RE_DONE:
     REM Release memory from MAL_READ
     IF R1<>0 THEN AY=R1:GOSUB RELEASE
     RETURN: REM caller must release result of EVAL
index aed3b60..d06e168 100755 (executable)
@@ -346,11 +346,11 @@ RE:
   R1=0
   GOSUB MAL_READ
   R1=R
-  IF ER<>-2 THEN GOTO REP_DONE
+  IF ER<>-2 THEN GOTO RE_DONE
 
   A=R:E=D:GOSUB EVAL
 
-  REP_DONE:
+  RE_DONE:
     REM Release memory from MAL_READ
     IF R1<>0 THEN AY=R1:GOSUB RELEASE
     RETURN: REM caller must release result of EVAL
@@ -395,8 +395,7 @@ MAIN:
   A$="(def! not (fn* (a) (if a false true)))"
   GOSUB RE:AY=R:GOSUB RELEASE
 
-  A$="(def! load-file (fn* (f) (eval (read-string (str "
-  A$=A$+CHR$(34)+"(do "+CHR$(34)+" (slurp f) "+CHR$(34)+")"+CHR$(34)+")))))"
+  A$="(def! load-file (fn* (f) (eval (read-file f))))"
   GOSUB RE:AY=R:GOSUB RELEASE
 
   REM load the args file
index 7bf085b..80aab03 100755 (executable)
@@ -436,11 +436,11 @@ RE:
   R1=0
   GOSUB MAL_READ
   R1=R
-  IF ER<>-2 THEN GOTO REP_DONE
+  IF ER<>-2 THEN GOTO RE_DONE
 
   A=R:E=D:GOSUB EVAL
 
-  REP_DONE:
+  RE_DONE:
     REM Release memory from MAL_READ
     IF R1<>0 THEN AY=R1:GOSUB RELEASE
     RETURN: REM caller must release result of EVAL
@@ -485,8 +485,7 @@ MAIN:
   A$="(def! not (fn* (a) (if a false true)))"
   GOSUB RE:AY=R:GOSUB RELEASE
 
-  A$="(def! load-file (fn* (f) (eval (read-string (str "
-  A$=A$+CHR$(34)+"(do "+CHR$(34)+" (slurp f) "+CHR$(34)+")"+CHR$(34)+")))))"
+  A$="(def! load-file (fn* (f) (eval (read-file f))))"
   GOSUB RE:AY=R:GOSUB RELEASE
 
   REM load the args file
index 8674115..0b52a43 100755 (executable)
@@ -505,11 +505,11 @@ RE:
   R1=0
   GOSUB MAL_READ
   R1=R
-  IF ER<>-2 THEN GOTO REP_DONE
+  IF ER<>-2 THEN GOTO RE_DONE
 
   A=R:E=D:GOSUB EVAL
 
-  REP_DONE:
+  RE_DONE:
     REM Release memory from MAL_READ
     IF R1<>0 THEN AY=R1:GOSUB RELEASE
     RETURN: REM caller must release result of EVAL
@@ -554,8 +554,7 @@ MAIN:
   A$="(def! not (fn* (a) (if a false true)))"
   GOSUB RE:AY=R:GOSUB RELEASE
 
-  A$="(def! load-file (fn* (f) (eval (read-string (str "
-  A$=A$+CHR$(34)+"(do "+CHR$(34)+" (slurp f) "+CHR$(34)+")"+CHR$(34)+")))))"
+  A$="(def! load-file (fn* (f) (eval (read-file f))))"
   GOSUB RE:AY=R:GOSUB RELEASE
 
   A$="(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs)"
index a7c50cc..024ebf0 100755 (executable)
@@ -537,11 +537,11 @@ RE:
   R1=0
   GOSUB MAL_READ
   R1=R
-  IF ER<>-2 THEN GOTO REP_DONE
+  IF ER<>-2 THEN GOTO RE_DONE
 
   A=R:E=D:GOSUB EVAL
 
-  REP_DONE:
+  RE_DONE:
     REM Release memory from MAL_READ
     IF R1<>0 THEN AY=R1:GOSUB RELEASE
     RETURN: REM caller must release result of EVAL
@@ -586,8 +586,7 @@ MAIN:
   A$="(def! not (fn* (a) (if a false true)))"
   GOSUB RE:AY=R:GOSUB RELEASE
 
-  A$="(def! load-file (fn* (f) (eval (read-string (str "
-  A$=A$+CHR$(34)+"(do "+CHR$(34)+" (slurp f) "+CHR$(34)+")"+CHR$(34)+")))))"
+  A$="(def! load-file (fn* (f) (eval (read-file f))))"
   GOSUB RE:AY=R:GOSUB RELEASE
 
   A$="(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs)"
index c953e5f..b5b5b57 100755 (executable)
@@ -537,11 +537,11 @@ RE:
   R1=0
   GOSUB MAL_READ
   R1=R
-  IF ER<>-2 THEN GOTO REP_DONE
+  IF ER<>-2 THEN GOTO RE_DONE
 
   A=R:E=D:GOSUB EVAL
 
-  REP_DONE:
+  RE_DONE:
     REM Release memory from MAL_READ
     IF R1<>0 THEN AY=R1:GOSUB RELEASE
     RETURN: REM caller must release result of EVAL
@@ -589,8 +589,7 @@ MAIN:
   A$="(def! not (fn* (a) (if a false true)))"
   GOSUB RE:AY=R:GOSUB RELEASE
 
-  A$="(def! load-file (fn* (f) (eval (read-string (str "
-  A$=A$+CHR$(34)+"(do "+CHR$(34)+" (slurp f) "+CHR$(34)+")"+CHR$(34)+")))))"
+  A$="(def! load-file (fn* (f) (eval (read-file f))))"
   GOSUB RE:AY=R:GOSUB RELEASE
 
   A$="(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs)"
index 174406d..bc3483c 100644 (file)
@@ -27,7 +27,7 @@ REM                    14  ->  Z% index of metdata object
 INIT_MEMORY:
   T=FRE(0)
 
-  Z1=2048+512: REM Z% (boxed memory) size (4 bytes each)
+  Z1=2048+1024: REM Z% (boxed memory) size (4 bytes each)
   Z2=256: REM S$ (string memory) size (3 bytes each)
   Z3=256: REM X% (call stack) size (2 bytes each)
   Z4=64: REM Y% (release stack) size (4 bytes each)
index ade67d6..c64e68b 100644 (file)
@@ -23,7 +23,8 @@ BI  : ENV_NEW_BINDS binds list
 EX  : ENV_NEW_BINDS expressions list
 LV  : EVAL stack call level/depth
 
-IDX : reader current string position
+RI  : reader current string position
+RJ  : READ_TOKEN current character index
 
 
 Calling arguments/temporaries:
@@ -45,15 +46,10 @@ R   : common return value
 T   : common temp, type
 V   : hash map value
 
-A0  : EVAL ast elements
-A1  : EVAL ast elements
-A2  : EVAL ast elements
-A3  : EVAL ast elements
 B1  : LIST2/LIST3 param
 B2  : LIST2/LIST3 param
 B3  : LIST3 param
 CZ  : DO_CONCAT stack position
-CUR : READ_TOKEN current character index
 EF  : ENV_FIND cur env ptr
 P1  : PR_MEMORY, CHECK_FREE_LIST start
 P2  : PR_MEMORY, CHECK_FREE_LIST end
@@ -61,9 +57,34 @@ SZ  : size argument to ALLOC
 
 Reused/temporaries:
 
+A0  : EVAL ast elements
+A1  : EVAL ast elements
+A2  : EVAL ast elements
+A3  : EVAL ast elements
+CH$ : READ_TOKEN, SKIP_SPACES, SKIP_TO_EOL current character
 I   : STRING, REPLACE, SLICE, PR_MEMORY, PR_OBJECT
 J   : REPLACE
+S1  : READ_TOKEN in a string?
+S2  : READ_TOKEN escaped?
+T$  : READ_* current token string
+T1$ : HASHMAP_GET temp
+T2$ : HASHMAP_GET temp
+T1  : PR_STR, and core DO_KEYS_VALS temp
+T2  :
+T3  :
+T4  :
+T5  :
+T6  :
+T7  : READ_FORM and PR_STR temp
+T8  :
+T9  :
+TA  :
+U1  :
+U2  :
+U3  :
+U4  :
+U6  :
 
 Unused:
 
-G, L, M, N, Q, U, W
+G, Q, U, W
index ae9ec63..368805f 100644 (file)
--- a/core.mal
+++ b/core.mal
@@ -84,3 +84,4 @@
             (list form x))
           `(->> (->> ~x ~form) ~@more))))))
 
+nil
index 71ff268..eee1fcc 100755 (executable)
@@ -127,6 +127,7 @@ class Runner():
                     self.buf += new_data.replace("\n", "\r\n")
                 else:
                     self.buf += new_data
+                self.buf = self.buf.replace("\r\r", "\r")
                 for prompt in prompts:
                     regexp = re.compile(prompt)
                     match = regexp.search(self.buf)