Last active
October 28, 2025 11:51
-
-
Save kenwebb/273e045fc59c9bbb3e0880258a041dce to your computer and use it in GitHub Desktop.
EC-4000 Distance Traveled
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Ken Webb | |
| * 2025 Oct 17 | |
| * EC4000 (TI57) emulation | |
| * my very first program from 1978, redone using TypeScript | |
| * 18 Oct - copied from rip to Lenovo | |
| * 19 Oct - and then copied to RPi4 | |
| * 21 Oct - edited at meetup | |
| * | |
| * TODO | |
| * - add more TODOs for Tuesday | |
| * - deal with display value, getNextDisplay() | |
| * - PARTLY DONE handle combining separate digits [0..9] and "." into strings and/or integers | |
| * - digits() | |
| * - I can collect the digits into a string | |
| * - BUT how do I use this collection of digits as a number in a numeric expression such as 123+456 ? | |
| * - 123+456= | |
| * - each number is bracketed by +-xDIV=COS etc. | |
| * - maybe I should accumulate the digits in the display variable (or other place) where the next instruction wlll naturally look for a number ? | |
| * - maybe put each complete number onto a stack; the problem here is infix expressions (3 + 4); s-expressions (+ 3 4) (prefix) are simpler, or reverse polish (3 4 +) (postfix) | |
| * - TODO look for an algorithm to compute arithmetic infix expressions | |
| * - DONE get the new monitor working | |
| * - use enum rather than string in my switch statement | |
| * - I have several ways of dealing with numbers/digits: OpCodes _0, zero, 0 | |
| * - OpCodes is an enum, my programs are string[] - how do I get these two to work together? | |
| */ | |
| enum OpCodes { | |
| _0 = "0", | |
| _1 = "1", | |
| _2 = "2", | |
| _3 = "3", | |
| _4 = "4", | |
| _5 = "5", | |
| _6 = "6", | |
| _7 = "7", | |
| _8 = "8", | |
| _9 = "9", | |
| /** | |
| * 2nd | |
| */ | |
| _2nd = "2nd", | |
| /** | |
| * LRN - "Learn" Key | |
| * Pressing this key once, puts calculator in "learn" mode — ready to remember up to 50 program steps (numbered 00 to 49). | |
| * Display switches to special format: 00 00. | |
| * Pressing this key once again takes calculator out of learn mode, calculator retains program steps. | |
| * (Display reverts to the standard format). | |
| */ | |
| LRN = "LRN", | |
| /** | |
| * RST - Reset Key | |
| * Resets program pointer to first step (step 00), whether entered from the keyboard or encountered as part of a program. | |
| * (Also, clears Subroutine Return register.) | |
| */ | |
| RST = "RST", | |
| /** | |
| * STO n - (n from 0 to 7) stores the number in the display in the memory you select (0 to 7). | |
| */ | |
| STO = "STO", | |
| /** | |
| * RCL n - recalls the number from memory n into the display. | |
| */ | |
| RCL = "RCL", | |
| /** | |
| * | |
| */ | |
| SUM = "SUM", | |
| /** | |
| * ( | |
| */ | |
| //_(, // how do I represent this character? https://en.wikipedia.org/wiki/Bracket U+0028 ( LEFT PARENTHESIS (() | |
| LPAR = "(", | |
| /** | |
| * ) | |
| */ | |
| //_), // how do I represent this character? U+0029 ) RIGHT PARENTHESIS ()) | |
| RPAR = ")", | |
| /** | |
| * X - + | |
| */ | |
| DIV = "DIV", | |
| /** | |
| * GTO - GOTO label | |
| * n _ Go to Label n Key Sequence. | |
| * Causes program pointer to immediately go to label n (n from 0 to 9), | |
| * whether encountered as part of a program, or used from the keyboard. | |
| * GT0 [2nd] nn — Go to Step Number nn Key Sequence (nn from 00 to 49) | |
| * May be used when out of learn mode only. Positions program pointer at step number nn. | |
| */ | |
| GTO = "GTO", | |
| TIMES = "X", | |
| MINUS = "-", | |
| PLUS = "+", | |
| /** | |
| * R/S — Run/Stop Key | |
| * When out of learn mode, this is the start/stop key for your program. | |
| * If the program is stopped, pressing R/S starts it; | |
| * if it's running, pressing R/S stops it. | |
| * When R/S is inserted as part of a program (in learn mode) it will stop the program at that point. | |
| */ | |
| R_S = "R/S", // R/S | |
| EQUALS = "=", | |
| }; | |
| /** | |
| * Opcodes that follow "2nd"; | |
| */ | |
| enum OpCodes2nd { | |
| /** | |
| * The Pause Key Sequence. | |
| * While a program is runninng and the program pointer comes to a 2nd Pause instruction, | |
| * it stops the program for about 3/4 of a second and displays whatever result is in the display register at that point. | |
| * Then, it continues on to the next step. | |
| */ | |
| Pause = "Pause", | |
| /** | |
| * The Label Key Sequence | |
| * This key allows you to label any point in a program, or a subroutine. | |
| * You can label up to 10 points in a program. | |
| * @param n - any digit 0 through 9 | |
| */ | |
| Lbl = "Lbl", | |
| /** | |
| * The "Decrement and Skip on Zero" Key Sequence. | |
| */ | |
| Dsz = "Dsz" | |
| } | |
| type Test = { | |
| un: string, | |
| deux: number | |
| } | |
| /** | |
| * ip - instruction pointer, program pointer | |
| * index into the program memory; zero-based | |
| */ | |
| let ip: number = 0; | |
| /** | |
| * display - the display on the EC4000 | |
| */ | |
| let display: number = 0; | |
| /** | |
| * Get the next item from the display. | |
| * This simulates a person having typed these. | |
| * This function will return a different sequence for each program. | |
| * For now, the sequence is hard-coded here. | |
| */ | |
| const getNextDisplay = (): number => { | |
| display = displayArr[displayCounter++]; | |
| return display; | |
| } | |
| const displayArr: number[] = [3, 4]; | |
| let displayCounter: number = 0; | |
| const test01: Test = {un: "One", deux: 2}; | |
| console.log(OpCodes); | |
| console.log(OpCodes.STO); | |
| console.log(OpCodes["0"]); | |
| console.log(test01); | |
| //let memory: Array<number> = new Array(8); | |
| let memory = new Array(8); | |
| memory.fill(0); | |
| memory[0] = 17; | |
| memory[7] = 23; | |
| console.log(memory, typeof memory, memory.length); | |
| /** | |
| * first simple program from the EC-4000 manual p.9 | |
| */ | |
| const prog01: string[] = ` | |
| LRN | |
| X 2 = | |
| 2nd Pause | |
| RST | |
| LRN | |
| RST | |
| `.trim().split("\n"); | |
| /** | |
| * sample program - July 27, 1978 - Distance Travelled at Constant Velocity | |
| * A program to calculate the distance travelled at one second intervals, given time and velocity. | |
| * (see TY Calculus p. 33) | |
| * memory 1 - t value | |
| * memory 2 - v value | |
| */ | |
| const prog02: string[] = ` | |
| LRN | |
| STO 1 | |
| R/S | |
| STO 2 | |
| 2nd Lbl 1 | |
| RCL 1 | |
| 2nd Pause | |
| X | |
| RCL 2 | |
| = | |
| 2nd Pause | |
| 2nd Pause | |
| RCL 1 | |
| + | |
| 1 | |
| = | |
| STO 1 | |
| GTO 1 | |
| LRN | |
| RST | |
| `.trim().split("\n"); | |
| const prog03: string[] = ` | |
| 1 | |
| 2 | |
| 3 | |
| . | |
| 4 | |
| 5 | |
| `.trim().split("\n"); | |
| /* | |
| How to use it: | |
| - see the steps that I wrote down in 1978 | |
| */ | |
| console.log(`prog01[4] ${prog01[4]}`); | |
| console.log(`prog02[4] ${prog02[4]}`); | |
| // opCode functions | |
| /** | |
| * toggle Learn mode; nothing to do | |
| */ | |
| const lrn = (): void => {return;} | |
| /** | |
| * rst - reset the instruction pointer (ip) | |
| */ | |
| const rst = (): void => { | |
| ip = 0; // reset the instruction pointer | |
| return; | |
| } | |
| const gto = (mix: number): void => { | |
| ip = mix; | |
| return; | |
| } | |
| /** | |
| * sto - stores the number in the display in the memory you select (0 to 7) | |
| * @param mix - index into the memory array 0..7 | |
| */ | |
| const sto = (mix: number): void => { | |
| console.log(`sto: ${mix} ${display}`); | |
| memory[mix] = display; | |
| } | |
| /** | |
| * rcl - recalls the number from memory n into the display | |
| */ | |
| const rcl = (mix: number): void => { | |
| display = memory[mix]; | |
| console.log(`rcl: ${mix} ${display}`); | |
| } | |
| // the numbers 0..9 | |
| const succ = (n: number): number => n + 1; | |
| const zero = (): number => 0; | |
| const one = (): number => succ(zero()); | |
| const two = (): number => succ(one()); | |
| const three = (): number => succ(two()); | |
| const four = (): number => succ(three()); | |
| const five = (): number => succ(four()); | |
| const six = (): number => succ(five()); | |
| const seven = (): number => succ(six()); | |
| const eight = (): number => succ(seven()); | |
| const nine = (): number => succ(eight()); | |
| console.log(`zero: ${zero()}`); | |
| console.log(`eight: ${eight()}`); | |
| // TODO these are placeholders | |
| const plus = () => null; | |
| const minus = () => null; | |
| const times = () => null; | |
| const div = () => null; | |
| console.log(seven() * six()); | |
| // ========================================== digits | |
| let collectedDigits = ""; | |
| /** | |
| * digits - Handle digits in the program [0..9] and "." | |
| * @param - digit - a digit or dot | |
| */ | |
| const digits = (digit: string): void => { | |
| // TODO | |
| collectedDigits += digit; | |
| console.log(`digits: found ${digit}`); | |
| } | |
| // ========================================== end digits | |
| /** | |
| * Parse and execute a EC4000 program. | |
| * @param parr - An array of EC4000 program instructions. | |
| * @remarks | |
| * The opcodes are ordered as presented on the EC-4000 Reference Guide (the blue folding card) | |
| */ | |
| const parse = (parr: string[]): void => { | |
| parr.forEach((pinst: string): void => { | |
| console.log("|" + pinst + "|"); | |
| const pline = pinst.trim().split(" "); | |
| const opcode: string = pline[0]; | |
| // TODO use the enum value rather than a string | |
| switch (opcode) { | |
| case "0": | |
| case "1": | |
| case "2": | |
| case "3": | |
| case "4": | |
| case "5": | |
| case "6": | |
| case "7": | |
| case "8": | |
| case "9": | |
| digits(opcode); | |
| break; | |
| case "lnx": break; | |
| case "INV": break; | |
| case "CE": break; | |
| case "CLR": break; | |
| case "2nd": | |
| parse2nd(pline.slice(1)); | |
| break; | |
| case "x<t": break; | |
| case "x2": break; | |
| case "sqrx": break; | |
| case "1/x": break; | |
| case OpCodes.STO: | |
| sto(Number(pline[1])); | |
| break; | |
| case OpCodes.RCL: | |
| rcl(Number(pline[1])); | |
| break; | |
| case "SUM": break; | |
| case "yx": break; | |
| case "EE": break; | |
| case "(": break; | |
| case ")": break; | |
| case "div": break; | |
| case "GTO": break; | |
| case "X": break; | |
| case "SBR": break; | |
| case "-": break; | |
| case "RST": | |
| rst(); | |
| break; | |
| case "+": break; | |
| case "R/S": break; | |
| case ".": | |
| digits(opcode); | |
| break; | |
| case "+/-": break; | |
| case "=": break; | |
| case "": break; | |
| case "LRN": lrn(); break; | |
| default: | |
| console.log(`unknown opcode: ${opcode}`); | |
| break; | |
| } | |
| }); | |
| } | |
| /** | |
| * | |
| */ | |
| const parse2nd = (pline: string[]): void => { | |
| console.log("|2 " + pline.join("_") + "|"); | |
| //const pline2 = pline.trim().split(" "); | |
| const code: string = pline[0]; | |
| switch (code) { | |
| case "log": break; | |
| case "C.t": break; | |
| case "tan": break; | |
| case "sin": break; | |
| case "cos": break; | |
| case "PI": break; | |
| case "Pause": break; | |
| case "Exc": break; | |
| case "Prd": break; | |
| case "Nop": break; | |
| case "FIX": break; | |
| case "Int": break; | |
| case "Deg": break; | |
| case "Dsz": break; | |
| case "Rad": break; | |
| case "x=t": break; | |
| case "Grad": break; | |
| case "Lbl": break; | |
| //case "": break; | |
| default: console.log(`unknown 2nd opcode: ${code}`); break; | |
| } | |
| } | |
| display = 33; | |
| console.log(`progBEFORE d ${display} m ${memory.join(" ")}`); | |
| //parse(prog01); | |
| //parse(prog02); | |
| parse(prog03); | |
| console.log(`progAFTER d ${display} m ${memory.join(" ")}`); | |
| console.log(`collectedDigits: ${collectedDigits}`); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8"?> | |
| <!--Xholon Workbook http://www.primordion.com/Xholon/gwt/ MIT License, Copyright (C) Ken Webb, Tue Oct 28 2025 07:49:11 GMT-0400 (Eastern Daylight Time)--> | |
| <XholonWorkbook> | |
| <Notes><![CDATA[ | |
| Xholon | |
| ------ | |
| Title: EC-4000 Distance Traveled | |
| Description: | |
| Url: http://www.primordion.com/Xholon/gwt/ | |
| InternalName: 273e045fc59c9bbb3e0880258a041dce | |
| Keywords: EC-4000 | |
| My Notes | |
| -------- | |
| 2025 Oct 23 | |
| This project combines two things: | |
| (1) In 1978 I bought a EC-4000 (TI-57) programmable calculator and wrote a bunch of simple programs. | |
| (2) Today I am learning to code using TypeScript. | |
| I have written a starter TypeScript program that runs in a console window using tsc and node. | |
| The goal is to simulate the EC-4000 program in TypeScript. | |
| In this Xholon workbook, I use the generated JavaScript code to build a more complete simulation, | |
| and to see how I can get Xholon and TypeScript working together. | |
| ### The original 1978 EC-4000 program | |
| LRN | |
| STO 1 | |
| R/S | |
| STO 2 | |
| 2nd Lbl 1 | |
| RCL 1 | |
| 2nd Pause | |
| X | |
| RCL 2 | |
| = | |
| 2nd Pause | |
| 2nd Pause | |
| RCL 1 | |
| + | |
| 1 | |
| = | |
| STO 1 | |
| GTO 1 | |
| LRN | |
| RST | |
| ### References | |
| (1) see my TypeScript program on RPi4 | |
| ### TODO | |
| - use a "working memory" variable, as equivalent to EC-4000 display | |
| - there is only one working memory value, that's it | |
| - data has to be moved in and out of memory (8 values) | |
| - working <-> memory(8) | |
| - DONE write a parser (see ref[1]) | |
| - reuse some of the code in the tsc-generated JavaScript code | |
| - including the OpCodes (TypeScript enum, JavaScript var with properties | |
| - BUT maybe OpCodes should be an Object in TypeScript and JavaScript ? NO for now | |
| - DONE save the TypeScript program to the gist, as a separate file | |
| - numbers are put together one digit at a time | |
| - I need a way to recognize when a number is complete ? | |
| - either it will actually work OK the way it is now, or I could have a state machine that knows if we are currently reading a number | |
| - carefully work out all the data pathways | |
| - draw a complete diagram | |
| - state machine ? opCodes are the events | |
| - is this a register machine? | |
| - see part of book I photocopied | |
| ### Correspondences between the EC-4000 code and the Xholon implementation | |
| - the setup part of the EC-4000 is implemented by Xholon postConfigure() | |
| - the EC-4000 "2nd Lbl 1" ... "GTO 1" loop is implemented by Xholon act() | |
| - GOTO label vs function with start and end | |
| - EC-4000 STO and RCL are implemented by Xholon arrow functions sto() and rcl() | |
| - EC-4000 R/S and 2nd Pause are like Xholon Step and Pause | |
| - EC-4000 LRN is like Xholon DistanceTraveledbehavior coding | |
| - it's not clear how to handle/parse EC-4000 infix operations + - × ÷ and = | |
| - | |
| ]]></Notes> | |
| <_-.XholonClass> | |
| <PhysicalSystem/> | |
| <!-- A manually generated Xholon Script that directly implements the Distance Traveled EC-4000 program. Intended for initial testing and playing around --> | |
| <DistanceTraveled/> | |
| <!-- Test definition of EC-4000 opcodes, based largely on what TypeScript generated from program (see ref[1]) --> | |
| <TestOpCodes superClass="script"/> | |
| <Ec4000Program superClass="Attribute_String"/> | |
| <Ec4000Programs/> | |
| <Ec4000Parser superClass="script"/> | |
| <Setup/> | |
| </_-.XholonClass> | |
| <xholonClassDetails> | |
| <DistanceTraveled><Color>green</Color></DistanceTraveled> | |
| <Avatar><Color>orange</Color></Avatar> | |
| <TestOpCodes><DefaultContent><![CDATA[ | |
| // the EC-4000 code parser should be able to use this | |
| var me, OpCodes, OpCodes2nd, beh = { | |
| postConfigure: function() { | |
| me = this.cnode; | |
| //me.println(me.name() + " getting OpCodes and OpCodes2nd"); | |
| OpCodes = this.getOpCodes({}); | |
| OpCodes2nd = this.getOpCodes2nd({}); | |
| // TODO | |
| //console.log(OpCodes["("]); | |
| //console.log(OpCodes.STO); | |
| //console.log(OpCodes); | |
| //me.println("Testing"); | |
| //me.println(OpCodes["("]); | |
| //me.println(OpCodes.STO); | |
| //me.println(OpCodes["STO"]); | |
| //me.println(OpCodes[0]); | |
| //me.println(OpCodes["0"]); | |
| //me.println(OpCodes2nd["Pause"]); | |
| }, | |
| act: function() { | |
| // TODO | |
| }, | |
| /* TESTING processReceivedSyncMessage | |
| test using Dev Tools: | |
| var tocs = temp0; | |
| tocs.call(103, "data"); | |
| - this test works | |
| var tocs = temp0; | |
| var response = tocs.call(103, "data"); | |
| var rdata = response.data; | |
| var OpCodes = rdata[0]; | |
| var OpCodes2nd = rdata[1]; | |
| //console.log(OpCodes); | |
| //console.log(OpCodes2nd); | |
| - this test also works! | |
| */ | |
| processReceivedSyncMessage(msg) { | |
| me.println("received message sync: " + msg.signal); | |
| console.log("received message sync: " + msg.signal); | |
| //return "TODO return a link to OpCodes and OpCodes2nd"; // this works! | |
| return [OpCodes, OpCodes2nd]; | |
| }, | |
| getOpCodes: function (OpCodes) { | |
| OpCodes["0"] = "0"; | |
| OpCodes["1"] = "1"; | |
| OpCodes["2"] = "2"; | |
| OpCodes["3"] = "3"; | |
| OpCodes["4"] = "4"; | |
| OpCodes["5"] = "5"; | |
| OpCodes["6"] = "6"; | |
| OpCodes["7"] = "7"; | |
| OpCodes["8"] = "8"; | |
| OpCodes["9"] = "9"; | |
| /** | |
| * 2nd | |
| */ | |
| OpCodes["2nd"] = "2nd"; | |
| /** | |
| * LRN - "Learn" Key | |
| * Pressing this key once, puts calculator in "learn" mode — ready to remember up to 50 program steps (numbered 00 to 49). | |
| * Display switches to special format: 00 00. | |
| * Pressing this key once again takes calculator out of learn mode, calculator retains program steps. | |
| * (Display reverts to the standard format). | |
| */ | |
| OpCodes["LRN"] = "LRN"; | |
| /** | |
| * RST - Reset Key | |
| * Resets program pointer to first step (step 00), whether entered from the keyboard or encountered as part of a program. | |
| * (Also, clears Subroutine Return register.) | |
| */ | |
| OpCodes["RST"] = "RST"; | |
| /** | |
| * STO n - (n from 0 to 7) stores the number in the display in the memory you select (0 to 7). | |
| */ | |
| OpCodes["STO"] = "STO"; | |
| /** | |
| * RCL n - recalls the number from memory n into the display. | |
| */ | |
| OpCodes["RCL"] = "RCL"; | |
| /** | |
| * | |
| */ | |
| OpCodes["SUM"] = "SUM"; | |
| /** | |
| * ( | |
| */ | |
| //_(, // how do I represent this character? https://en.wikipedia.org/wiki/Bracket U+0028 ( LEFT PARENTHESIS (() | |
| OpCodes["("] = "("; | |
| /** | |
| * ) | |
| */ | |
| //_), // how do I represent this character? U+0029 ) RIGHT PARENTHESIS ()) | |
| OpCodes[")"] = ")"; | |
| /** | |
| * X - + | |
| */ | |
| OpCodes["/"] = "/"; | |
| /** | |
| * GTO - GOTO label | |
| * n _ Go to Label n Key Sequence. | |
| * Causes program pointer to immediately go to label n (n from 0 to 9), | |
| * whether encountered as part of a program, or used from the keyboard. | |
| * GT0 [2nd] nn — Go to Step Number nn Key Sequence (nn from 00 to 49) | |
| * May be used when out of learn mode only. Positions program pointer at step number nn. | |
| */ | |
| OpCodes["GTO"] = "GTO"; | |
| OpCodes["X"] = "X"; | |
| OpCodes["-"] = "-"; | |
| OpCodes["+"] = "+"; | |
| /** | |
| * R/S — Run/Stop Key | |
| * When out of learn mode, this is the start/stop key for your program. | |
| * If the program is stopped, pressing R/S starts it; | |
| * if it's running, pressing R/S stops it. | |
| * When R/S is inserted as part of a program (in learn mode) it will stop the program at that point. | |
| */ | |
| OpCodes["R/S"] = "R/S"; | |
| OpCodes["="] = "="; | |
| return OpCodes; | |
| }, | |
| //(OpCodes || (OpCodes = {})); | |
| /** | |
| * Opcodes that follow "2nd"; | |
| */ | |
| //var OpCodes2nd; | |
| getOpCodes2nd: function (OpCodes2nd) { | |
| /** | |
| * The Pause Key Sequence. | |
| * While a program is runninng and the program pointer comes to a 2nd Pause instruction, | |
| * it stops the program for about 3/4 of a second and displays whatever result is in the display register at that point. | |
| * Then, it continues on to the next step. | |
| */ | |
| OpCodes2nd["Pause"] = "Pause"; | |
| /** | |
| * The Label Key Sequence | |
| * This key allows you to label any point in a program, or a subroutine. | |
| * You can label up to 10 points in a program. | |
| * @param n - any digit 0 through 9 | |
| */ | |
| OpCodes2nd["Lbl"] = "Lbl"; | |
| /** | |
| * The "Decrement and Skip on Zero" Key Sequence. | |
| */ | |
| OpCodes2nd["Dsz"] = "Dsz"; | |
| return OpCodes2nd; | |
| } | |
| // )(OpCodes2nd || (OpCodes2nd = {})); | |
| } // end beh | |
| //# sourceURL=TestOpCodes.js | |
| ]]></DefaultContent></TestOpCodes> | |
| <Ec4000Parser><DefaultContent><![CDATA[ | |
| const TESTCASE = 1; | |
| var me, ava, ec4000prog, linesep, OpCodes, OpCodes2nd, code, ix, memory, working, operatorStack, operandStack, beh = { | |
| postConfigure: function() { | |
| me = this.cnode; | |
| console.log(me, me.parent()); | |
| ava = $wnd.xh.avatar(); | |
| ec4000prog = me.xpath(`../Ec4000Programs/Ec4000Program[${TESTCASE}]`); | |
| linesep = ec4000prog.linesep; | |
| if (linesep === "CRLF") {linesep = "\n";}; | |
| console.log(ec4000prog); | |
| code = ec4000prog.text().trim().split(linesep); | |
| ix = 0; | |
| memory = new Array(8).fill(0); // memory slots are indexed from 0 to 7; | |
| working = {}; | |
| working.sval = ""; // accumulating String value | |
| working.nval = 0; // numeric value | |
| operatorStack = []; // use push and pop + - X div | |
| operandStack = []; // use push and pop 123.456 etc. | |
| let testOpCodes = me.xpath("../TestOpCodes"); | |
| //console.log(testOpCodes.name(), testOpCodes); // OK | |
| var response = testOpCodes.call(103, "data"); | |
| //console.log(response); | |
| var rdata = response.data; | |
| //console.log(rdata); | |
| if (rdata) { | |
| OpCodes = rdata[0]; | |
| OpCodes2nd = rdata[1]; | |
| console.log(OpCodes); | |
| console.log(OpCodes2nd); | |
| } | |
| }, | |
| act: function() { | |
| // handle one line of EC4000 code each time step | |
| if (ix < code.length) { | |
| const line = code[ix].split(" "); | |
| const opcode = line[0]; | |
| me.println(opcode + " |" + line + "|"); | |
| // TODO use the enum value rather than a string | |
| switch (opcode) { | |
| case OpCodes["0"]: | |
| case OpCodes["1"]: | |
| case OpCodes["2"]: | |
| case OpCodes["3"]: | |
| case OpCodes["4"]: | |
| case OpCodes["5"]: | |
| case OpCodes["6"]: | |
| case OpCodes["7"]: | |
| case OpCodes["8"]: | |
| case OpCodes["9"]: | |
| this.digits(opcode); | |
| break; | |
| case OpCodes.lnx: break; | |
| case OpCodes.INV: break; | |
| case OpCodes.CE: break; | |
| case OpCodes.CLR: break; | |
| case OpCodes["2nd"]: | |
| this.parse2nd(line.slice(1)); | |
| break; | |
| case OpCodes["x<t"]: break; | |
| case OpCodes.x2: break; | |
| case OpCodes.sqrx: break; | |
| case OpCodes["1/x"]: break; | |
| case OpCodes.STO: // TODO fix | |
| this.sto(Number(line[1]), working.sval); //nval++); | |
| break; | |
| case OpCodes.RCL: // TODO fix | |
| working.sval = this.rcl(Number(line[1])); | |
| break; | |
| case OpCodes.SUM: break; | |
| case OpCodes.yx: break; | |
| case OpCodes.EE: break; | |
| case OpCodes["("]: break; | |
| case OpCodes[")"]: break; | |
| case OpCodes["/"]: | |
| operatorStack.push(opcode); | |
| operandStack.push(working.sval); | |
| working.sval = ""; | |
| break; | |
| case OpCodes.GTO: break; | |
| case OpCodes.X: | |
| operatorStack.push(opcode); | |
| operandStack.push(working.sval); | |
| working.sval = ""; | |
| break; | |
| case OpCodes.SBR: break; | |
| case OpCodes["-"]: | |
| operatorStack.push(opcode); | |
| operandStack.push(working.sval); | |
| working.sval = ""; | |
| break; | |
| case OpCodes.RST: | |
| this.rst(); | |
| break; | |
| case OpCodes["+"]: | |
| operatorStack.push(opcode); | |
| operandStack.push(working.sval); | |
| working.sval = ""; | |
| break; | |
| case OpCodes["R/S"]: | |
| this.pause(); | |
| break; | |
| case ".": | |
| this.decimalPoint(opcode); | |
| break; | |
| case OpCodes["+/-"]: break; | |
| case OpCodes["="]: | |
| this.equals(); | |
| break; | |
| case "": break; // ignore blank lines | |
| case OpCodes.LRN: | |
| this.lrn(); | |
| break; | |
| default: | |
| console.log(`unknown opcode: ${opcode}`); | |
| me.println(`unknown opcode: ${opcode}`); | |
| break; | |
| } // end switch | |
| } // end if | |
| ix++; | |
| me.println(memory); | |
| }, // end act() | |
| parse2nd: function(pline) { | |
| console.log("|2 " + pline.join("_") + "|"); | |
| //const pline2 = pline.trim().split(" "); | |
| const code = pline[0]; | |
| switch (code) { | |
| case OpCodes2nd.log: break; | |
| case OpCodes2nd["C.t"]: break; | |
| case OpCodes2nd.tan: break; | |
| case OpCodes2nd.sin: break; | |
| case OpCodes2nd.cos: break; | |
| case OpCodes2nd.PI: break; | |
| case OpCodes2nd.Pause: | |
| this.pause(); | |
| break; | |
| case OpCodes2nd.Exc: break; | |
| case OpCodes2nd.Prd: break; | |
| case OpCodes2nd.Nop: break; | |
| case OpCodes2nd.FIX: break; | |
| case OpCodes2nd.Int: break; | |
| case OpCodes2nd.Deg: break; | |
| case OpCodes2nd.Dsz: break; | |
| case OpCodes2nd.Rad: break; | |
| case OpCodes2nd["x=t"]: break; | |
| case OpCodes2nd.Grad: break; | |
| case OpCodes2nd.Lbl: break; | |
| //case "": break; | |
| default: | |
| console.log(`unknown 2nd opcode: ${code}`); | |
| break; | |
| } // end switch | |
| }, // end parse2nd | |
| lrn: () => null, | |
| // ex: STO 1 this.sto(1, t) | |
| sto: (ix, val) => memory[ix] = Number(val), | |
| // ex: RCL 1 let t = this.rcl(1) | |
| rcl: (ix) => memory[ix], | |
| rst: () => { | |
| ix = 0; | |
| memory.fill(0); | |
| ava.action("break"); // pause until hit p key | |
| }, | |
| pause: () => { | |
| ava.action("break") | |
| }, | |
| // UNABLE TO USE THE FOLLOWING 5 FUNCTIONS | |
| plus: function(a, b) { | |
| return a + b; | |
| }, | |
| minus: (a, b) => a - b, | |
| times: (a, b) => a * b, | |
| div: (a, b) => a / b, | |
| digits: (val) => { | |
| working.sval += val; | |
| me.println(`working ${working.sval}`); | |
| return; | |
| }, | |
| decimalPoint: () => { | |
| working.sval += "."; | |
| return; | |
| }, | |
| equals: () => { | |
| me.println(`operatorStack ${operatorStack}`); | |
| me.println(`operandStack ${operandStack}`); | |
| const operator = operatorStack.pop(); | |
| const operand1 = operandStack.pop(); | |
| working.nval = Number(working.sval); | |
| working.sval = ""; | |
| me.println(`working ${working.nval}`); | |
| me.print(`${operand1} ${operator} ${working.nval} = `); | |
| switch (operator) { | |
| //case "+": me.println(plus(Number(operand1), working.nval)); break; plus or this.plus fail | |
| case "+": me.println(Number(operand1) + working.nval); break; | |
| case "-": me.println(Number(operand1) - working.nval); break; | |
| case "X": me.println(Number(operand1) * working.nval); break; | |
| case "/": me.println(Number(operand1) / working.nval); break; | |
| default: break; | |
| } | |
| if (operator) { | |
| working.nval = 0; // ??? works for some test cases, and not with others (test case 1) | |
| } | |
| return; | |
| } | |
| } // end beh | |
| //# sourceURL=Ec4000Parser.js | |
| ]]></DefaultContent></Ec4000Parser> | |
| </xholonClassDetails> | |
| <PhysicalSystem> | |
| <Setup/> | |
| <!-- | |
| Distance Traveled | |
| @param time0 - the time interval at time 0 | |
| @param velocity0 - the velocity at time 0 (constant velocity) | |
| --> | |
| <!--<DistanceTraveled time0="1" velocity0="13"/>--> | |
| <!-- this node must come before TestOpCodes --> | |
| <Ec4000Parser/> | |
| <!-- | |
| Test Op Codes | |
| --> | |
| <TestOpCodes/> | |
| <!-- TODO put all instances of Ec4000Program inside this container --> | |
| <Ec4000Programs> | |
| <!--1 this works! --> | |
| <Ec4000Program linesep="CRLF"><![CDATA[ | |
| 0 | |
| STO 0 | |
| 1 | |
| 1 | |
| = | |
| STO 1 | |
| 2 | |
| . | |
| 2 | |
| = | |
| STO 2 | |
| 3 | |
| = | |
| STO 3 | |
| 4 | |
| 4 | |
| . | |
| 4 | |
| 4 | |
| = | |
| STO 4 | |
| 5 | |
| = | |
| STO 5 | |
| 6 | |
| 6 | |
| 6 | |
| = | |
| STO 6 | |
| 7 | |
| = | |
| STO 7 | |
| RST | |
| ]]></Ec4000Program> | |
| <!--2 7 + 4 add two numbers with + works! --> | |
| <Ec4000Program linesep="|">7|+|4|=</Ec4000Program> | |
| <!--3 11 + 22 remember: each digit must be on its own line works! --> | |
| <Ec4000Program linesep="|">1|1|+|2|2|=</Ec4000Program> | |
| <!--4 works! --> | |
| <Ec4000Program linesep="|">1|.|1|+|3|.|4|5|=</Ec4000Program> | |
| <!--5 split this so that each character is on it's own line works! --> | |
| <Ec4000Program linesep="">1.1+3.46=</Ec4000Program> | |
| <!--6 works! --> | |
| <Ec4000Program linesep="CRLF"><![CDATA[ | |
| 5 | |
| X | |
| 4 | |
| = | |
| ]]></Ec4000Program> | |
| <!--7 I added additional digits to test 123; the original content is just 1 sort-of works! --> | |
| <Ec4000Program linesep="CRLF"> | |
| LRN | |
| STO 1 | |
| R/S | |
| STO 2 | |
| 2nd Lbl 1 | |
| RCL 1 | |
| 2nd Pause | |
| X | |
| RCL 2 | |
| = | |
| 2nd Pause | |
| 2nd Pause | |
| RCL 1 | |
| + | |
| 1 | |
| 2 | |
| 3 | |
| = | |
| STO 1 | |
| GTO 1 | |
| LRN | |
| RST | |
| </Ec4000Program> | |
| <!--8 works! --> | |
| <Ec4000Program linesep="CRLF"> | |
| 1 | |
| 4 | |
| . | |
| 2 | |
| 5 | |
| + | |
| 2 | |
| 3 | |
| = | |
| </Ec4000Program> | |
| <!--9 --> | |
| <Ec4000Program linesep="CRLF"><![CDATA[ | |
| 8 | |
| STO 0 | |
| 9 | |
| STO 1 | |
| RCL 1 | |
| - | |
| RCL 0 | |
| = | |
| R/S | |
| ]]></Ec4000Program> | |
| </Ec4000Programs> | |
| </PhysicalSystem> | |
| <DistanceTraveledbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[ | |
| var me, memory, working, beh = { | |
| postConfigure: function() { | |
| me = this.cnode.parent(); | |
| memory = new Array(8).fill(0); // memory slots are indexed from 0 to 7; here I need two slots with index 1 and 2; index 0 is unused | |
| //memory[1] = Number(me.time0); // STO 1 store a value in memory[1] t (time unit in seconds) | |
| //memory[2] = Number(me.velocity0); // STO 2 store a value in memory[2] v (velocity) | |
| this.sto(1, me.time0); | |
| this.sto(2, me.velocity0); | |
| //me.println(`${memory.length} ${memory}`); | |
| working = 0; // working memory | |
| $wnd.xh.root().append(this.cnode.remove()); | |
| }, | |
| // TODO use working+memory, rather than t v d variables | |
| act: function() { | |
| //me.print(me.xhc().name() + " "); | |
| // 2nd Lbl 1 | |
| // CALCULATE DISTANCE | |
| //let t = this.rcl(1); //memory[1]; // RCL 1 | |
| //let v = this.rcl(2); //memory[2]; // RCL 2 | |
| //let d = v * t; // distance X | |
| //me.println(d); | |
| working = this.rcl(1); | |
| //me.println(this.times(working, this.rcl(2))); | |
| // INCREMENT TIME | |
| //t = t + 1; // RCL 1 + 1 | |
| //this.sto(1, t); //memory[1] = t; // STO 1 | |
| this.sto(1, this.rcl(1) + 1); // do it all in one JavaScript step | |
| // GTO 1 | |
| }, | |
| // ex: STO 1 this.sto(1, t) | |
| sto: (ix, val) => memory[ix] = Number(val), | |
| // ex: RCL 1 let t = this.rcl(1) | |
| rcl: (ix) => memory[ix], | |
| plus: (a, b) => a + b, | |
| minus: (a, b) => a - b, | |
| times: (a, b) => a * b, | |
| div: (a, b) => a / b | |
| } | |
| //# sourceURL=DistanceTraveledbehavior.js | |
| ]]></DistanceTraveledbehavior> | |
| <Setupbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[ | |
| //$wnd.xh.root().println("SETUP " + $wnd.xh.param("TimeStepInterval")); | |
| $wnd.xh.param("TimeStepInterval", "750"); | |
| //$wnd.xh.root().println("SETUP " + $wnd.xh.param("TimeStepInterval")); | |
| //# sourceURL=Setupbehavior.js | |
| ]]></Setupbehavior> | |
| <SvgClient><Attribute_String roleName="svgUri"><![CDATA[data:image/svg+xml, | |
| <svg width="100" height="50" xmlns="http://www.w3.org/2000/svg"> | |
| <g> | |
| <title>DistanceTraveled</title> | |
| <rect id="PhysicalSystem/DistanceTraveled" fill="#98FB98" height="50" width="50" x="25" y="0"/> | |
| <g> | |
| <title>DistanceTraveled</title> | |
| <rect id="PhysicalSystem/DistanceTraveled" fill="#6AB06A" height="50" width="10" x="80" y="0"/> | |
| </g> | |
| </g> | |
| </svg> | |
| ]]></Attribute_String><Attribute_String roleName="setup">${MODELNAME_DEFAULT},${SVGURI_DEFAULT}</Attribute_String></SvgClient> | |
| </XholonWorkbook> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment