!!This version of ECCE, derived from a paper copy believed to !!date from 1975, removes PDP9/15 machine code, and other !!IMP9/15 system dependencies, and I'm hopeful that as a result !!it might well work if compiled with a generic Imp compiler. !!RWT Feb 2002 !!Code slightly rearranged to fit the model of Peter Stephen's Imp to C !!translator. This now compiles and runs exactly as on the pdp9/15 !!Remember to run it with redirected input, eg ecce < file.txt > file2.txt !!The I/O library currently assumes you are running on Unix. !!NOTE: There IS a bug in this implementation. Lines of more !!than 120 characters have a newline inserted at the 120th character !!on output. This *may* be an original bug rather than an artifact !!of the translation or run-time library.. !!GT 02 Mar 2002 external integer outstream owninteger in=1; !current input stream constinteger min=1; !main input stream constinteger mout=1; !main output stream constinteger sin=2; !secondary input stream constinteger sextra=122; !extra buff for sin constinteger size=30000; !of edit buffer (bytes) owninteger mon=0; !monitor indic owninteger print1=0,print2=0; !print indicators constinteger stop=-5000; !loop stop (const) integer i,j,k,pp1,sym integer code; !command code letter integer text; !text pointer integer num; !repetition number integername mainfp; ! == fp or mfp (for sin) constinteger cbase=1,tbase=120 ownintegerarray c(cbase:tbase); !command -> <- text ! each command unit -- letter, parenthesis or comma -- is ! represented by a trio: code(+lim) text num ! in the case of parentheses and commas 'text' is a pointer ! to another command unit (not to a text string) integer ci; !command index (ad) integer ti; !text index (ad) owninteger cmax=0; !command max (ad) integerarray stored(1:192); !defs of x,y,z owninteger pos1=0, pos2=0, pos3=0 byteintegerarray byte(1:size) owninteger top = 2; !top of buff (index) owninteger bot = size-sextra; !bottom of buff (index) integer lbeg; !line start (index) integer pp; !previous pointer (index) owninteger fp=0; !file pointer (index) integer lend; !line end (index) owninteger fend; !end of file in buff (index) owninteger ms=0; !match start (index) owninteger ml=0; !match limit (index) ! significance of file pointers: ! [nl] o n e nl t w . . . o nl n e x t nl . . nl l a s t nl [nl] ! ! ! ! ! ! ! ! t l p f l f ! o b p p e e ! p e n n ! g d d integer type,chain; !command input vars owninteger pend=0; !ditto routine prompt(string(1) s); ! Emulating pdp9/15 routine integer oldstream, c c = charno(s, 1) if c # 0 then start ; ! c = 0 is supposed to flush output on the 9/15 oldstream = outstream select output(0) print symbol(c) select output(oldstream) finish end routine load pp(integer k); !!!also increments pp byte(pp) = k; pp = pp+1 end routine load fp(integer k) byte(fp) = k end routine left star cycle return if pp = lbeg fp = fp-1; pp = pp-1 load fp(byte(pp)) repeat end routine right star cycle return if fp = lend load pp(byte(fp)) fp = fp+1 repeat end ownintegerarray symtype(33:95) = c 64, 3, 3, 3, 2, 3, 3,11, 9,64, 3,12, 2, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 3, 3, 3,64, 3, 2,10,18, 5, 8,52,10, 2, 6,10,10,10,56, 2, 2, 10,50,10,22, 5, 5, 6, 2,32,32,32, 3,10, 3, 3, 3 ! ! " # $ % & ' ( ) * + , - . / ! 0 1 2 3 4 5 6 7 8 9 : < = > ? ! @ A B C D E F G H I J K L M N O ! P Q R S T U V W X Y Z [ ¬ ] ^ _ routine read sym if pend # 0 then sym=pend and pend=0 else start while pos3 # 0 cycle sym = stored(pos3); pos3 = pos3+1 return unless sym = nl pos3 = pos2; pos2 = pos1; pos1 = 0 repeat read symbol(sym) finish end routine read item type = 1 cycle read sym until sym # ' ' return if sym < 32; !nl sym = sym-32 if sym >= 96; !ensure upper case type = symtype(sym) return unless type&15 = 0 exit unless type=32 pos1 = pos2; pos2 = pos3 pos3 = (sym-'X')<<6+1 repeat if type = 0 start num = sym-'0' cycle read symbol(pend) exit unless '0' <= pend <= '9' num = (num<<2+num)<<1-'0'+pend repeat finish else start type = 0 num = 0; return if sym = '*' num = stop+1; return if sym = '?' num = stop; ! '!' finish end routine unchain cycle text = chain; return if text = 0 chain = c(text+1); c(text+1) = ci repeat until c(text) = 'X' end routine stack(integer v) c(ci) = v; ci = ci+1 end routine make space integer k,p1,p2 return if mainfp-pp-240 > 0 select output(mout) p1 = top; p2 = (p1+lbeg)>>1; !output about half p2 = lbeg if code = 'C'; !but all if closing monitor and stop if p2 = top; !!!logical error cycle k = byte(p1); print symbol(k); p1 = p1+1 repeat until k = nl and p1-p2 >= 0 select output(0) lbeg = top+lbeg-p1; p2 = pp; pp = top cycle return if p1 = p2 load pp(byte(p1)); p1 = p1+1 repeat end routine read line integer k ! %on %event 9 %start ! ->eof ! %finish if fp # fend start lend = fp lend = lend+1 while byte(lend) # nl return finish ms = 0; print1 = 0; print2 = 0 select input(in) fp = bot-sextra+1 cycle if fp # bot then read symbol(k) else k = nl ->eof if k<0 load fp(k); fp = fp+1 repeat until k = nl fend = fp; lend = fend-1 fp = bot-sextra+1 select input(0) return eof:fp = bot; lend = fp; fend = lend load fp(nl) select input(0) end routine switch inputs owninteger mfp,mlend,mend,sfp,send if in = min start left star in = sin mfp = fp; mlend = lend; mend = fend mainfp == mfp bot = bot+sextra; fp = sfp; fend = send read line finish else start pp = lbeg in = min bot = bot-sextra; sfp = fp; send = fend fp = mfp; lend = mlend; fend = mend mainfp == fp finish end routine print line integer p print1 = lend; print2 = fp+pp p = lbeg cycle if p = pp start print symbol('^') if p # lbeg and num = 0 p = fp finish exit if p = lend print symbol(byte(p)) p = p+1 repeat print string("**END**") if p = fend newline end integerfn matched integer i,j,k,l,t1,fp1,lim lim = c(ci-3)&(¬127); t1 = c(text) L1: pp1 = pp; fp1 = fp ->L3 unless fp = ms and (code='F' or code='U') k = byte(fp) L2: load pp(k); fp = fp+1 L3: ->L10 if fp = lend k = byte(fp) ->L2 unless k = t1 i = fp; j = text L6: i = i+1; j = j-1 l = c(j) ->L6 if byte(i) = l ->L2 if l # 0 ms = fp; ml = i result = 1 L10: lim = lim-128 if lim # 0 and fp # fend start if code # 'U' start load pp(nl); lbeg = pp finish else pp = pp1 fp = fp+1; make space; read line ->L1 finish pp = pp1; fp = fp1 result = 0 end externalintegerfn main; !edit15: ecce for pdp9/15 !initialise switch t(0:12) switch s('A':'¬') !%on %event 9 %start ! printstring("Caught event"); newline ! ->eof !%finish select input(0) pp = top-1; load pp(nl); !for bouncing off lbeg = pp; mainfp == fp stored(1) = nl; stored(65) = nl; stored(129) = nl select output(0); print string("EDIT ") read line !read command line L1: prompt(">") read item; ->eof if sym<0; ->L1 if type = 1 ci = cbase; ti = tbase; chain = 0 if type = 0 and cmax # 0 start c(cmax+2) = num read item; ->er2 if type # 1 ->go finish if sym = '%' start read sym; sym = sym-32 if sym >= 96 code = sym; ->er5 if code<=32 read item ->t(symtype(code)>>4) finish L2: i = type&15; ->er2 if i < 4 code = sym; text = 0; num = 1; !default values read item ->t(i) t(2): !%x, %y, %z ->er1 if sym # '=' i = (code-'X')<<6 cycle read sym i = i+1; stored(i) = sym ->L1 if sym = nl repeat t(3): !%m, %f, %q mon = 'M'-code ->L1 t(4): !find num = 0 unless type = 0 t(5): !+del,trav,uncover code = num<<7+code; num = 1 read item if type = 0 t(6): !+insert,subst,verify ->er4 if type # 3 text = ti; i = sym L61: read sym if sym # nl start if sym # i start ->er6 if ti <= ci c(ti) = sym; ti = ti-1 ->L61 finish finish else start pend = sym ->er4 unless code = 'S' or code = 'I' finish ->er4 if ti = text and code # 'S' c(ti) = 0; ti = ti-1 ->L81 t(8): !move,erase ->L100 unless sym = '-' code = code+10 L81: read item ->L101 t(9): !close bracket unchain; ->er3 if text = 0 code = 'Z'; c(text+2) = num text = text+3 t(10): !+get,kill,etc. L100:->er1 if type = 3 L101:read item if type = 0 ->put t(11): !open bracket code = 'X' ->L121 t(12): !comma code = 'Y' read item if type = 1 L121:text = chain; chain = ci num = 0 put:stack(code); stack(text); stack(num) ->er6 if ci+4 >= ti ->L2 unless type = 1 unchain; ->er3 if text # 0 cmax = ci stack('Z'); stack(cbase); stack(1); !extra close b stack(0) ->go !command input error reports er1:space; print symbol(code) er2:code = sym ->er5 er3:print string(" ()") ->er7 er4:print string(" TEXT FOR") t(0): er5:space; print symbol(code&127) ->er7 er6:print string(" SIZE") er7:print symbol('?') newline; cmax = 0 if ci # cbase L10: ->L1 if sym<32 read sym ->L10 !execute command line go: ci = cbase get:code = c(ci)&127; ->L99 if code = 0 text = c(ci+1) num = c(ci+2) ci = ci+3 rep:num = num-1 ->s(code) ok: ->rep unless num = 0 or num = stop ->get s('¬'): !invert no: ->get if num < 0 ci = ci+3 and ->get if c(ci) = '¬' skp:i = c(ci); ci = c(ci+1) if i = 'X' ci = ci+3 num = c(ci-1)-1 and ->no if i > 'X' ->skp if i # 0 !execution error report print string("FAILURE: ") if code='O' or code='W' start print symbol(code-10); code = '-' finish print symbol(code) if text # 0 start print symbol('''') while c(text) # 0 cycle print symbol(c(text)) text = text-1 repeat print symbol('''') finish newline print1 = 0 !end of command line L99: ->L1 if sym # nl ->L1 unless (mon>=0 and print1#lend) or (mon>0 and print2#fp+pp) num = 0; print line ->L1 !individual commands s('X'): !open bracket c(text+2) = num+1 ->get s('Z'): !close bracket ->get if num = 0 or num = stop c(ci-1) = num s('Y'): !+comma ci = text ->get s('R'): !right shift ->no if fp = lend load pp(byte(fp)); fp = fp+1 ->ok s('L'): !left shift ->no if in = sin or pp = lbeg fp = fp-1; pp = pp-1; load fp(byte(pp)) ms = 0 ->ok s('E'): !erase ->no if fp = lend fp = fp+1 ->ok s('O'): !erase back ->no if pp = lbeg pp = pp-1 ->ok s('V'): !verify i = fp-1; j = text+1 v1: i = i+1; j = j-1 k = c(j) ->v1 if byte(i) = k ->no if k # 0 ms = fp; ml = i ->ok s('F'): !find ->no if matched = 0 ->ok s('U'): !uncover ->no if matched = 0; pp = pp1 ->ok s('D'): !delete ->no if matched = 0; fp = ml ->ok s('T'): !traverse ->no if matched = 0 s('S'): !+substitute fp = ml if fp = ms s('I'): !+insert make space !! ->no %if pp-lbeg+lend-fp > 80 i = text i1: ->ok if c(i) = 0 load pp(c(i)); i = i-1 ->i1 s('G'): !get (line from tt) prompt(":") !! make space read symbol(i) ->no if i = ':' left star while i # nl cycle load pp(i) read symbol(i) repeat s('B'): !+break (insert newline) make space load pp(nl); lbeg = pp ->ok s('P'): !print print line ->get if num = 0 s('M'): !+move right star ->no if fp = fend load pp(nl); lbeg = pp m1: fp = fp+1; make space; read line ->ok s('K'): !kill (line) pp = lbeg; fp = lend k1: ->no if fp = fend ->m1 s('J'): !join (delete newline) right star !! ->no %if pp-lbeg > 80 ->k1 s('W'): !move back ->no if in = sin make space ->no if lbeg = top lend = fp-pp+lbeg-1 w1: k = byte(pp-1) ->w2 if k = nl and pp # lbeg fp = fp-1; pp = pp-1; load fp(k) ->w1 w2: lbeg = pp; ms = 0 ->ok t(1): !%s, %c ... ->eof if code = 'C' switch inputs ->L99 eof:code = 'C'; !+eof on command stream switch inputs if in = sin cycle right star exit if fp = fend load pp(nl); lbeg = pp fp = fp+1; make space; read line repeat select output(mout) while top # pp cycle print symbol(byte(top)); top = top+1 repeat select output(0) if code # 'C' then monitor end endoffile