aboutsummaryrefslogtreecommitdiff
path: root/sys/gio/stdgraph/stgencode.x
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /sys/gio/stdgraph/stgencode.x
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'sys/gio/stdgraph/stgencode.x')
-rw-r--r--sys/gio/stdgraph/stgencode.x539
1 files changed, 539 insertions, 0 deletions
diff --git a/sys/gio/stdgraph/stgencode.x b/sys/gio/stdgraph/stgencode.x
new file mode 100644
index 00000000..3c7a6ffb
--- /dev/null
+++ b/sys/gio/stdgraph/stgencode.x
@@ -0,0 +1,539 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include "stdgraph.h"
+
+.help stg_encode
+.nf _________________________________________________________________________
+STG_ENCODE -- Table driven binary encoder/decoder. The encoder (which can
+also decode) processes a format string, also referred to as a program, to
+either encode an output string or decode an input string. Internally the
+encoder operates in two modes, copy mode and execute mode. In copy mode
+all format characters are copied to the output except the following special
+characters:
+
+ ' escape next character (literal)
+ % begin a formatted output string
+ ( switch to execute mode (stack driven, RPN interpreter)
+
+An ( appearing in the format string causes a mode switch to execute mode.
+In execute mode characters are metacode instructions to be executed. An
+unescaped ) causes reversion to copy mode. Parens may not be nested; an
+( in execute mode is an instruction to push the binary value of ( on the
+stack, and an ) in copy mode is copied to the output as a character. In
+execute mode the following characters are recognized as special instructions.
+All other characters are instructions too, telling the encoder to push the
+ASCII value of the character on the stack.
+
+ ' escape next character (recognized everywhere)
+ % formatted output
+ ) revert to copy mode
+ #nnn push signed decimal integer number nnn
+ $ switch case construct
+ . pop number from stack and place in output string
+ , get next character from input string and push on stack
+ & modulus (similar to AND of low bits)
+ + add (similar to OR)
+ - subtract (similar to AND)
+ * multiply (shift left if pwr of 2)
+ / divide (shift right if pwr of 2)
+ < less than (0=false, 1=true)
+ > greater than (0=false, 1=true)
+ = equals (0=false, 1=true)
+ ; branch if: <bool> <offset> ;. The ; is at offset zero.
+ 0-9 push register
+ !N pop stack into register N
+ !! pop N from stack and output an N millisecond delay
+
+The encoder communicates with the outside world via three general purpose
+data structures.
+
+ registers 0-9 (integer only)
+ memory char array
+ program char array
+
+The registers are used for parameter input and output as well as for storing
+intermediate results. R 1-3 are used for input and output arguments. R 4-9
+and R0 (R10) are reserved for use by the program. R11 is the i/o pointer into
+encoder memory, used for character input and output. R12 should contain the
+maximum memory address upon input. Memory may be used for anything but is
+normally used only for the input string or output string. The program is the
+format string.
+
+Further documentation is given in the GIO reference manual.
+.endhelp _____________________________________________________________________
+
+define SZ_FORMAT 10 # max length printf format
+define SZ_NUMSTR 10 # encoded numeric string
+
+define R1 registers[1] # argument
+define R2 registers[2] # argument
+define R3 registers[3] # argument
+define R4 registers[4] # scratch
+define R5 registers[5] # scratch
+define R6 registers[6] # scratch
+define R7 registers[7] # scratch
+define R8 registers[8] # scratch
+define R9 registers[9] # scratch
+define R0 registers[10] # scratch
+define IOP registers[11] # i/o pointer into encoder memory
+define TOP registers[12] # max memory location
+
+# Inline macros.
+
+define memory_overflow_ 1
+define stack_underflow_ 2
+define stack_overflow_ 3
+
+define input {$1=memory[iop];iop=iop+1}
+define output {memory[iop]=($1);iop=iop+1;if(iop>top)goto memory_overflow_}
+define push {stack[sp]=($1);sp=sp+1}
+define pop {sp=sp-1;$1=stack[sp]}
+
+
+# STG_ENCODE -- Interpret a program, encoding values passed in registers into
+# memory, or decoding memory into registers.
+
+int procedure stg_encode (program, memory, registers)
+
+char program[ARB] # program to be executed
+char memory[ARB] # data space
+int registers[NREGISTERS] # general purpose registers
+
+int x, y, num, ch, status
+int stack[LEN_STACK]
+int sp, pc, iop, top, incase
+common /sgecom/ pc, sp, iop, top, incase, stack
+int sge_execute()
+include "stdgraph.com"
+
+begin
+ # TEK format, %t. This format deserves special treatment due to the
+ # prevalence of tektronix compatible graphics terminals.
+
+ if (program[1] == '%' && program[2] == 't') {
+ x = R1
+ y = R2
+ iop = IOP + 4
+ if (iop > top)
+ goto memory_overflow_
+
+ memory[iop-4] = g_hixy[y+1]
+ memory[iop-3] = g_loy[y+1]
+ memory[iop-2] = g_hixy[x+1]
+ memory[iop-1] = g_lox[x+1]
+
+ IOP = iop
+ if (program[3] == EOS)
+ return (OK)
+ }
+
+ # Process a general format string (as well as any chars following the
+ # %t format).
+
+ incase = NO
+ iop = IOP
+ top = TOP
+ pc = 1
+ sp = 1
+
+ for (ch=program[pc]; ch != EOS; ch=program[pc]) {
+ pc = pc + 1
+ if (ch == '%' && program[pc] != EOS) {
+ if (program[pc] == 't') {
+ # Tek format again.
+ pc = pc + 1
+ x = R1
+ y = R2
+ iop = iop + 4
+ if (iop > top)
+ goto memory_overflow_
+
+ memory[iop-4] = g_hixy[y+1]
+ memory[iop-3] = g_loy[y+1]
+ memory[iop-2] = g_hixy[x+1]
+ memory[iop-1] = g_lox[x+1]
+
+ } else {
+ # Extract a general format specification and use it to
+ # encode the number on top of the stack.
+ pop (num)
+ if (sp < 1) {
+ IOP = iop
+ return (stack_underflow_)
+ } else
+ call sge_printf (num, memory, iop, top, program, pc)
+ }
+
+ } else if (ch == '(' && program[pc] != EOS) {
+ # Switch to execute mode.
+ status = sge_execute (program, memory, registers)
+ if (status != OK)
+ return (status)
+
+ } else if (ch == '\'' && program[pc] != EOS) {
+ # Escape next character.
+ output (program[pc])
+ pc = pc + 1
+
+ } else {
+ # Copy an ordinary character to the output string.
+ output (ch)
+ }
+ }
+
+ IOP = iop
+ return (OK)
+
+memory_overflow_
+ IOP = iop
+ return (memory_overflow_)
+end
+
+
+# SGE_EXECUTE -- Execute a metacode program stored in encoder memory starting
+# at the location of the PC. The stack, program counter, i/o pointer, and
+# registers are shared by the copy and execute mode procedures via common.
+
+int procedure sge_execute (program, memory, registers)
+
+char program[ARB] # program to be executed
+char memory[ARB] # data space
+int registers[NREGISTERS] # general purpose registers
+
+int num, ch, a, b, neg, x, y
+int stack[LEN_STACK]
+int sp, pc, iop, top, incase, msec, npad, baud, envgeti(), btoi()
+common /sgecom/ pc, sp, iop, top, incase, stack
+include "stdgraph.com"
+errchk envgeti
+
+begin
+ # Execute successive single character instructions until either ) or
+ # EOS is seen. On a good host machine this case will be compiled as
+ # a vectored goto with a loop overhead of only a dozen or so machine
+ # instructions per loop.
+
+ for (ch=program[pc]; ch != EOS; ch=program[pc]) {
+ pc = pc + 1
+
+ switch (ch) {
+ case '\'':
+ # Escape next character (recognized everywhere).
+ ch = program[pc]
+ if (ch != EOS) {
+ # Push ASCII value of character.
+ push (ch)
+ pc = pc + 1
+ }
+
+ case '%':
+ if (program[pc] == 't') {
+ # Tek format again.
+ pc = pc + 1
+ x = R1
+ y = R2
+ iop = iop + 4
+ if (iop > top)
+ goto memory_overflow_
+
+ memory[iop-4] = g_hixy[y+1]
+ memory[iop-3] = g_loy[y+1]
+ memory[iop-2] = g_hixy[x+1]
+ memory[iop-1] = g_lox[x+1]
+
+ } else {
+ # Formatted output.
+ if (program[pc] != EOS) {
+ pop (num)
+ call sge_printf (num, memory, iop, top, program, pc)
+ } else
+ output (ch)
+ }
+
+ case ')':
+ # End interpreter mode.
+ return (OK)
+
+ case '#':
+ # Push signed decimal integer number.
+ neg = NO
+ if (program[pc] == '-') {
+ neg = YES
+ pc = pc + 1
+ }
+
+ num = 0
+ while (IS_DIGIT (program[pc])) {
+ num = num * 10 + TO_INTEG (program[pc])
+ pc = pc + 1
+ }
+
+ if (neg == YES)
+ push (-num)
+ else
+ push (num)
+
+ case '$':
+ # Switch case instruction.
+
+ if (incase == NO) {
+ # Pop the switch off the stack.
+ pop (num)
+
+ # Search for case number 'num'.
+ for (ch=program[pc]; ch != EOS; ch=program[pc]) {
+ if (ch == '$') {
+ # End of switch statement.
+ pc = pc + 1
+ incase = NO
+ break
+
+ } else if (program[pc+1] == '-') {
+ # Range of cases.
+ a = TO_INTEG (ch)
+ b = TO_INTEG (program[pc+2])
+ pc = pc + 3
+ if (a <= num && num <= b) {
+ incase = YES
+ break
+ }
+ } else if (ch == 'D' || TO_INTEG(ch) == num) {
+ # Default or requested case.
+ pc = pc + 1
+ incase = YES
+ break
+
+ }
+
+ # Advance to the next case. Leave pc pointing to the
+ # N of case $N.
+
+ if (ch != '$' && incase == NO) {
+ while (program[pc] != EOS && program[pc] != '$')
+ pc = pc + 1
+ if (program[pc] == '$')
+ pc = pc + 1
+ }
+ }
+
+ } else {
+ # $ encountered delimiting a case. Search forward for
+ # $$ or EOS.
+
+ if (program[pc] != '$')
+ for (ch=program[pc]; ch != EOS; ch=program[pc]) {
+ pc = pc + 1
+ if (ch == '$' && program[pc] == '$')
+ break
+ }
+
+ if (program[pc] == '$')
+ pc = pc + 1
+
+ incase = NO
+ }
+
+ case '.':
+ # Pop number from stack and place in output string as a
+ # binary character.
+ pop (num)
+ output (num)
+
+ case ',':
+ # Get next character from input string and push on stack.
+ input (num)
+ push (num)
+
+ case '&':
+ # Modulus (similar to AND of low bits).
+ pop (b)
+ pop (a)
+ push (mod (a, b))
+
+ case '+':
+ # Add (similar to OR).
+ pop (b)
+ pop (a)
+ push (a + b)
+
+ case '-':
+ # Subtract (similar to AND).
+ pop (b)
+ pop (a)
+ push (a - b)
+
+ case '*':
+ # Multiply (shift left if pwr of 2).
+ pop (b)
+ pop (a)
+ push (a * b)
+
+ case '/':
+ # Divide (shift right if pwr of 2).
+ pop (b)
+ pop (a)
+ push (a / b)
+
+ case '<':
+ # Less than (0=false, 1=true).
+ pop (b)
+ pop (a)
+ push (btoi (a < b))
+
+ case '>':
+ # Greater than (0=false, 1=true).
+ pop (b)
+ pop (a)
+ push (btoi (a > b))
+
+ case '=':
+ # Equals (0=false, 1=true).
+ pop (b)
+ pop (a)
+ push (btoi (a == b))
+
+ case ';':
+ # If 2nd value on stack is true add 1st value on stack to PC.
+ # Example: "12<#-8;". The ; is at offset zero.
+ pop (a)
+ pop (b)
+ if (b != 0)
+ pc = pc - 1 + a
+
+ case '0':
+ # Push contents of register 0 (10).
+ push (R0)
+ case '1':
+ # Push contents of register 1.
+ push (R1)
+ case '2':
+ # Push contents of register 2.
+ push (R2)
+ case '3':
+ # Push contents of register 3.
+ push (R3)
+ case '4':
+ # Push contents of register 4.
+ push (R4)
+ case '5':
+ # Push contents of register 5.
+ push (R5)
+ case '6':
+ # Push contents of register 6.
+ push (R6)
+ case '7':
+ # Push contents of register 7.
+ push (R7)
+ case '8':
+ # Push contents of register 8.
+ push (R8)
+ case '9':
+ # Push contents of register 9.
+ push (R9)
+
+ case '!':
+ if (program[pc] == '!') {
+ # !!: Pop stack and generate delay.
+ pc = pc + 1
+ pop (msec)
+ iferr (baud = envgeti ("ttybaud"))
+ baud = 9600
+ npad = real(msec) * (real(baud) / 8. / 1000.)
+ while (npad > 0) {
+ output (PADCHAR)
+ npad = npad - 1
+ }
+ } else {
+ # !N: Pop stack into register N.
+ num = TO_INTEG (program[pc])
+ if (num >= 0 && num <= 9) {
+ if (num == 0)
+ num = 10
+ pop (registers[num])
+ pc = pc + 1
+ } else
+ output (ch)
+ }
+
+ default:
+ # Push ASCII value of character.
+ push (ch)
+ }
+
+ if (sp <= 0)
+ return (stack_underflow_)
+ if (sp > LEN_STACK)
+ return (stack_overflow_)
+ }
+
+ return (OK)
+
+memory_overflow_
+ return (memory_overflow_)
+end
+
+
+# SGE_PRINTF -- Process a %.. format specification. The number to be encoded
+# has already been popped from the stack into the first argument. The encoded
+# number is returned in memory at IOP, leaving IOP positioned to the first
+# char following the encoded number. The format used to encode the number is
+# extracted from the program starting at PC. PC is left pointing to the first
+# character following the format.
+
+procedure sge_printf (number, memory, iop, top, program, pc)
+
+int number # number to be encoded
+char memory[top] # output buffer
+int iop # index of first char to be written (in/out)
+int top # size of output buffer
+char program[ARB] # contains printf format string
+int pc # index of first char of format string (in/out)
+
+char format[SZ_FORMAT]
+char numstr[SZ_NUMSTR]
+int op, ch, junk
+int gstrcpy(), itoc()
+
+begin
+ # Extract format %w.dC, a string of digits, -, or ., delimited by a
+ # letter. The format %w.dr is followed by a single character which
+ # must also be included in the format string.
+
+ format[1] = '%'
+ op = 2
+ for (ch=program[pc]; ch != EOS; ch=program[pc]) {
+ pc = pc + 1
+ format[op] = ch
+ op = op + 1
+ if (IS_LOWER(ch)) {
+ if (ch == 'r' && program[pc] != EOS) {
+ # Radix digit follows %r.
+ format[op] = program[pc]
+ op = op + 1
+ pc = pc + 1
+ }
+ break
+ }
+ }
+ format[op] = EOS
+
+ # Encode the number using the extracted format string. The case of
+ # a simple decimal encoding is optimized.
+
+ if (format[2] == 'd')
+ junk = itoc (number, numstr, SZ_NUMSTR)
+ else {
+ iferr {
+ call sprintf (numstr, SZ_NUMSTR, format)
+ call pargi (number)
+ } then
+ numstr[1] = EOS
+ }
+
+ # Move the encoded number to encoder memory, advancing the i/o
+ # pointer and taking care not to overrun memory. Leave the iop
+ # pointing AT, not after, the EOS output by gstrcpy.
+
+ iop = iop + gstrcpy (numstr, memory[iop], top - iop + 1)
+end