Thread View: alt.lang.teco
2 messages
2 total messages
Started by Dale R. Worley
Wed, 19 Jun 1991 22:51
Teco for Gnu Emacs!
Author: Dale R. Worley
Date: Wed, 19 Jun 1991 22:51
Date: Wed, 19 Jun 1991 22:51
1915 lines
56220 bytes
56220 bytes
Having gotten tired of not having Teco, I coded up this version for
Gnu Emacs. There are probably a zillion bugs. Happy hacking!
Dale
;;; Teco interpreter for Gnu Emacs, version 1.
(require 'backquote)
(provide 'teco)
;; This code has been tested some, but no doubt contains a zillion bugs.
;; You have been warned.
;; Written by Dale R. Worley based on a C implementation by Matt Fichtenbaum.
;; Please send comments, bug fixes, enhancements, etc. to drw@math.mit.edu.
;; Emacs Lisp version copyright (C) 1991 by Dale R. Worley.
;; Do what you will with it.
;; Since much of this code is translated from the C version by
;; Matt Fichtenbaum, I include his copyright notice:
;; TECO for Ultrix. Copyright 1986 Matt Fichtenbaum.
;; This program and its components belong to GenRad Inc, Concord MA 01742.
;; They may be copied if this copyright notice is included.
;; To invoke directly, do:
;; (global-set-key ?\C-z 'teco:command)
;; (autoload teco:command "teco"
;; "Read and execute a Teco command string."
;; t nil)
;; Differences from other Tecos:
;; Character positions in the buffer are numbered in the Emacs way: The first
;; character is numbered 1 (or (point-min) if narrowing is in effect). The
;; B command returns that number.
;; Ends of lines are represented by a single character (newline), so C and R
;; skip over them, rather than 2C and 2R.
;; All file I/O is left to the underlying Emacs. Thus, almost all Ex commands
;; are omitted.
;; Command set:
;; NUL Not a command.
;; ^A Output message to terminal (argument ends with ^A)
;; ^C Exit macro
;; ^C^C Stop execution
;; ^D Set radix to decimal
;; ^EA (match char) Match alphabetics
;; ^EC (match char) Match symbol constituents
;; ^ED (match char) Match numerics
;; ^EGq (match char) Match any char in q-reg
;; ^EL (match char) Match line terminators
;; ^EQq (string char) Use contents of q-reg
;; ^ER (match char) Match alphanumerics
;; ^ES (match char) Match non-null space/tab
;; ^EV (match char) Match lower case alphabetic
;; ^EW (match char) Match upper case alphabetic
;; ^EX (match char) Match any char
;; ^G^G (type-in) Kill command string
;; ^G<sp> (type-in) Retype current command line
;; ^G* (type-in) Retype current command input
;; TAB Insert tab and text
;; LF Line terminator; Ignored in commands
;; VT Ignored in commands
;; FF Ignored in commands
;; CR Ignored in commands
;; ^Nx (match char) Match all but x
;; ^O Set radix to octal
;; ^P Find matching parenthesis
;; ^Q Convert line argument into character argument
;; ^Qx (string char) Use x literally
;; n^R Set radix to n
;; :^R Enter recursive edit
;; ^S -(length of last referenced string)
;; ^S (match char) match separator char
;; ^T Ascii value of next character typed
;; n^T Output Ascii character with value n
;; ^U (type-in) Kill command line
;; ^Uq Put text argument into q-reg
;; n^Uq Put Ascii character 'n' into q-reg
;; :^Uq Append text argument to q-reg
;; n:^Uq Append character 'n' to q-reg
;; ^X Set/get search mode flag
;; ^X (match char) Match any character
;; ^Y Equivalent to '.+^S,.'
;; ^Z Not a Teco command
;; ESC String terminator; absorbs arguments
;; ESC ESC (type-in) End command
;; ^\ Not a Teco command
;; ^] Not a Teco command
;; ^^x Ascii value of the character x
;; ^_ One's complement (logical NOT)
;; ! Define label (argument ends with !)
;; " Start conditional
;; n"< Test for less than zero
;; n"> Test for greater than zero
;; n"= Test for equal to zero
;; n"A Test for alphabetic
;; n"C Test for symbol constituent
;; n"D Test for numeric
;; n"E Test for equal to zero
;; n"F Test for false
;; n"G Test for greater than zero
;; n"L Test for less than zero
;; n"N Test for not equal to zero
;; n"R Test for alphanumeric
;; n"S Test for successful
;; n"T Test for true
;; n"U Test for unsuccessful
;; n"V Test for lower case
;; n"W Test for upper case
;; # Logical OR
;; $ Not a Teco command
;; n%q Add n to q-reg and return result
;; & Logical AND
;; ' End conditional
;; ( Expression grouping
;; ) Expression grouping
;; * Multiplication
;; + Addition
;; , Argument separator
;; - Subtraction or negation
;; . Current pointer position
;; / Division
;; 0-9 Digit
;; n< Iterate n times
;; = Type in decimal
;; := Type in decimal, no newline
;; = Type in octal
;; := Type in octal, no newline
;; = Type in hexadecimal
;; := Type in hexadecimal, no newline
;; :: Make next search a compare
;; > End iteration
;; n:A Get Ascii code of character at relative position n
;; B Character position of beginning of buffer
;; nC Advance n characters
;; nD Delete n characters
;; n,mD Delete characters between n and m
;; Gq Get string from q-reg into buffer
;; :Gq Type out q-reg
;; H Equivalent to 'B,Z'
;; I Insert text argument
;; nJ Move pointer to character n
;; nK Kill n lines
;; n,mK Kill characters between n and m
;; nL Advance n lines
;; Mq Execute string in q-reg
;; O Goto label
;; nO Go to n-th label in list (0-origin)
;; Qq Number in q-reg
;; nQq Ascii value of n-th character in q-reg
;; :Qq Size of text in q-reg
;; nR Back up n characters
;; nS Search
;; nT Type n lines
;; n,mT Type chars from n to m
;; nUq Put number n into q-reg
;; nV Type n lines around pointer
;; nXq Put n lines into q-reg
;; n,mXq Put characters from n to m into q-reg
;; n:Xq Append n lines to q-reg q
;; n,m:Xq Append characters from n to m into q-reg
;; Z Pointer position at end of buffer
;; [q Put q-reg on stack
;; \ Value of digit string in buffer
;; n\ Convert n to digits and insert in buffer
;; ]q Pop q-reg from stack
;; :]q Test whether stack is empty and return value
;; ` Not a Teco command
;; a-z Treated the same as A-Z
;; { Not a Teco command
;; | Conditional 'else'
;; } Not a Teco comand
;; ~ Not a Teco command
;; DEL Delete last character typed in
;; set a range of elements of an array to a value
(defun teco:set-elements (array start end value)
(let ((i start))
(while (<= i end)
(aset array i value)
(setq i (1+ i)))))
;; set a range of elements of an array to their indexes plus an offset
(defun teco:set-elements-index (array start end offset)
(let ((i start))
(while (<= i end)
(aset array i (+ i offset))
(setq i (1+ i)))))
(defvar teco:command-string ""
"The current command string being executed.")
(defvar teco:command-pointer nil
"Pointer into teco:command-string showing next character to be executed.")
(defvar teco:ctrl-r 10
"Current number radix.")
(defvar teco:digit-switch nil
"Set if we have just executed a digit.")
(defvar teco:exp-exp nil
"Expression value preceeding operator.")
(defvar teco:exp-val1 nil
"Current argument value.")
(defvar teco:exp-val2 nil
"Argument before comma.")
(defvar teco:exp-flag1 nil
"t if argument is present.")
(defvar teco:exp-flag2 nil
"t if argument before comma is present.")
(defvar teco:exp-op nil
"Pending arithmetic operation on argument.")
(defvar teco:exp-stack nil
"Stack for parenthesized expressions.")
(defvar teco:macro-stack nil
"Stack for macro invocations.")
(defvar teco:mapch-l nil
"Translation table to lower-case letters.")
(setq teco:mapch-l (make-vector 256 0))
(teco:set-elements-index teco:mapch-l 0 255 0)
(teco:set-elements-index teco:mapch-l ?A ?Z (- ?a ?A))
(defvar teco:trace nil
"t if tracing is on.")
(defvar teco:at-flag nil
"t if an @ flag is pending.")
(defvar teco:colon-flag nil
"1 if a : flag is pending, 2 if a :: flag is pending.")
(defvar teco:qspec-valid nil
"Flags describing whether a character is a vaid q-register name.
3 means yes, 2 means yes but only for file and search operations.")
(setq teco:qspec-valid (make-vector 256 0))
(teco:set-elements teco:qspec-valid ?a ?z 3)
(teco:set-elements teco:qspec-valid ?0 ?9 3)
(aset teco:qspec-valid ?_ 2)
(aset teco:qspec-valid ?* 2)
(aset teco:qspec-valid ?% 2)
(aset teco:qspec-valid ?# 2)
(defvar teco:exec-flags 0
"Flags for iteration in process, ei macro, etc.")
(defvar teco:iteration-stack nil
"Iteration list.")
(defvar teco:cond-stack nil
"Conditional stack.")
(defvar teco:qreg-text (make-vector 256 "")
"The text contents of the q-registers.")
(defvar teco:qreg-number (make-vector 256 0)
"The number contents of the q-registers.")
(defvar teco:qreg-stack nil
"The stack of saved q-registers.")
(defconst teco:prompt "*"
"*Prompt to be used when inputting Teco command.")
(defconst teco:exec-1 (make-vector 256 nil)
"Names of routines handling type 1 characters (characters that are
part of expression processing).")
(defconst teco:exec-2 (make-vector 256 nil)
"Names of routines handling type 2 characters (characters that are
not part of expression processing).")
(defvar teco:last-search-string ""
"Last string searched for.")
(defvar teco:last-search-regexp ""
"Regexp version of teco:last-search-string.")
(defmacro teco:define-type-1 (char &rest body)
"Define the code to process a type 1 character.
Transforms
(teco:define-type-1 ?x
code ...)
into
(defun teco:type-1-x ()
code ...)
and does
(aset teco:exec-1 ?x 'teco:type-1-x)"
(let ((s (intern (concat "teco:type-1-" (char-to-string char)))))
(` (progn
(defun (, s) ()
(,@ body))
(aset teco:exec-1 (, char) '(, s))))))
(defmacro teco:define-type-2 (char &rest body)
"Define the code to process a type 2 character.
Transforms
(teco:define-type-2 ?x
code ...)
into
(defun teco:type-2-x ()
code ...)
and does
(aset teco:exec-2 ?x 'teco:type-2-x)"
(let ((s (intern (concat "teco:type-2-" (char-to-string char)))))
(` (progn
(defun (, s) ()
(,@ body))
(aset teco:exec-2 (, char) '(, s))))))
(defconst teco:char-types (make-vector 256 0)
"Define the characteristics of characters, as tested by \":
1 alphabetic
2 alphabetic, $, or .
4 digit
8 alphabetic or digit
16 lower-case alphabetic
32 upper-case alphabetic")
(teco:set-elements teco:char-types ?0 ?9 (+ 4 8))
(teco:set-elements teco:char-types ?A ?Z (+ 1 2 8 32))
(teco:set-elements teco:char-types ?a ?z (+ 1 2 8 16))
(aset teco:char-types ?$ 2)
(aset teco:char-types ?. 2)
(defconst teco:error-texts '(("BNI" . "> not in iteration")
("CPQ" . "Can't pop Q register")
("COF" . "Can't open output file ")
("FNF" . "File not found ")
("IEC" . "Invalid E character")
("IFC" . "Invalid F character")
("IIA" . "Invalid insert arg")
("ILL" . "Invalid command")
("ILN" . "Invalid number")
("IPA" . "Invalid P arg")
("IQC" . "Invalid \" character")
("IQN" . "Invalid Q-reg name")
("IRA" . "Invalid radix arg")
("ISA" . "Invalid search arg")
("ISS" . "Invalid search string")
("IUC" . "Invalid ^ character")
("LNF" . "Label not found")
("MEM" . "Insufficient memory available")
("MRP" . "Missing )")
("NAB" . "No arg before ^_")
("NAC" . "No arg before ,")
("NAE" . "No arg before =")
("NAP" . "No arg before )")
("NAQ" . "No arg before \"")
("NAS" . "No arg before ;")
("NAU" . "No arg before U")
("NFI" . "No file for input")
("NFO" . "No file for output")
("NYA" . "Numeric arg with Y")
("OFO" . "Output file already open")
("PDO" . "Pushdown list overflow")
("POP" . "Pointer off page")
("SNI" . "; not in iteration")
("SRH" . "Search failure ")
("STL" . "String too long")
("UTC" . "Unterminated command")
("UTM" . "Unterminated macro")
("XAB" . "Execution interrupted")
("YCA" . "Y command suppressed")
("IWA" . "Invalid W arg")
("NFR" . "Numeric arg with FR")
("INT" . "Internal error")
("EFI" . "EOF read from std input")
("IAA" . "Invalid A arg")
))
(defconst teco:spec-chars
[
0 1 0 0 ; ^@ ^A ^B ^C
0 64 0 0 ; ^D ^E ^F ^G
0 2 128 128 ; ^H ^I ^J ^K
128 0 64 0 ; ^L ^M ^N ^O
0 64 64 64 ; ^P ^Q ^R ^S
0 34 0 0 ; ^T ^U ^V ^W
64 0 0 0 ; ^X ^Y ^Z ^\[
0 0 1 0 ; ^\ ^\] ^^ ^_
0 1 16 0 ; ! \" #
0 0 0 16 ; $ % & '
0 0 0 0 ; \( \) * +
0 0 0 0 ; , - . /
0 0 0 0 ; 0 1 2 3
0 0 0 0 ; 4 5 6 7
0 0 0 0 ; 8 9 : ;
16 0 16 0 ; < = > ?
1 0 12 0 ; @ A B C
0 1 1 32 ; D E F G
0 6 0 0 ; H I J K
0 32 10 2 ; L M N O
0 32 4 10 ; P Q R S
0 32 0 4 ; T U V W
32 0 0 32 ; X Y Z \[
0 32 1 6 ; \ \] ^ _
0 0 12 0 ; ` a b c
0 1 1 32 ; d e f g
0 6 0 0 ; h i j k
0 32 10 2 ; l m n o
0 32 4 10 ; p q r s
0 32 0 4 ; t u v w
32 0 0 0 ; x y z {
16 0 0 0 ; | } ~ DEL
]
"The special properties of characters:
1 skipto() special character
2 command with std text argument
4 E<char> takes a text argument
8 F<char> takes a text argument
16 char causes skipto() to exit
32 command with q-register argument
64 special char in search string
128 character is a line separator")
(defun teco:execute-command (string)
"Execute teco command string."
;; Initialize everything
(let ((teco:command-string string)
(teco:command-pointer 0)
(teco:digit-switch nil)
(teco:exp-exp nil)
(teco:exp-val1 nil)
(teco:exp-val2 nil)
(teco:exp-flag1 nil)
(teco:exp-flag2 nil)
(teco:exp-op 'start)
(teco:trace nil)
(teco:at-flag nil)
(teco:colon-flag nil)
(teco:exec-flags 0)
(teco:iteration-stack nil)
(teco:cond-stack nil)
(teco:exp-stack nil)
(teco:macro-stack nil)
(teco:qreg-stack nil))
;; initialize output
(teco:out-init)
;; execute commands
(catch 'teco:exit
(while t
;; get next command character
(let ((cmdc (teco:get-command0 teco:trace)))
;; if it's ^, interpret the next character as a control character
(if (eq cmdc ?^)
(setq cmdc (logand (teco:get-command teco:trace) 31)))
(if (and (<= ?0 cmdc) (<= cmdc ?9))
;; process a number
(progn
(setq cmdc (- cmdc ?0))
;; check for invalid digit
(if (>= cmdc teco:ctrl-r)
(teco:error "ILN"))
(if teco:digit-switch
;; later digits
(setq teco:exp-val1 (+ (* teco:exp-val1 teco:ctrl-r) cmdc))
;; first digit
(setq teco:exp-val1 cmdc)
(setq teco:digit-switch t))
;; indicate a value was read in
(setq teco:exp-flag1 t))
;; not a digit
(setq teco:digit-switch nil)
;; cannonicalize the case
(setq cmdc (aref teco:mapch-l cmdc))
;; dispatch on the character, if it is a type 1 character
(let ((r (aref teco:exec-1 cmdc)))
(if r
(funcall r)
;; if a value has been entered, process any pending operation
(if teco:exp-flag1
(cond ((eq teco:exp-op 'start)
nil)
((eq teco:exp-op 'add)
(setq teco:exp-val1 (+ teco:exp-exp teco:exp-val1))
(setq teco:exp-op 'start))
((eq teco:exp-op 'sub)
(setq teco:exp-val1 (- teco:exp-exp teco:exp-val1))
(setq teco:exp-op 'start))
((eq teco:exp-op 'mult)
(setq teco:exp-val1 (* teco:exp-exp teco:exp-val1))
(setq teco:exp-op 'start))
((eq teco:exp-op 'div)
(setq teco:exp-val1
(if (/= teco:exp-val1 0)
(/ teco:exp-exp teco:exp-val1)
0))
(setq teco:exp-op 'start))
((eq teco:exp-op 'and)
(setq teco:exp-val1
(logand teco:exp-exp teco:exp-val1))
(setq teco:exp-op 'start))
((eq teco:exp-op 'or)
(setq teco:exp-val1
(logior teco:exp-exp teco:exp-val1))
(setq teco:exp-op 'start))))
;; dispatch on a type 2 character
(let ((r (aref teco:exec-2 cmdc)))
(if r
(funcall r)
(teco:error "ILL")))))))))))
;; Type 1 commands
(teco:define-type-1
?\m ; CR
nil)
(teco:define-type-1
?\n ; LF
nil)
(teco:define-type-1
?\^k ; VT
nil)
(teco:define-type-1
?\^l ; FF
nil)
(teco:define-type-1
32 ; SPC
nil)
(teco:define-type-1
?\e ; ESC
(if (teco:peek-command ?\e)
;; ESC ESC terminates macro or command
(teco:pop-macro-stack)
;; otherwise, consume argument
(setq teco:exp-flag1 nil)
(setq teco:exp-op 'start)))
(teco:define-type-1
?! ; !
(while (/= (teco:get-command teco:trace) ?!)
nil))
(teco:define-type-1
?@ ; @
;; set at-flag
(setq teco:at-flag t))
(teco:define-type-1
?: ; :
;; is it '::'?
(if (teco:peek-command ?:)
(progn
;; skip second colon
(teco:get-command teco:trace)
;; set flag to show two colons
(setq teco:colon-flag 2))
;; set flag to show one colon
(setq teco:colon-flag 1)))
(teco:define-type-1
?? ; ?
;; toggle trace
(setq teco:trace (not teco:trace)))
(teco:define-type-1
?. ; .
;; value is point
(setq teco:exp-val1 (point)
teco:exp-flag1 t))
(teco:define-type-1
?z ; z
;; value is point-max
(setq teco:exp-val1 (point-max)
teco:exp-flag1 t))
(teco:define-type-1
?b ; b
;; value is point-min
(setq teco:exp-val1 (point-min)
teco:exp-flag1 t))
(teco:define-type-1
?h ; h
;; value is b,z
(setq teco:exp-val1 (point-max)
teco:exp-val2 (point-min)
teco:exp-flag1 t
teco:exp-flag2 t
teco:exp-op 'start))
(teco:define-type-1
?\^s ; ^s
;; value is - length of last insert, etc.
(setq teco:exp-val1 teco:ctrl-s
teco:exp-flag1 t))
(teco:define-type-1
?\^y ; ^y
;; value is .+^S,.
(setq teco:exp-val1 (+ (point) teco:ctrl-s)
teco:exp-val2 (point)
teco:exp-flag1 t
teco:exp-flag2 t
teco:exp-op 'start))
(teco:define-type-1
?\( ; \(
;; push expression stack
(teco:push-exp-stack)
(setq teco:exp-flag1 nil
teco:exp-flag2 nil
teco:exp-op 'start))
(teco:define-type-1
?\^p ; ^p
(teco:do-ctrl-p))
(teco:define-type-1
?\C-^ ; ^^
;; get next command character
(setq teco:exp-val1 (teco:get-command teco:trace)
teco:exp-flag1 t))
;; Type 2 commands
(teco:define-type-2
?+ ; +
(setq teco:exp-exp (if teco:exp-flag1 teco:exp-val1 0)
teco:exp-flag1 nil
teco:exp-op 'add))
(teco:define-type-2
?- ; -
(setq teco:exp-exp (if teco:exp-flag1 teco:exp-val1 0)
teco:exp-flag1 nil
teco:exp-op 'sub))
(teco:define-type-2
?* ; *
(setq teco:exp-exp (if teco:exp-flag1 teco:exp-val1 0)
teco:exp-flag1 nil
teco:exp-op 'mult))
(teco:define-type-2
?/ ; /
(setq teco:exp-exp (if teco:exp-flag1 teco:exp-val1 0)
teco:exp-flag1 nil
teco:exp-op 'div))
(teco:define-type-2
?& ; &
(setq teco:exp-exp (if teco:exp-flag1 teco:exp-val1 0)
teco:exp-flag1 nil
teco:exp-op 'and))
(teco:define-type-2
?# ; #
(setq teco:exp-exp (if teco:exp-flag1 teco:exp-val1 0)
teco:exp-flag1 nil
teco:exp-op 'or))
(teco:define-type-2
?\) ; \)
(if (or (not teco:exp-flag1) (not teco:exp-stack))
(teco:error "NAP"))
(let ((v teco:exp-val1))
(teco:pop-exp-stack)
(setq teco:exp-val1 v
teco:exp-flag1 t)))
(teco:define-type-2
?, ; ,
(if (not teco:exp-flag1)
(teco:error "NAC"))
(setq teco:exp-val2 teco:exp-val1
teco:exp-flag2 t
teco:exp-flag1 nil))
(teco:define-type-2
?\^_ ; ^_
(if (not teco:exp-flag1)
(teco:error "NAB")
(setq teco:exp-val1 (lognot teco:exp-val1))))
(teco:define-type-2
?\^d ; ^d
(setq teco:ctrl-r 10
teco:exp-flag1 nil
teco:exp-op 'start))
(teco:define-type-2
?\^o ; ^o
(setq teco:ctrl-r 8
teco:exp-flag1 nil
teco:exp-op 'start))
(teco:define-type-2
?\^r ; ^r
(if teco:colon-flag
(progn
(recursive-edit)
(setq teco:colon-flag nil))
(if teco:exp-flag1
;; set radix
(progn
(if (and (/= teco:exp-val1 8)
(/= teco:exp-val1 10)
(/= teco:exp-val1 16))
(teco:error "IRA"))
(setq teco:ctrl-r teco:exp-val1
teco:exp-flag1 nil
teco:exp-op 'start))
;; get radix
(setq teco:exp-val1 teco:ctrl-r
teco:exp-flag1 t))))
(teco:define-type-2
?\^c ; ^c
(if (teco:peek-command ?\^c)
;; ^C^C stops execution
(throw 'teco:exit nil)
(if teco:macro-stack
;; ^C inside macro exits macro
(teco:pop-macro-stack)
;; ^C in command stops execution
(throw 'teco:exit nil))))
(teco:define-type-2
?\^x ; ^x
;; set/get search mode flag
(teco:set-var 'teco:ctrl-x))
(teco:define-type-2
?m ; m
(let ((macro-name (teco:get-qspec nil
(teco:get-command teco:trace))))
(teco:push-macro-stack)
(setq teco:command-string (aref teco:qreg-text macro-name)
teco:command-pointer 0)))
(teco:define-type-2
?< ; <
;; begin iteration
(if (and teco:exp-flag1 (<= teco:exp-val1 0))
;; if this is not to be executed, just skip the
;; intervening stuff
(teco:find-enditer)
;; push iteration stack
(teco:push-iter-stack teco:command-pointer
teco:exp-flag1 teco:exp-val1)
;; consume the argument
(setq teco:exp-flag1 nil)))
(teco:define-type-2
?> ; >
;; end iteration
(if (not teco:iteration-stack)
(teco:error "BNI"))
;; decrement count and pop conditionally
(teco:pop-iter-stack nil)
;; consume arguments
(setq teco:exp-flag1 nil
teco:exp-flag2 nil
teco:exp-op 'start))
(teco:define-type-2
59 ; ;
;; semicolon iteration exit
(if (not teco:iteration-stack)
(teco:error "SNI"))
;; if exit
(if (if (>= (if teco:exp-flag1
teco:exp-val1
teco:search-result) 0)
(not teco:colon-flag)
teco:colon-flag)
(progn
(teco:find-enditer)
(teco:pop-iter-stack t)))
;; consume argument and colon
(setq teco:exp-flag1 nil
teco:colon-flag nil
teco:exp-op 'start))
(teco:define-type-2
?\" ; \"
;; must be an argument
(if (not teco:exp-flag1)
(teco:error "NAQ"))
;; consume argument
(setq teco:exp-flag1 nil
teco:exp-op 'start)
(let* (;; get the test specification
(c (aref teco:mapch-l (teco:get-command teco:trace)))
;; determine whether the test is true
(test (cond ((eq c ?a)
(/= (logand (aref teco:char-types teco:exp-val1)
1) 0))
((eq c ?c)
(/= (logand (aref teco:char-types teco:exp-val1)
2) 0))
((eq c ?d)
(/= (logand (aref teco:char-types teco:exp-val1)
4) 0))
((or (eq c ?e) (eq c ?f) (eq c ?u) (eq c ?=))
(= teco:exp-val1 0))
((or (eq c ?g) (eq c ?>))
(> teco:exp-val1 0))
((or (eq c ?l) (eq c ?s) (eq c ?t) (eq c ?<))
(< teco:exp-val1 0))
((eq c ?n)
(/= teco:exp-val1 0))
((eq c ?r)
(/= (logand (aref teco:char-types teco:exp-val1)
8) 0))
((eq c ?v)
(/= (logand (aref teco:char-types teco:exp-val1)
16) 0))
((eq c ?w)
(/= (logand (aref teco:char-types teco:exp-val1)
32) 0))
(t
(teco:error "IQC")))))
(if (not test)
;; if the conditional isn't satisfied, read
;; to matching | or '
(let ((ll 1)
c)
(while (> ll 0)
(while (progn (setq c (teco:skipto))
(and (/= c ?\")
(/= c ?|)
(/= c ?\')))
(if (= c ?\")
(setq ll (1+ ll))
(if (= c ?\')
(setq ll (1- ll))
(if (= ll 1)
(break))))))))))
(teco:define-type-2
?' ; '
;; ignore it if executing
t)
(teco:define-type-2
?| ; |
(let ((ll 1)
c)
(while (> ll 0)
(while (progn (setq c (teco:skipto))
(and (/= c ?\")
(/= c ?\')))
nil)
(if (= c ?\")
(setq ll (1+ ll))
(setq ll (1- ll))))))
(teco:define-type-2
?u ; u
(if (not teco:exp-flag1)
(teco:error "NAU"))
(aset teco:qreg-number
(teco:get-qspec 0 (teco:get-command teco:trace))
teco:exp-val1)
(setq teco:exp-flag1 teco:exp-flag2 ; command's value is second arg
teco:exp-val1 teco:exp-val2
teco:exp-flag2 nil
teco:exp-op 'start))
(teco:define-type-2
?q ; q
;; Qn is numeric val, :Qn is # of chars, mQn is mth char
(let ((mm (teco:get-qspec (or teco:colon-flag teco:exp-flag1)
(teco:get-command teco:trace))))
(if (not teco:exp-flag1)
(setq teco:exp-val1 (if teco:colon-flag
;; :Qn
(length (aref teco:qreg-text mm))
;; Qn
(aref teco:qreg-number mm))
teco:exp-flag1 t)
;; mQn
(let ((v (aref teco:qreg-text mm)))
(setq teco:exp-val1 (condition-case nil
(aref v teco:exp-val1)
(error -1))
teco:exp-op 'start)))
(setq teco:colon-flag nil)))
(teco:define-type-2
?% ; %
(let* ((mm (teco:get-qspec nil (teco:get-command teco:trace)))
(v (+ (aref teco:qreg-number mm) (teco:get-value 1))))
(aset teco:qreg-number mm v)
(setq teco:exp-val1 v
teco:exp-flag1 t)))
(teco:define-type-2
?c ; c
(let ((p (+ (point) (teco:get-value 1))))
(if (or (< p (point-min)) (> p (point-max)))
(teco:error "POP")
(goto-char p)
(setq teco:exp-flag2 nil))))
(teco:define-type-2
?r ; r
(let ((p (- (point) (teco:get-value 1))))
(if (or (< p (point-min)) (> p (point-max)))
(teco:error "POP")
(goto-char p)
(setq teco:exp-flag2 nil))))
(teco:define-type-2
?j ; j
(let ((p (teco:get-value (point-min))))
(if (or (< p (point-min)) (> p (point-max)))
(teco:error "POP")
(goto-char p)
(setq teco:exp-flag2 nil))))
(teco:define-type-2
?l ; l
;; move forward by lines
(forward-char (teco:lines (teco:get-value 1))))
(teco:define-type-2
?\C-q ; ^q
;; number of characters until the nth line feed
(setq teco:exp-val1 (teco:lines (teco:get-value 1))
teco:exp-flag1 t))
(teco:define-type-2
?= ; =
;; print numeric value
(if (not teco:exp-flag1)
(teco:error "NAE"))
(teco:output (format
(if (teco:peek-command ?=)
;; at least one more =
(progn
;; read past it
(teco:get-command teco:trace)
(if (teco:peek-command ?=)
;; another?
(progn
;; read it too
(teco:get-command teco:trace)
;; print in hex
"%x")
;; print in octal
"%o"))
;; print in decimal
"%d")
teco:exp-val1))
;; add newline if no colon
(if (not teco:colon-flag)
(teco:output ?\n))
;; absorb argument, etc.
(setq teco:exp-flag1 nil
teco:exp-flag2 nil
teco:colon-flag nil
teco:exp-op 'start))
(teco:define-type-2
?\t ; TAB
(if exp-flag1
(teco:error "IIA"))
(let ((text (teco:get-text-arg)))
(insert ?\t text)
(setq teco:ctrl-s (1+ (length text))))
;; clear arguments
(setq teco:colon-flag nil
teco:exp-flag1 nil
teco:exp-flag2 nil))
(teco:define-type-2
?i ; i
(let ((text (teco:get-text-arg)))
(if teco:exp-flag1
;; if a nI$ command
(progn
;; text argument must be null
(or (string-equal text "") (teco:error "IIA"))
;; insert the character
(insert teco:exp-val1)
(setq teco:ctrl-s 1)
;; consume argument
(setq teco:exp-op 'start))
;; otherwise, insert the text
(insert text)
(setq teco:ctrl-s (length text)))
;; clear arguments
(setq teco:colon-flag nil
teco:exp-flag1 nil
teco:exp-flag2 nil)))
(teco:define-type-2
?t ; t
(let ((args (teco:line-args nil)))
(teco:output (buffer-substring (car args) (cdr args)))))
(teco:define-type-2
?v ; v
(let ((ll (teco:get-value 1)))
(teco:output (buffer-substring (+ (point) (teco:lines (- 1 ll)))
(+ (point) (teco:lines ll))))))
(teco:define-type-2
?\C-a ; ^a
(teco:output (teco:get-text-arg nil ?\C-a))
(setq teco:at-flag nil
teco:colon-flag nil
teco:exp-flag1 nil
teco:exp-flag2 nil
teco:exp-op 'start))
(teco:define-type-2
?d ; d
(if (not teco:exp-flag2)
;; if only one argument
(delete-char (teco:get-value 1))
;; if two arguments, treat as n,mK
(let ((ll (teco:line-args 1)))
(delete-region (car ll) (cdr ll)))))
(teco:define-type-2
?k ; k
(let ((ll (teco:line-args 1)))
(delete-region (car ll) (cdr ll))))
(teco:define-type-2
?\C-u ; ^u
(let* ((mm (teco:get-qspec nil (teco:get-command teco:trace)))
(text-arg (teco:get-text-arg))
(text (if (not teco:exp-flag1)
text-arg
(if (string-equal text-arg "")
(char-to-string teco:exp-val1)
(teco:error "IIA")))))
;; if :, append to the register
(aset teco:qreg-text mm (if teco:colon-flag
(concat (aref teco:qreg-text mm) text)
text))
;; clear various flags
(setq teco:exp-flag1 nil
teco:at-flag nil
teco:colon-flag nil
teco:exp-flag1 nil)))
(teco:define-type-2
?x ; x
(let* ((mm (teco:get-qspec nil (teco:get-command teco:trace)))
(args (teco:line-args 0))
(text (buffer-substring (car args) (cdr args))))
;; if :, append to the register
(aset teco:qreg-text mm (if teco:colon-flag
(concat (aref teco:qreg-text mm) text)
text))
;; clear various flags
(setq teco:exp-flag1 nil
teco:at-flag nil
teco:colon-flag nil
teco:exp-flag1 nil)))
(teco:define-type-2
?g ; g
(let ((mm (teco:get-qspec t (teco:get-command teco:trace))))
(if teco:colon-flag
(teco:output (aref teco:qreg-text mm))
(insert (aref teco:qreg-text mm)))
(setq teco:colon-flag nil)))
(teco:define-type-2
?\[ ; \[
(let ((mm (teco:get-qspec t (teco:get-command teco:trace))))
(setq teco:qreg-stack
(cons (cons (aref teco:qreg-text mm)
(aref teco:qreg-number mm))
teco:qreg-stack))))
(teco:define-type-2
?\] ; \]
(let ((mm (teco:get-qspec t (teco:get-command teco:trace))))
(if teco:colon-flag
(setq teco:exp-flag1 t
teco:exp-val1 (if teco:qreg-stack -1 0))
(if teco:qreg-stack
(let ((pop (car teco:qreg-stack)))
(aset teco:qreg-text mm (car pop))
(aset teco:qreg-number mm (cdr pop))
(setq teco:qreg-stack (cdr teco:qreg-stack)))
(teco:error "CPQ")))
(setq teco:colon-flag nil)))
(teco:define-type-2
?\\ ; \
(if (not teco:exp-flag1)
;; no argument; read number
(let ((p (point))
(sign +1)
(n 0)
c)
(setq c (char-after p))
(if c
(if (= c ?+)
(setq p (1+ p))
(if (= c ?-)
(setq p (1+ p)
sign -1))))
(cond
((= teco:ctrl-r 8)
(while (progn
(setq c (char-after p))
(and c (>= c ?0) (<= c ?7)))
(setq p (1+ p)
n (+ c -48 (* n 8)))))
((= teco:ctrl-r 10)
(while (progn
(setq c (char-after p))
(and c (>= c ?0) (<= c ?9)))
(setq p (1+ p)
n (+ c -48 (* n 10)))))
(t
(while (progn
(setq c (char-after p))
(and c
(or
(and (>= c ?0) (<= c ?9))
(and (>= c ?a) (<= c ?f))
(and (>= c ?A) (<= c ?F)))))
(setq p (1+ p)
n (+ c (if (> c ?F)
;; convert 'a' to 10
-87
(if (> c ?9)
;; convert 'A' to 10
-55
;; convert '0' to 0
-48))
(* n 16))))))
(setq teco:exp-val1 (* n sign)
teco:exp-flag1 t
teco:ctrl-s (- (point) p)))
;; argument: insert it as a digit string
(insert (format (cond
((= teco:ctrl-r 8) "%o")
((= teco:ctrl-r 10) "%d")
(t "%x"))
teco:exp-val1))
(setq teco:exp-flag1 nil
teco:exp-op 'start)))
(teco:define-type-2
?\C-t ; ^t
(if teco:exp-flag1
;; type a character
(progn
(teco:output teco:exp-val1)
(setq teco:exp-flag1 nil))
;; input a character
(let* ((echo-keystrokes 0)
(c (read-char)))
(teco:output c)
(setq teco:exp-val1 c
teco:exp-flag1 t))))
(teco:define-type-2
?s ; s
(let ((arg (teco:get-text-arg))
(count (if teco:exp-flag1 teco:expr-val1 1))
regexp)
(if (not (string-equal arg ""))
(setq regexp (teco:parse-search-string arg)
teco:last-search-string arg
teco:last-search-regexp regexp)
(setq regexp (teco:last-search-regexp)
arg teco:last-search-string))
(let ((p (point))
(result (cond
((> count 0)
(re-search-forward regexp nil t count))
((< count 0)
(re-search-backward regexp nil t count))
(t
;; 0s always is successful
t))))
;; if ::s, restore point
(if (eq teco:colon-flag 2)
(goto-char p))
;; if no real or implied colon, error if not found
(if (and (not result)
(not teco:colon-flag)
(/= (teco:peekcmdc) 34))
(teco:error "SRH"))
;; set return results
(setq teco:exp-flag2 nil
teco:colon-flag nil
teco:at-flag nil
teco:exp-op 'start)
(if teco:colon-flag
(setq teco:exp-flag1 t
teco:exp-val1 (if result -1 0))
(setq teco:exp-flag1 nil)))))
(defun teco:parse-search-string (s)
(let ((i 0)
(l (length s))
(r "")
c)
(while (< i l)
(setq r (concat r (teco:parse-search-string-1))))
r))
(defun teco:parse-search-string-1 ()
(if (>= i l)
(teco:error "ISS"))
(setq c (aref s i))
(setq i (1+ i))
(cond
((eq c ?\C-e) ; ^E - special match characters
(teco:parse-search-string-e))
((eq c ?\C-n) ; ^Nx - match all but x
(teco:parse-search-string-n))
((eq c ?\C-q) ; ^Qx - use x literally
(teco:parse-search-string-q))
((eq c ?\C-s) ; ^S - match separator chars
"[^A-Za-z0-9]")
((eq c ?\C-x) ; ^X - match any character
"[\000-\377]")
(t ; ordinary character
(teco:parse-search-string-char c))))
(defun teco:parse-search-string-char (c)
(regexp-quote (char-to-string c)))
(defun teco:parse-search-string-q ()
(if (>= i l)
(teco:error "ISS"))
(setq c (aref s i))
(setq i (1+ i))
(teco:parse-search-string-char c))
(defun teco:parse-search-string-e ()
(if (>= i l)
(teco:error "ISS"))
(setq c (aref s i))
(setq i (1+ i))
(cond
((or (eq c ?a) (eq c ?A)) ; ^EA - match alphabetics
"[A-Za-z]")
((or (eq c ?c) (eq c ?C)) ; ^EC - match symbol constituents
"[A-Za-z.$]")
((or (eq c ?d) (eq c ?D)) ; ^ED - match numerics
"[0-9]")
((eq c ?g) ; ^EGq - match any char in q-reg
(teco:parse-search-string-e-g))
((or (eq c ?l) (eq c ?L)) ; ^EL - match line terminators
"[\012\013\014]")
((eq c ?q) ; ^EQq - use contents of q-reg
(teco:parse-search-string-e-q))
((eq c ?r) ; ^ER - match alphanumerics
"[A-Za-z0-9]")
((eq c ?s) ; ^ES - match non-null space/tab seq
"[ \t]+")
((eq c ?v) ; ^EV - match lower case alphabetic
"[a-z]")
((eq c ?w) ; ^EW - match upper case alphabetic
"[A-Z]")
((eq c ?x) ; ^EX - match any character
"[\000-\377]")
(t
(teco:error "ISS"))))
(defun teco:parse-search-string-e-q ()
(if (>= i l)
(teco:error "ISS"))
(setq c (aref s i))
(setq i (1+ i))
(regexp-quote (aref reco:q-reg-text c)))
(defun teco:parse-search-string-e-g ()
(if (>= i l)
(teco:error "ISS"))
(setq c (aref s i))
(setq i (1+ i))
(let* ((q (aref teco:qreg-text c))
(len (length q))
(null (= len 0))
(one-char (= len 1))
(dash-present (string-match "-" q))
(caret-present (string-match "\\^" q))
(outbracket-present (string-match "]" q))
p)
(cond
(null
"[^\000-\377]")
(one-char
(teco:parse-search-string-char c))
(t
(while (setq p (string-match "^]\\^"))
(setq q (concat (substring q 1 p) (substring q (1+ p)))))
(concat
"["
(if outbracket-present "]" "")
(if dash-present "---" "")
q
(if caret-present "^" ""))))))
(defun teco:parse-search-string-n ()
(let ((p (teco:parse-search-string-1)))
(cond
((= (aref p 0) ?\[)
(if (= (aref p 1) ?^)
;; complement character set
(if (= (length p) 4)
;; complement of one character
(teco:parse-search-string-char (aref p 2))
;; complement of more than one character
(concat "[" (substring p 2)))
;; character set - invert it
(concat "[^" (substring p 1))))
((= (aref p 0) ?\\)
;; single quoted character
(concat "[^" (substring p 1) "]"))
(t
;; single character
(if (string-equal p "-")
"[^---]"
(concat "[^" p "]"))))))
(teco:define-type-2
?o ; o
(let ((label (teco:get-text-arg))
(index (and teco:exp-flag1 teco:exp-val1)))
(setq teco:exp-flag1 nil)
;; handle computed goto by extracting the proper label
(if index
(if (< index 0)
;; argument < 0 is a noop
(setq label "")
;; otherwise, find the n-th label (0-origin)
(setq label (concat label ","))
(let ((p 0))
(while (and (> index 0)
(setq p (string-match "," label p))
(setq p (1+ p)))
(setq index (1- index)))
(setq q (string-match "," label p))
(setq label (substring label p q)))))
;; if the label is non-null, find the correct label
;; start from beginning of iteration or macro, and look for tag
(setq teco:command-pointer
(if teco:iteration-stack
;; if in iteration, start at beginning of iteration
(aref (car teco:iteration-stack) 0)
;; if not in iteration, start at beginning of command or macro
0))
;; search for tag
(catch 'label
(let ((level 0)
c p l)
;; look for interesting things, including !
(while t
(setq c (teco:skipto t))
(cond
((= c ?<) ; start of iteration
(setq level (1+ level)))
((= c ?>) ; end of iteration
(if (= level 0)
(teco:pop-iter-stack t)
(setq level (1- level))))
((= c ?!) ; start of tag
(setq p (string-match "!" teco:command-string teco:command-pointer))
(if (and p
(string-equal label (substring teco:command-string
teco:command-pointer
p)))
(progn
(setq teco:command-pointer (1+ p))
(throw 'label nil))))))))))
(teco:define-type-2
?a ; :a
;; 'a' must be used as ':a'
(if (and teco:exp-flag1 teco:colon-flag)
(let ((char (+ (point) teco:exp-val1)))
(setq teco:exp-val1
(if (and (>= char (point-min))
(< char (point-max)))
(char-after char)
-1)
teco:colon-flag nil))
(teco:error "ILL")))
;; Routines to get next character from command buffer
;; getcmdc0, when reading beyond command string, pops
;; macro stack and continues.
;; getcmdc, in similar circumstances, reports an error.
;; If pushcmdc() has returned any chars, read them first
;; routines type characters as read, if argument != 0.
(defun teco:get-command0 (trace)
;; get the next character
(let (char)
(while (not (condition-case nil
(setq char (aref teco:command-string teco:command-pointer))
;; if we've exhausted the string, pop the macro stack
;; if we exhaust the macro stack, exit
(error (teco:pop-macro-stack)
nil))))
;; bump the command pointer
(setq teco:command-pointer (1+ teco:command-pointer))
;; trace, if requested
(and trace (teco:trace-type char))
;; return the character
char))
;; while (cptr.dot >= cptr.z) /* if at end of this level, pop macro stack
;; {
;; if (--msp < &mstack[0]) /* pop stack; if top level
;; {
;; msp = &mstack[0]; /* restore stack pointer
;; cmdc = ESC; /* return an ESC (ignored)
;; exitflag = 1; /* set to terminate execution
;; return(cmdc); /* exit "while" and return
;; }
;; }
;; cmdc = cptr.p->ch[cptr.c++]; /* get char
;; ++cptr.dot; /* increment character count
;; if (trace) type_char(cmdc); /* trace
;; if (cptr.c > CELLSIZE-1) /* and chain if need be
;; {
;; cptr.p = cptr.p->f;
;; cptr.c = 0;
;; }
;; return(cmdc);
;; }
(defun teco:get-command (trace)
;; get the next character
(let ((char (condition-case nil
(aref teco:command-string teco:command-pointer)
;; if we've exhausted the string, give error
(error
(teco:error (if teco:macro-stack "UTM" "UTC"))))))
;; bump the command pointer
(setq teco:command-pointer (1+ teco:command-pointer))
;; trace, if requested
(and trace (teco:trace-type char))
;; return the character
char))
;; char getcmdc(trace)
;; {
;; if (cptr.dot++ >= cptr.z) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM);
;; else
;; {
;; cmdc = cptr.p->ch[cptr.c++]; /* get char
;; if (trace) type_char(cmdc); /* trace
;; if (cptr.c > CELLSIZE-1) /* and chain if need be
;; {
;; cptr.p = cptr.p->f;
;; cptr.c = 0;
;; }
;; }
;; return(cmdc);
;; }
;; peek at next char in command string, return 1 if it is equal
;; (case independent) to argument
(defun teco:peek-command (arg)
(condition-case nil
(eq (aref teco:mapch-l (aref teco:command-string teco:command-pointer))
(aref teco:mapch-l arg))
(error nil)))
;; int peekcmdc(arg)
;; char arg;
;; {
;; return(((cptr.dot < cptr.z) && (mapch_l[cptr.p->ch[cptr.c]] == mapch_l[arg])) ? 1 : 0);
;; }
(defun teco:get-text-arg (&optional term-char default-term-char)
;; figure out what the terminating character is
(setq teco:term-char (or term-char
(if teco:at-flag
(teco:get-command teco:trace)
(or default-term-char
?\e)))
teco:at_flag nil)
(let ((s "")
c)
(while (progn
(setq c (teco:get-command teco:trace))
(/= c teco:term-char))
(setq s (concat s (char-to-string c))))
s))
;; Routines to manipulate the stacks
;; Pop the macro stack. Throw to 'teco:exit' if the stack is empty.
(defun teco:pop-macro-stack ()
(if teco:macro-stack
(let ((frame (car teco:macro-stack)))
(setq teco:macro-stack (cdr teco:macro-stack)
teco:command-string (aref frame 0)
teco:command-pointer (aref frame 1)
teco:exec-flags (aref frame 2)
teco:iteration-stack (aref frame 3)
teco:cond-stack (aref frame 4)))
(throw 'teco:exit nil)))
;; Push the macro stack.
(defun teco:push-macro-stack ()
(setq teco:macro-stack
(cons (vector teco:command-string
teco:command-pointer
teco:exec-flags
teco:iteration-stack
teco:cond-stack)
teco:macro-stack)))
;; Pop the expression stack.
(defun teco:pop-exp-stack ()
(let ((frame (car teco:exp-stack)))
(setq teco:exp-stack (cdr teco:exp-stack)
teco:exp-val1 (aref frame 0)
teco:exp-flag1 (aref frame 1)
teco:exp-val2 (aref frame 2)
teco:exp-flag2 (aref frame 3)
teco:exp-exp (aref frame 4)
teco:exp-op (aref frame 5))))
;; Push the expression stack.
(defun teco:push-exp-stack ()
(setq teco:exp-stack
(cons (vector teco:exp-val1
teco:exp-flag1
teco:exp-val2
teco:exp-flag2
teco:exp-exp
teco:exp-op)
teco:exp-stack)))
;; Pop the iteration stack
;; if arg t, exit unconditionally
;; else check exit conditions and exit or reiterate
(defun teco:pop-iter-stack (arg)
(let ((frame (car teco:iteration-stack)))
(if (or arg
(not (aref frame 1))
;; test against 1, since one iteration has already been done
(<= (aref frame 2) 1))
;; exit iteration
(setq teco:iteration-stack (cdr teco:iteration-stack))
;; continue with iteration
;; decrement count
(aset frame 2 (1- (aref frame 2)))
;; reset command pointer
(setq teco:command-pointer (aref frame 0)))))
;; Push the iteration stack
(defun teco:push-iter-stack (pointer flag count)
(setq teco:iteration-stack
(cons (vector pointer
flag
count)
teco:iteration-stack)))
(defun teco:find-enditer ()
(let ((icnt 1)
c)
(while (> icnt 0)
(while (progn (setq c (teco:skipto))
(and (/= c ?<)
(/= c ?>)))
(if (= c ?<)
(setq icnt (1+ icnt))
(setq icnt (1- icnt)))))))
;; I/O routines
(defvar teco:output-buffer (get-buffer-create "*Teco Output*")
"The buffer into which Teco output is written.")
(defun teco:out-init ()
;; Recreate the teco output buffer, if necessary
(setq teco:output-buffer (get-buffer-create "*Teco Output*"))
(save-excursion
(set-buffer teco:output-buffer)
;; get a fresh line in output buffer
(goto-char (point-max))
(insert ?\n)
;; remember where to start displaying
(setq teco:output-start (point))
;; clear minibuffer, in case we have to display in it
(save-window-excursion
(select-window (minibuffer-window))
(erase-buffer))
;; if output is visible, position it correctly
(let ((w (get-buffer-window teco:output-buffer)))
(if w
(progn
(set-window-start w teco:output-start)
(set-window-point w teco:output-start))))))
(defun teco:output (s)
(let ((w (get-buffer-window teco:output-buffer))
(b (current-buffer))
(sw (selected-window)))
;; Put the text in the output buffer
(set-buffer teco:output-buffer)
(goto-char (point-max))
(insert s)
(let ((p (point)))
(set-buffer b)
(if w
;; if output is visible, move the window point to the end
(set-window-point w p)
;; Otherwise, we have to figure out how to display the text
;; Has a newline followed by another character been added to the
;; output buffer? If so, we have to make the output buffer visible.
(if (save-excursion
(set-buffer teco:output-buffer)
(backward-char 1)
(search-backward "\n" teco:output-start t))
;; a newline has been seen, clear the minibuffer and make the
;; output buffer visible
(progn
(save-window-excursion
(select-window (minibuffer-window))
(erase-buffer))
(let ((pop-up-windows t))
(pop-to-buffer teco:output-buffer)
(goto-char p)
(set-window-start w teco:output-start)
(set-window-point w p)
(select-window sw)))
;; a newline has not been seen, add output to minibuffer
(save-window-excursion
(select-window (minibuffer-window))
(goto-char (point-max))
(insert s)))))))
;; Output a character of tracing information
(defun teco:trace-type (c)
(teco:output (if (= c ?\e)
?$
c)))
;; Report an error
(defun teco:error (code)
(let ((text (cdr (assoc code teco:error-texts))))
(teco:output (concat (if (save-excursion (set-buffer teco:output-buffer)
(/= (point) teco:output-start))
"\n"
"")
"? " code " " text))
(beep)
(if debug-on-error (debug nil code text))
(throw 'teco:exit nil)))
;; Utility routines
;; copy characters from command string to buffer
(defun teco:moveuntil (string pointer terminate trace)
(let ((count 0))
(condition-case nil
(while (/= (aref string pointer) terminate)
(and teco:trace (teco:trace-type (aref string pointer)))
(insert (aref string pointer))
(setq pointer (1+ pointer))
(setq count (1+ count)))
(error (teco:error (if teco:macro-stack "UTM" "UTC"))))
count))
;; Convert character to q-register name
;; If file-or-search is t, allow _, *, %, #
(defun teco:get-qspec (file-or-search char)
;; lower-case char
(setq char (aref teco:mapch-l char))
;; test that it's valid
(if (= (logand (aref teco:qspec-valid char) (if file-or-search 2 1)) 0)
(teco:error "IQN"))
char)
;; Set or get value of a variable
(defun teco:set-var (var)
(if teco:exp-flag1
(progn
(if teco:exp-flag2
;; if two arguments, they they are <clear bits>, <set bits>
(set var (logior (logand (symbol-value var) (lognot teco:exp-val2))
teco:exp-val1))
;; if one argument, it is the new value
(set var teco:exp-val1))
;; consume argument(s)
(setq teco:exp-flag2 nil
teco:exp-flag1 nil))
;; if no arguments, fetch the value
(setq teco:exp-val1 (symbol-value var)
teco:exp-flag1 t)))
;; Get numeric argument
(defun teco:get-value (default)
(prog1
(if teco:exp-flag1
teco:exp-val1
(if (eq teco:exp-op 'sub)
(- default)
default))
;; consume argument
(setq teco:exp-flag1 nil
teco:exp-op 'start)))
;; Get argument measuring in lines
(defun teco:lines (r)
(- (save-excursion
(if (> r 0)
(if (search-forward "\n" nil t r)
(point)
(point-max))
(if (search-backward "\n" nil t (- 1 r))
(1+ (point))
(point-min))))
(point)))
;; routine to handle args for K, T, X, etc.
;; if two args, 'char x' to 'char y'
;; if just one arg, then n lines (default 1)
(defun teco:line-args (arg)
(if teco:exp-flag2
(cons teco:exp-val1 teco:exp-val2)
(cons (point) (+ (point) (teco:lines (if teco:exp-flag1
teco:exp-val1
1))))))
;; routine to skip to next ", ', |, <, or >
;; skips over these chars embedded in text strings
;; stops in ! if argument is t
;; returns character found
(defun teco:skipto (&optional arg)
(catch 'teco:skip
(let (;; "at" prefix
(atsw nil)
;; temp attributes
ta
;; terminator
term
skipc)
(while t ; forever
(while (progn
(setq skipc (teco:get-command nil)
ta (aref teco:spec-chars skipc))
;; if char is ^, treat next char as control
(if (eq skipc ?^)
(setq skipc (logand 31 (teco:get-command nil))
ta (aref teco:spec-chars skipc)))
(= (logand ta 51) 0)) ; read until something interesting
; found
nil)
(if (/= (logand ta 32) 0)
(teco:get-command nil)) ; if command takes a Q spec,
; skip the spec
(if (/= (logand ta 16) 0) ; sought char found: quit
(progn
(if (= skipc ?\") ; quote must skip next char
(teco:get-command nil))
(throw 'teco:skip skipc)))
(if (/= (logand ta 1) 0) ; other special char
(cond
((eq skipc ?@) ; use alternative text terminator
(setq atsw t))
((eq skipc ?\C-^) ; ^^ is value of next char
; skip that char
(teco:get-command nil))
((eq skipc ?\C-a) ; type text
(setq term (if atsw (teco:get-command nil) ?\C-a)
atsw nil)
(while (/= (teco:get-command nil) term)
nil)) ; skip text
((eq skipc ?!) ; tag
(if arg
(throw 'teco:skip skipc))
(while (/= (teco:get-command nil) ?!)
nil)) ; skip until next !
((or (eq skipc ?e)
(eq skipc ?f)) ; first char of two-letter E or F
; command
nil))) ; not implemented
(if (/= (logand ta 2) 0) ; command with a text
; argument
(progn
(setq term (if atsw (teco:get-command nil) ?\e)
atsw nil)
(while (/= (teco:get-command nil) term)
nil) ; skip text
))))))
(defvar teco:command-keymap (make-vector 128 'teco:command-self-insert)
"Keymap used while reading teco commands.")
(define-key teco:command-keymap "\^g" 'teco:command-ctrl-g)
(define-key teco:command-keymap "\^m" 'teco:command-return)
(define-key teco:command-keymap "\^u" 'teco:command-ctrl-u)
(define-key teco:command-keymap "\e" 'teco:command-escape)
(define-key teco:command-keymap "\^?" 'teco:command-delete)
(defvar teco:command-escapes nil
"Records where ESCs are, since they are represented in the command buffer
by $.")
(defun teco:command ()
"Read and execute a Teco command string."
(interactive)
(let* ((teco:command-escapes nil)
(command (catch 'teco:command-quit
(read-from-minibuffer teco:prompt nil
teco:command-keymap))))
(if command
(progn
(while teco:command-escapes
(aset command (car teco:command-escapes) ?\e)
(setq teco:command-escapes (cdr teco:command-escapes)))
(setq teco:output-buffer (get-buffer-create "*Teco Output*"))
(save-excursion
(set-buffer teco:output-buffer)
(goto-char (point-max))
(insert teco:prompt command))
(teco:execute-command command)))))
(defun teco:read-command ()
"Read a teco command string from the user."
(let ((command (catch 'teco:command-quit
(read-from-minibuffer teco:prompt nil
teco:command-keymap)))
teco:command-escapes)
(if command
(while teco:command-escapes
(aset command (car teco:command-escapes ?\e))
(setq teco:command-escapes (cdr teco:command-escapes))))
command))
(defun teco:command-self-insert ()
(interactive)
(insert last-command-char)
(if (not (pos-visible-in-window-p))
(enlarge-window 1)))
(defun teco:command-ctrl-g ()
(interactive)
(beep)
(throw 'teco:command-quit nil))
(defun teco:command-return ()
(interactive)
(setq last-command-char ?\n)
(teco:command-self-insert))
(defun teco:command-escape ()
(interactive)
;; Two ESCs in a row terminate the command string
(if (eq last-command 'teco:command-escape)
(throw 'teco:command-quit (buffer-string)))
(setq teco:command-escapes (cons (1- (point)) teco:command-escapes))
(setq last-command-char ?$)
(teco:command-self-insert))
(defun teco:command-ctrl-u ()
(interactive)
;; delete the characters
(kill-line 0)
;; forget that they were ESCs
(while (and teco:command-escapes (<= (point) (car teco:command-escapes)))
(setq teco:command-escapes (cdr teco:command-escapes)))
;; decide whether to shrink the window
(while (let ((a (insert ?\n))
(b (pos-visible-in-window-p))
(c (backward-delete-char 1)))
b)
(shrink-window 1)))
(defun teco:command-delete ()
(interactive)
;; delete the character
(backward-delete-char 1)
;; forget that it was an ESC
(if (and teco:command-escapes (= (point) (car teco:command-escapes)))
(setq teco:command-escapes (cdr teco:command-escapes)))
;; decide whether to shrink the window
(insert ?\n)
(if (prog1 (pos-visible-in-window-p)
(backward-delete-char 1))
(shrink-window 1)))
Re: Teco for Gnu Emacs!
Author: Dave Sill
Date: Thu, 20 Jun 1991 13:02
Date: Thu, 20 Jun 1991 13:02
10 lines
1028 bytes
1028 bytes
In article <DRW.91Jun19185103@nevanlinna.mit.edu>, drw@nevanlinna.mit.edu (Dale R. Worley) writes: >Having gotten tired of not having Teco, I coded up this version for >Gnu Emacs. There are probably a zillion bugs. Happy hacking! Has anyone tried running the original TECO Emacs under this? :-) -- Dave Sill (de5@ornl.gov) Tug on anything in nature and you will find Martin Marietta Energy Systems it connected to everything else. Workstation Support --John Muir
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads