Sunday, November 12, 2023

Ham Radio Assembly Language for Browsers

<!-- HAL -->
<!DOCTYPE html>
<html>
<!-- Hi I am a comment -->
  <style >
body {background-color: gray;}
  td { overflow='clip';}
  textarea
  {background-color: green; color: white; font-size: 25px; padding = 10px}
  canvas {background-color=navy;}
  th { color:black}
  select { color:black;background-color : lime}
  table  {color: blue; text-align: center; border : 2px;}
  button {background-color : red }
  h1 {background-color : green; font-size : 24px; }
  ul {background-color : blue; color : white; border : 4px ; text-align : center}
  caption {background-color : yellow;font-size:20px;}
  p {background-color : yellow; color: black;font-size: 15px;
   text-align: center; vertical-align : top; width " 70"; hidden=true}
</style>
   <h1 align='center'>HAL</h1>
  <form id = 'dummy' >
    <button onclick ='ok()'>OK</button>
<button onclick ='cancel()'>Cancel</button>
<textarea cols=50 rows = 3 font-size = 14px>Javascript libraries use this part of the screen for user input. The dialog docking area.  Operators hide this window as desired.</textarea>


</form>
   <div align = left>
<div>
  <table >
        <caption>Simple Menu System V1.77</caption>
    <tbody >
    <tr>
      <td>
        <textarea id = 'selectedItem' cols=10 rows=1>Top</textarea>
      </td>
      <td>
        <button id ='menuNext' >Next</button>
        <button id ='menuDown' >Down</button>
        <button id ='menuUp' >Up</button>
      </td>
      <td width=200></td>

</tr>
</tbody>
</table>
</div>

</div>
<br>
<table id = 'Display1' align = left>
    <caption>Incoming Connection Reports</caption>
    <tbody class = 'Display' id = 'Displays' >
      <tr>
        <td ><textarea  class = 'Display' cols=15 id = "D1">  Frequ 10</textarea></td>
        <td><textarea  class = 'Display' cols=15 id = "D2">  Power 10</textarea>
        </td>

        
      </tr>
       <tr>
         <td id = 'connectTop'>
           <button  name = 'B11'  > B11</button><button  name = 'B12'  > B12</button><button  name = 'B13'> B13</button> <button name = 'B14'> B14</button>
       </td>
       <td id = 'connectBottom'>
         <button  name = 'B21'  > B21</button><button  name = 'B22'  > B22</button><button  name = 'B23'  > B23</button><button name = 'B24'>B24</button>
        </td>
     
       </tr>
    </tbody>

  </table>

<div >

<table >
  <colgroup>
    <col valign=top/>
    <col valign=top/>
  </colgroup>
  <caption>Ham Assembly Language</caption>
  <tbody >
    <tr>
      <th id= 'contexts'>
      <select name= "textMethods" onchange = "actionText(this)">
        <option  onclick = 'saveText()'>Save</option>
        <option  onclick = 'closeText()'>Close</option>
        <option  onclick = 'openText()'>Open</option>
        <option  onclick = 'createText()'>Create</option>
      </select>
    </th>
    <th>Log</th>
      <th id = 'sources' contenteditable=true>Sources</th>
    </tr>
      <tr id = 'textareas' valign=top>
           <td>
      <ul class = 'visible' id = 'macroList'></ul>
    </td>
      <td>
      <textarea class = 'visible' id = 'logger' cols="35" rows="25" border = 2  >Logger </textarea>
      </td>
      <td id = "textanchor"></td>
    <td>

  </td>
 
  </tr>
  </tbody>
  </table>

  </div>

  <ul  class = 'top' id = 'simpleMenu' hidden>
    <ul class = 'Debugger'>
    <li class = 'debug' onclick = 'DebugStep(INIT)'>Init</li>
    <li class = 'debug' onclick = 'DebugStep(TOKEN)'>Token</li>
    <li class = 'debug' onclick = 'DebugStep(LINE)'>Line</li>
  </ul>
  <ul  class= "usb">
      <li class = "method"  onclick ="USBConnect(current)">Connect</li>
      <li class = "method"  onclick = "openport()">open</li>
      <li class = "method"  onclick ="getports()">Ports</li>
      <li class = "method"  onclick ="getport()">Port</li>
      <li class = "method"  onclick ="readport()">Read</li>
      <li class = "method"  onclick ="writeport()">Write</li>
      <li class = "method"  onclick ="closeport()">Close</li>
      <li class = "method"  onclick ="infoport()">Info</li>
      <li class = "method"  onclick ="freeport()">Free</li>
    </ul>
    <li class = 'Exec' onclick ="ExecSource(current);">RUN</li>
   
    <ul class = 'Assembler'>
      <li class = 'list' onclick ="listLibrary()">Library</li>
      <li class = 'list' onclick ="listOpcodes()">Opcodes</li>
      <li class = 'list' onclick ="listSysOps();">Sysops</li>
      <li class = 'list' onclick ="listSymbols();">Symbols</li>
    </ul>


  </ul>

<div id = 'startcode'>


#log nice start;
  add r0 hope;
#log end;
hope sub r0 r2;
#log done it;
</div>

  <script>
//tokens
// tokens can have various types
// with precedances
//  / scoping rules
const NEWLINE = 32;
const LITERAL = 20;
const VAL = 19; const NUM = 18; const REG = 17;
const MUL = 16; const DIV = 15;
const ADD = 14; const SUB = 13;
const LP = 12; const RP = 11;
const COMMA = 10;
const MACRO = 9;
const OP = 8; const SEMI = 7;
const ALPHA = 6;
const SYSOP = 5
const DISCARD = 4;
const QUOTE = 3;

// return status
const OK = 101; const DONE =102; // normal or source done
const WAIT = 103; const ERROR = -3; // forward reference or syntax error

// symbol classes
const USER = 40; const HAL = 41; const CONST = 42;
const EMBED = 43; const MODULE = 44; const LIB = 45;
// step indicators
const TEST = 56; const INIT = 55; const INDEX = 54;
const LINE = 53; const TOKEN = 52; const OFF = 51;

// symbol,states
const NULL = -1; const UNDEF = -2;
const DEF = 202; const PREDEF = 203;
const LOG = document.getElementById('logger');
</script>
<script id='halinone'>
  
  //bigtable

// const USER,OP,SYSOP,EMBED,MODULE,LIB  / scoping rules
// All symbols in one table, sysops, opodes, user symbols
const Symbol = {str : "",expr : 0,type : 0,value : 0,handle : null}
var symtable = [
  {str : 'R0',expr : RegExp(/R0/,'i'),type : USER, value : 0,handle : 0},
  {str : 'R1',expr : RegExp(/R1/,'i'),type : USER, value : 1,handle : null},
  {str : 'R2',expr : RegExp(/R2/,'i'),type : USER, value : 2,handle : null},
  {str : 'R3',expr : RegExp(/R3/,'i'),type : USER, value : 3,handle : null},
  {str : 'define',  expr : RegExp(/define/), type : SYSOP, value : 0,handle :  function(){return define()}},
  {str : 'assign',  expr : RegExp(/assign/), type : SYSOP,value : 0,handle :  function(){return assign() }},
  {str : 'include', expr : RegExp(/include/),type : SYSOP,value : 0,handle :  function(){return include()}},
  {str : 'end',     expr : RegExp(/end/), type : SYSOP,value : 0,handle :  function(){return OK}},
  {str : 'log',     expr : RegExp(/log/), type : SYSOP,value : 0,handle :  function(){return log()}},
  {str : 'ifdef',   expr : RegExp(/ifdef/), type : SYSOP,value : 0,handle :  function(){return OK }},
  {str : 'else',    expr : RegExp(/else/) , type : SYSOP,value : 0,handle :
    function(){return OK }},
  {str : 'seg',     expr : RegExp(/seg/) , type : SYSOP,value : 0,handle :
    function(){return OK }},
  {str : 'add', expr : RegExp(/add/), type : OP, value : 0,handle : null},
  {str : 'sub', expr : RegExp(/sub/), type : OP, value : 0,handle : null},
  {str : 'mul' ,expr : RegExp(/mul/), type : OP, value : 0,handle : null},
  {str : 'div' ,expr : RegExp(/div/), type : OP, value : 0,handle : null},
  {str : 'shft',expr : RegExp(/shft/),type : OP, value : 0,handle : null},
  {str : 'and', expr : RegExp(/and/), type : OP, value : 0,handle : null},
  {str : 'or'  ,expr : RegExp(/or/),  type : OP, value : 0,handle : null},
  {str : 'xor' ,expr : RegExp(/xor/), type : OP, value : 0,handle : null},
  {str : 'addi',expr : RegExp(/addi/),type : OP, value : 0,handle : null},
  {str : 'subi',expr : RegExp(/subi/),type : OP, value : 0,handle : null},
  {str : 'ori', expr : RegExp(/ori/), type : OP, value : 0,handle : null},
  {str : 'xori',expr : RegExp(/xori/),type : OP, value : 0,handle : null},
  {str : 'clr' ,expr : RegExp(/clr/), type : OP, value : 0,handle : null},
  {str : 'comp',expr : RegExp(/comp/),type : OP, value : 0,handle : null},
  {str : 'jmp' ,expr : RegExp(/jmp/), type : OP, value : 0,handle : null},
  {str : 'call',expr : RegExp(/call/),type : OP, value : 0,handle : null},
  {str : 'bre' ,expr : RegExp(/br/) , type : OP, value : 0,handle : null},
  {str : 'brn' ,expr : RegExp(/brn/), type : OP, value : 0,handle : null},
  {str : 'br'  ,expr : RegExp(/brp/), type : OP, value : 0,handle : null},
  {str : 'ret' ,expr : RegExp(/ret/), type : OP, value : 0,handle : null},
  {str : 'btst',expr : RegExp(/btst/),type : OP, value : 0,handle : null},
  {str : 'bset',expr : RegExp(/bset/),type : OP, value : 0,handle : null},
  {str : 'ld'  ,expr : RegExp(/ld/),  type : OP, value : 0,handle : null},
  {str : 'ldm' ,expr : RegExp(/stm/), type : OP, value : 0,handle : null},
  {str : 'ldw' ,expr : RegExp(/ldw/), type : OP, value : 0,handle : null},
  {str : 'st'  ,expr : RegExp(/st/),  type : OP, value : 0,handle : null},
  {str : 'stm' ,expr : RegExp(/stm/), type : OP, value : 0,handle : null},
  {str : 'stw' ,expr : RegExp(/stw/), type : OP, value : 0,handle : null}
  ]
  var symLength = symtable.length;

 function listSymbols(type) {
   clearLog();
  strLog('\n  Symbols ');
  for(let i=0; i < symtable.length;i++)
    if(symtable[i] = type)
  strLog('\n: ' + i +' '  + symtable[i].str + ' '+symtable[i].expr +' '+symtable[i].value );
  }

function symValue(index) {
   if(index == false) index =0;
  if((index< 0) || (index > symtable.length)) return syntaxError('Bad index');
  return symtable[index].value;
}

function addSym(name,type,value) {
  var index = findSym(name)
  if(index > -1) {
    symtable[index].expr = RegExp(name);
    symtable[inde].type = type
    symtable[index].value = value;
    }
  else{
    var sym = Object(Symbol);
    sym.str =name;
    sym.expr = RegExp(name)
    sym.type = type;
    sym.value = value;
    symtable.push(sym);
  }
  return OK;
}
function findSym(name) {
    len = name.length;
    for(let i =0; i < symtable.length;i++) {
      if(len == symtable[i].str.length)
        if(symtable[i].expr.test(name)) {
        return i;
        }
    }
      return UNDEF;
}
// Drop entries from  user symbols
 function delSym() {
  do {
    if(nextToken() < 0) return syntaxError('No token')
    if(index = findSym(cc.slice) < 0)
      break;
    var type = cc.type;
    if(type == SEMI) break;
    symtable.splice(index,1);
  } while(type != SEMI);
  return endOfLine();
}


  // assembler found a symbol
  // a finite string of alpha numerics
  // that begins with an alpha
function symbol(opContext) {
  var index;
  if(arguments.length == 0) {// symbol defined
    console.log('New symbol');
    index=newSym(cc.slice(),cc.line())
    symtable[index].state = DEF;
    symtable[index].value = cc.line();
    return waitService(i);
  } else  { // this maybe a wait
    if( (index = findSym(cc.slice())) < 0){
      opContext.index =newSym(cc.slice());
      return waitRequest(opContext); // opcode context pushed onto wait stack
    } else {
      if(symtable[index].state == UNDEF) {
        opContext.index = index;
        return waitRequest(opContext); // opcode context pushed onto wait stace
      } else {
        cc.setIndex(symtable[index].value)
        cc.setType(VAL); //resolved
        return OK
        }
      }
    }
}
// text
 function clearLog() {
  LOG.textContent = ' ';
}
// send string to log
function strLog(str){
  LOG.textContent+=  str;
  }
 // send string to log
function strPrependLog(str){
  LOG.textContent =  str + LOG.textContent;
  }
function srcCharByIndex(node,index) {
  var ch = node.textContent.charAt(index);
  return ch
}
 function tokenText(str) {
  var s= String();
  s =  '|'+cc.slice()+'|';
  //s.replace(/\n/,'X')
  if(arguments > 1) s += str;
  strPrependLog(
  '\nTok ' + s + ' ' + ' t: ' + cc.type()+' s: '+cc.start()+ ' e: ' + cc.end()+'\n' );
}

// generic find a name among
// a list of html children
function findItemByName(items,name) {
  for(i=0;i < items.length;i++)
    if(items[i].name == name)
      return items[i];
  return null;
}
function findText(name) {
  items = document.getElementById('textanchor').children;
  return findItemByName(items,name);
}

function findListItem(name) {
  items = document.getElementsByClassName('openmacro');
  return findItemByName(items,name);
}
// when the user clicks on a macro list item
function setListEvent(node) {
  node.addEventListener('click', () => {
  showText(node.name);
  blinkListItems(node.name);
  //console.log('Set up ' +node.name)
  });
}
function newListItem(name) {
  var list = document.createElement('li')
  list.name = name;
  list.className = 'openmacro'
  list.textContent = name
  //console.log('NewItem '+ name);
  setListEvent(list);
  document.getElementById('macroList').appendChild(list);
  showText(name);
  }
function delListItem(name) {
  parent = document.getElementById('macroList');
  node = findName(name,parent.children);
  parents.removeChild(node);
}
////////////// Methods to manage textareas////////////////
function listTexts() {
  var items = document.getElementById('textanchor').children;
  for(let i =0; i < items.length;i++) {
    strLog(': '+ items[i].name);
  }
}
function saveText() {
  strPrependLog('Save\n');
  var nameNode =  document.getElementById('sources');
  var textNode = findTextByName(nameNode.textContent);
  if(textNode.hidden == false) {// The macro in focus
    localStorage.setItem(nameNode.name,textNode.textContent);
    nameSelector();
  }
  return;
}
// th element as editable input
function newText(name) {
  strPrependLog('New\n');
  if(name == null)
    name = document.findElementByID('sources').textContent;
  addText(name);
}
function openText(name) {
  strPrependLog('Open\n');
}
function closeText() { strPrependLog('Close\n');
  parent = document.getElementById('macroList');
  name = document.getElementById('sources').textContent;
  node = nodeFindByName(parent.chldren,name);
  parent.removeChild(node);
  parent = documemt.getElementById('textanchor');
  node = nodeFindByName(parent.chldren,name);
  parent.removeChild(node);
}
function showText(name) {
  items = document.getElementById('textanchor').children;
  for(i=0;i < items.length;i++) {
    if(items[i].name == name)
      items[i].hidden=false;
    else
      items[i].hidden=true;
    document.getElementById('sources').textContent = name;
  }
}
function createText(name) {
  var td = document.getElementById('textanchor');
  var text = document.createElement('textarea');
  text.hidden = false;
  text.cols =30
  text.rows = 15
  if(name == null)
  text.name = document.getElementById('sources').textContent;
  else
  text.name = name;
  text.className = 'invisible';
  td.appendChild(text);
  showText(text.name);
  return text;
  }
  function context() {
    this.hidden = true;
    this.nextSibling().hidden = false;
    //this.parent.onchange();
  }
function actionText(node) {
  var items = node.children;
  for(i=0;i < items.length;i++)
    if(items[i].selected) {
      items[i].onclick(items[i].value);
      return;}
  }

function blinkListItems(name) {
  items = document.getElementById('macroList').children;
  radioButtons(name,items);
}

function source(name) {
  getElementById('sources').textContent=name;
  showTextArea(name);
  console.log('arrived');
}

// Make a name list from local storage
function nameSelector() {
  var len = localStorage.length;
  parent = document.getElementById('sources');
  var  sel = document.createElement('select');
  sel.hidden = true;
  sel.onchange = 'source()'.
  parent.append(sel);
  for(let i = 0;i < len;i++) {
    name = localStorage.key(i);
    var opt = document.createElement('option');
    opt.textContent = name;
    sel.appendChild(opt)
  }
  opt = document.createElement('option');
  opt.textContent='rename';
  sel.appendChild(opt);
}


function listLibrary() {
  clearLog();
  var len = localStorage.length;
  strLog('\nLocal storage ' + len)
  for(let i =0;i < len;i++) {
    var name = localStorage.key(i);
    value = localStorage.getItem(name);
    strLog('\n '+i+': ' +name + ' '+ value);
    }
  }
  // sysops

  //Install a module from local storage
// put up a selector for it, add its own
// text area, and install the name
// on the sysop table
function installModule(name,str) {
    console.log('Install');
    if(arguments.length == 2)
      localStorage.setItem(name,str);
    var index =  findSym(name);  // is it installed?
    if((index > -1) && (index < builtinsLength))
        return syntaxError('Opcode  redefined i '+index+' '+builtinsLength+'|'+name+'|')
    if(index >= 0) {  // already in the opcode table
      node= findListItem(name);
      if(node==null) syntaxError('Library misorder')
      node = findText(name)
      if(node== 0) syntaxError('Set up wrong')
    } else { // new set up
      strPrependLog('\nNew set '+name);
      node = createText(name);
      console.log('Installed  '+node.name + ' '+name);
      addSym(name);
      newListItem(name);
    }
    node.textContent=localStorage.getItem(name);
    return OK;
}

// drop an entry in the sysop table
 function undef() {
   remove(delSys); }
// in user table
function remove() {
   remove(delSym); }

function define() {
  do {
    if(nextToken() < 0) return syntaxError('No token')
      newSysop(cc.slice());
    }while(cc.type() != SEMI)
}
// manipulate the user symbol table
function assign(){
  do {
    if(nextToken() < 0) return syntaxError('No token')
    type = cc.type();
    if(type() == SEMI) break;
    token1 = cc.slice();
    if(nextToken() > 0) {
      type = cc.type()
      if(type ==ARG)
        newSym(token1,args.pop());
      else if(type = NUM)
        newSym(token1,JSON.parse(cc.slice()));
    } else
    newSym(token1,UNDEF);
    strPrependLog('Define: '+ token1 + ' ' + symValue(findSym(token1))+'\n')
  } while(cc.type() != SEMI);
  //nextToken(); //pass the semi
  return endOfLine();
}

function log(ptr){
  var start,end;
  var eol = endOfLine(); // move the newline pointer
  //console.log('log ' + newline.lastIndex + ' '+ SRC.textContent.length);
  start = cc.end();
  if(newline.lastIndex !== 0)
    end = newline.lastIndex-1;
  else
    end = cc.node().textContent.length;
  strPrependLog('\n '+ cc.slice(start,end)+'\n');
  return eol;
}
  function newSysop(name) {
  var i=0;
  var symbol = new Object(opCode);
  i = findSym(name,optable)
  console.log('New sys  '+name + ' '+i)
  if(i < 0) {// New entry
    symbol.str = name;
    symbol.expr = RegExp(name);
    symbol.idx=optable.length+1;
    optable.push(symbol);
    opcodesLength = optable.length;
  }
  return OK;
}
function delsysop(name) {
  i = findSym(name,optable);
  if(i < 0) return OK;
  optable.splice(i,1);
  return OK;
}

function include(){
  var node;
    console.log('Include');
    do {
      r=nextToken()
      var type = cc.type();
      if(type == SEMI)
        break; // move the newline pointer
      if(r < 0) return syntaxError('No token');
      if(type != ALPHA) return syntaxError('Expected Name');
      var name = cc.slice();
      installsysop(name);
      strPrependLog('Add sysop '+ name+'\n')
    } while(type != SEMI);
  return OK;
}
// Bracket quoted HAL must be valid
// Should end with end; pseudo opcode
function macro() {
  var index = nextToken();
  if(index > -1) syntaxError('cannot redefine');
  token = cc.slice();
  nextToken();
  if(cc.type() != LB) syntaxError('No start');
  newOpcode(token,cc.end());
  while(true) {
    nextToken()
    if(cc.type() == RB)
      break;
    endOfLine(); // skip the line
  }
}
</script>


<script>
  
// sneak in a fake source on startup
function sneak() {
  var str = document.getElementById('startcode').textContent
  installModule('source',str);
}
sneak();
</script>
<script>
 // exec

//Define a context of some type  of token
// must include the node holding textContent,
// and a start, end, lastIndex
// scanned in a  textArea of node, possibly
//having a symbol index pointing into the symbol table
// .
const Context = { start : 0, end : 0, type : 0,
                  node : 0,index : 0,line:1,lastIndex:0}
var CS = Array();

const cc = {
  k : -1,
  version : function(){ strPrependLog('V1.0\n')},
  length : function(){ return CS[this.k].end - CS[this.k].start;},
  get : function() {return CS[this.k]},
  clear : function(){CS.length =0; this.k =-1;},
  incLine : function(){ CS[this.k].line++;return CS[this.k].line;},
  line : function(){ return CS[this.k].line;},
  push : function(x){ this.k++; return CS.push(x)},
  pop : function(){ this.k--; return CS.pop()},
  startChar : function(){ return CS[this.k].node.textContent.charAt(CS[this.k].start)},
  endChar   : function(){ return CS[this.k].node.textContent.charAt(CS[this.k].end)},
  indexChar : function(index) { return CS[this.k].node.textContent.charAt(index);},
  setStart : function(start) {CS[this.k].start =start;},
  incStart : function(start) {CS[this.k].start++;},
  setLastIndex : function() {CS[this.k].lastIndex =CS[this.k].end;},
  start : function(start) {return  CS[this.k].start;},
  setIndex : function(index) {CS[this.k].index =index;},
  setEnd : function(end) { CS[this.k].end =end;},
  end : function() {return CS[this.k].end;},
  node : function() {return CS[this.k].node;},
  setType : function(type) { CS[this.k].type =type;},
  type : function() {return CS[this.k].type;},
  text : function() { return CS[this.k.node.textContent];},
  slice : function(start,end){
    var s,e;
    var i = this.k;
    if(arguments.length > 0)  s = start; else s = CS[this.k].start;
    if(arguments.length > 1) e = end; else e =CS[this.k].end;
    return CS[this.k].node.textContent.slice(s,e);
  },
  twoChars : function(){
    var s = CS[this.k].end;  // aftr the newline
    return CS[this.k].node.textContent.slice(s,s+2);
  }
}

// Initialize the assembler
function initHal() {
  tokend.lastIndex =0;
  newline.lastIndex =0;//
  clearLog();
  resetRpn();
  //resetWaits();
  return OK;
}
function endOfLine() {
  newline.lastIndex = tokend.lastIndex;
  newline.exec(cc.node().textContent)
  if(newline.lastIndex !== 0) {
// Do not allow parser to chew past arguments
    tokend.lastIndex = newline.lastIndex;
   return OK;
  }else return DONE;
  }
  // everything needed to process textContent
function newContext(node) {
  var p = new Object(CONTEXT);
  var x =0;
  p.lastIndex = 0;
  p.line = 1;
  p.start = 0;
  p.end = 0;
  p.type = DISCARD;
  p.node = node;
  p.name = node.name;
  cc.push(p);
  // Newline required here
  if(cc.indexChar(0) != '\n') return syntaxError('No starting newline');
  strLog('New Context ' + node.name);
  return endOfLine();
}
function execLines(){
  var result=OK;
  var count = 0;
  while( (result == OK) || (result == WAIT))  {
    count++;
    result = firstColumn();
    if(result==DONE)
      return strPrependLog('\nSource done');
    }
    syntaxAlert('Assembly error ' + result)
  }
  
function ExecSource() {
  node = findText('source')
  if(node == null) return syntaxError('Nosource');
  initHal();
  console.log('CC ' +cc.k)
  newContext(node);
  execLines();
  return OK;
}



function listToken() {
  var result = nextToken();
  if(result == OK)
    tokenText();
  return result;
}
function listTokens() {
  var result=OK;
  var str;
  clearLog()
  strPrependLog('\n...All tokens....');
  cc.setStart(0);
  cc.setEnd(1);
  tokstart.lastIndex =0;
  tokend.lastIndex = 0;
  newline.lastIndex =0;
  //endOfLine(); // to starting line
  do result = listToken();  while(result == OK);
  strPrependLog('End of source');
  return result;
}
function DebugStep(as) {
  var result;
  switch(as) {
    case TEST:
      e = findText('source');
      if(e.hidden == 1) delete e.hidden;
      else e.hidden = 1;
      break;
    case TOKEN :
      if(listToken() == DONE) InitHal();
    break;+tokend.lastIndex
    case LINE :
      if(nextToken() != DONE);
        result = firstColumn();
      //console.log('col end |'+cc.slice()+'|'+tokend.lastIndex);
    break;
    case INDEX:
    break;
    case INIT:
      var node = findText('source');
      if(node == null) console.log('Nosource');
      initHal();
      newContext(node);
    break;
  }
}

// forward reference array
var waits = new Array();
function waitService(index) {
  var n = waits.length;
  console.log('Wait service len ' + n)
  for(let i = 0; i < n;i++)
    if(waits[i].index == index) {
      cc.push(waits[i]);
      console.log('Service '+tokenText())
      waits.splice(i,1);
      argsProcess();
      CS.pop();
      }
    return OK;
  }
function waitRequest(context,index) {
  console.log('Wait request');
  context.index =index;
  waits.push(context);
  return WAIT;
}
function opProcess(token){}
function funProcess(token) {
  var result = 0;
  var textNodes = document.getElementsByClassName('invisible');
  var el = findName(textNodes,optable[token.index].str);
  initHal();
  result = newContext(el);
  while(result != DONE) {
      result = firstColumn();
  }
  return OK;
}

 //
// Global and local  regx
const newline = RegExp(/\n/ ,'g'); // a regx to find end of line
const tokstart = RegExp(/\S|\n/, 'g');
const semi =  RegExp(/;/,'g');
const tokend =  RegExp(/\W/,'g'); // no alpha or numeric
const quote =  RegExp(/\"/,'g'); // open literal
const bracket =  RegExp(/\{\}/,'g'); // open literal
// local operators

const alum =  RegExp(/\w/); // alpha or numeric
const space =  RegExp(/\t| /); // valid separators
const nospace =  RegExp(/\S/); // drk
const operator = RegExp(/[;\*\\\+\-#\(\)]/);
const white = RegExp(/\s/);  //not words

const primes = [
{ str : 'register', expr :  RegExp(/r\d/), type : REG},
{ str : 'alpha',    expr :  RegExp(/[a-zA-Z]/),type : ALPHA},
{ str : 'number',   expr :  RegExp(/[0-9]/),type : NUM},
{ str : 'sysop',    expr :  RegExp(/#/),type : SYSOP},
{ str : 'muliply',  expr :  RegExp(/[\*]/),type : MUL},
{ str : 'divide',   expr:   RegExp(/[\\]/),type : DIV},
{ str : 'add',      expr :  RegExp(/[\+]/),type : ADD},
{ str : 'sub',      expr :  RegExp(/[\-]/),type : SUB},
{ str : 'comma',    expr :  RegExp(/\,/),type : COMMA},
{ str : 'semi',     expr :  RegExp(/;/),type : SEMI},
{ str : 'left',     expr :  RegExp(/\(/),type : LP},
{ str : 'right',    expr :  RegExp(/\)/),type : RP},
{ str : 'newline',  expr :  RegExp(/\n/),type : NEWLINE}
]
const primeLength = primes.length;

function regtest(regx,str){
  
  let x = regx.test(str);
  return x;
}
 // errors
function syntaxAlert(msg) {
    var l;
    alert(msg +' type '+cc.type()+' '+cc.start()+' '+cc.end()+' '+cc.slice()+'\n')
    return OK;
  }
  // errors
function syntaxError(msg) {
    var l;
    strPrependLog(msg +' '+cc.start()+' '+cc.end()+' '+cc.slice()+'\n')
    return ERROR;
  }
function typeGet(index,str){
  let x = primes[index].expr.test(str);
  if(x) return primes[index].type;
  else return ERROR;
}
function updateToken(index) {
  var type,ch;
    ch = cc.indexChar(index);

    for(i=0;i < primeLength;i++)
      if( (type = typeGet(i,ch)) >  -1){
        cc.setType(type);
        return  cc.type();
      }
    return syntaxError('No type |'+ch+'|' );
  }

//args process found a quote character
function literal() {
  cc.setStart(cc.end());
  quote.lastIndex = cc.start();
  quote.exec(cc.text());
  if( (quote.lastIndex ==0) || (quote.lastIndex >= newlne.lastIndex) )
    return syntaxError('missing quote');
  cc.setEnd(quote.lastIndex-1);
  rpn();
  return OK;
  }
  
// The function sets the start and end indices
// for a token of three classes:
//  numeric, alphanumeric and single char operators
// New lin3 is a valid operator, right associated.
// It changes assmbler state based on the next two chars.
  function nextToken() {
    SRC= cc.node();
    if(SRC ===null) syntaxError('No source');
    var ch,index,result;
    tokstart.lastIndex = tokend.lastIndex-1; // get end of last token
    if(regtest(space,SRC.textContent.charAt(tokstart.lastIndex) )){
      tokstart.exec(cc.node().textContent)
      if(tokstart.lastIndex == 0) return DONE;
      } else tokstart.lastIndex++;
    updateToken(tokstart.lastIndex-1);
    tokend.lastIndex = tokstart.lastIndex;  // get start of current token
    if(regtest(alum,SRC.textContent.charAt(tokend.lastIndex-1)) ){
      tokend.exec(SRC.textContent);
      if(tokend.lastIndex == 0) return syntaxError('No line terminator')
      } else tokend.lastIndex++;  //must be a single char
    cc.setStart(tokstart.lastIndex-1);
    cc.setEnd(tokend.lastIndex-1);
    return OK;
    }
//First argument always an opcode
// handle opcode and multiple arguments
// symbol argument, literals, end of line
function argsProcess() {
  opContext = cc.get(); // restart here on forward reference
  if(nextToken() == DONE) return DONE;
  if(cc.type() == NEWLINE) { //blank line
    return OK;
  }
  // opcode required here
  index = findSym(cc.slice());
  if( index< 0) return syntaxError('\nNo op ' + cc.slice())
  rpn(); // process opcode
  let type = cc.type();
  while((type !=  SEMI) && (type != NEWLINE )) {
    if(nextToken() == ERROR) return syntaxError('Or a bug'); // line done
    type = cc.type();
    if(type == QUOTE) { // literals shipped as is.
      literal(); // one literal per line
      break;
    } else if(type == ALPHA)
        if(symbol(opContext ) == WAIT ) {
          return endOfLine(); // fludh to end of line
        }
 // ready to activate rpn)
    if(type > OP )
     rpn();
  }
  return OK;
  //endOfLine();
}
//the currnt token is newline
// which triggers  first column call
 function  firstColumn() {
  var result;
  if(cc.type() != NEWLINE) return syntaxError('Col bug');
  var twochars = cc.twoChars();

  // arrive here once per line and never more
  cc.incLine();  // Every context keeps its own line counter
  if(white.test(twochars)) // if no column one work
    return argsProcess(); // pass it on
  console.log('after args |'+cc.slice()+'|'+tokend.lastIndex);
  nextToken(); // there is column one work
  if(cc.type() == SYSOP) {
    if(nextToken() < 0)return syntaxError('No sysop ');
      let index = findMacro(cc.slice());
      if(index < 0)
        return syntaxError('Undefined sysop ');
      else {
        //console.log('Sysop '+cc.slice())
        return mactable[index].handle();
      }
      }
    // source defines symbol
    else if(cc.type() == ALPHA) {
      // we just set the symbol to the current lineZ
      symbol();
      return argsProcess();
      }
    else
      return syntaxError('Illegal char ');
}
if ("serial" in navigator) {
  // The Web Serial API is supported.
}
var port;

async function getport() {
  console.log('get port')
  port = await navigator.serial.requestPort();
  if(port)
    var info = port.getInfo();
  else console.log('no port')
  console.log('info '+ info)
}
// Get all serial ports the user has previously granted the website access to.
async function getports() {
 ports = await navigator.serial.getPorts();
 console.log('Get ports ' + ports.length)
 console.log(ports[0])
}

async function closeport() {
  await port.close();
}

// Filter on devices with te Arduino Uno USB Vendor/Product IDs.
const filters = [
  { usbVendorId: 0x2341, usbProductId: 0x0043 },
  { usbVendorId: 0x2341, usbProductId: 0x0001 }
];

// Prompt user to select an Arduino Uno device.
async function getPort() {
port = await navigator.serial.requestPort([filters]);
if(port)
 var info = port.getInfo();
}

// Wait for the serial port to open.
async function openport() {
await port.open({ baudRate: 9600 });
}
//After the serial port connection is established, the readable and writable properties //from the SerialPort object return a ReadableStream and a WritableStream. Those will be //used to receive data from and send data to the serial device. Both use Uint8Array //instances for data transfer.

//When new data arrives from the serial device, port.readable.getReader().read() returns //two properties asynchronously: the value and a done boolean. If done is true, the serial //port has been closed or there is no more data coming in. Calling //port.readable.getReader() creates a reader and locks readable to it. While readable is //locked, the serial port can't be closed.

async function readport() {
reader = port.readable.getReader();
  console.log('read '+  reader);
// Listen to data coming from the serial device.
while (true) {

  var { value, done } = await reader.read();
  if (done)
  {
    console.log('Value ' + value.length)
    // Allow the serial port to be closed later.
    reader.releaseLock();
    break;
  }
  // value is a Uint8Array.
}
  console.log('Done '+value.length);
}
function freeport(){
  if(reader)
    reader.releaseLock();
  if(writer)
    writr.relaseLock();
}

async function writeport() {
  var writer = port.writable.getWriter();
  var data = new Uint8Array([104, 101, 108, 108, 111,010,013]); // hello
  await writer.write(data);
  console.log('Written ');
  // Allow the serial port to be closed later.
  writer.releaseLock();
}
function getreader() {
const textDecoder = new TextDecoderStream();
const readableStreamClosed = port.readable.pipeTo(textDecoder.writable);
reader = textDecoder.readable.getReader();
}

// menu
var iCount=-1;
    var current;
    var selected =  document.getElementById("selectedItem")
    var menuItems =  document.getElementById('simpleMenu').childNodes
    current= menuItems[0];
    parent=current.parentNode;
    
 function radioButtons(name,items){
  for(i=0;i < items.length;i++) {
    if(items[i].name == name)
      items[i].style.backgroundColor = "orange";
    else
      items[i].style.backgroundColor = "navy";
  }
}
   
    // set up the radio buttons
function setRadioEvent(element) {
  element.addEventListener('click', () => {
  element.style.backgroundColor = 'red'
  let items=element.parentNode.children;
    radioButtons(element.name,items);
    //for(i=0;i<items.length;i++)
      // if(items[i].name != element.name)
        // items[i].style.backgroundColor = "blue"
    });
  }

 
function setConnects(str) {
  var element = document.getElementById(str)
  var items = element.children
  for(i=0; i < items.length;i++) setRadioEvent(items[i]);
  }
   
button = document.getElementById("menuNext")
 button.addEventListener('click', () => {

        do{
        iCount++
        if(menuItems.length == iCount) iCount = 0;
        current =  menuItems[iCount];
          if(current.nodeName=="UL")
            selected.textContent= current.className;
          else if(current.nodeName=="LI")
            selected.textContent= current.textContent;
      } while(current.nodeType !=1)
  
      });
   
   
   
  button = document.getElementById("menuDown")
  button.addEventListener('click', () => {
    if(current.nodeName == "UL") {
        parent=current;
        menuItems = parent.childNodes;
        current =  menuItems[0];
        iCount=-1
        if(current.nodeName=="UL")
              selected.textContent= current.className
        }
        else {
          selected.textContent= current.textContent;
          current.onclick()
        }
   });

 button = document.getElementById("menuUp")
 button.addEventListener('click', () => {
    if(parent.nodeName =="UL") {
      current = parent
      parent = current.parentNode;
      menuItems = parent.childNodes;
      iCount=-1
      selected.textContent= current.className
    } else
    console.log('To level')

   });
      setConnects('connectTop')
      setConnects('connectBottom')
      
      // resolve
objectCode = new Uint8Array(100);
arg = new Array();
oper = new Array();
function resetRpn() {
  arg.length = 0;
  oper.length = 0;}

function operLast()  {
  return oper[oper.length-1]}
function argLast()  {
  return arg[arg.length-1]}
  
function OpProcess(index) {
  var result = 0;
  switch(optable[index].type) {
    case MODULE:
      var str = optable[index].str;
      var node = findTextarea(str);
      newContext(node);
      execLines();
      cc.pop();
    break
    case MACRO:
      var state = nextToken();
      while(state != DONE)
      executeLine();
    break
    case END:
     return DONE;
     break;
}
  if(index < builtinsLength) processOpcode(index)
  else { // must be a module
    var str = optable[index].str;
    var node = findText(str);
    newContext(node);
    execLines();
    CS.pop();
  }

  return OK;
}
function flushLiteral(addr) {
  start = cc.start();
  end = start + cc.length;
  node=cc.node();
  while(start < end) {
    objectCode[addr] = node.textContent[start];
    start++;addr++;
  }
}
function flushNum(n,addr) {
  var list = String('0123456789abcdef')
  var out = String(' ');
  bit = 1;
  while(bit < n) {
    var r = 0;
    var t = 1;
    for(j=0;j < 4;j++) { // for each bit
      if(n & bit)
        r += t;
      t *=2;
      bit *=2;
    }
    out = list[r] +out;
  }
  for(j=0;j < out.length;j++){
    objectCode[addr] = out[j];
    addr++;
  }
    return addr;
}
// numbers or operators
function flushExpression(arg,addr) {
  var len = expr.length;
  var x;
  var y;
  var z;
  console.log('flush');
  while(arg.length>2) {  // there should remain one resolved literal
    x = arg.pop();
    y = arg.pop();
    z = 0;
      switch(lastOper.type) {
        case MUL:
          z = (x*y);
        break;
        case DIV:
          z =(x/y);
          break;
        case ADD:
          z =(x+y);
          break;
        case SUB:
          z =(x-y)
          break;
      }
      arg.push(z);
      arg.splice(0,1)
    }
    flushNum(z);
    return OK;
  }
// make the source line shunted
// evaluate arg expressions
// separat arguments
var addr=0;
function rpn()
{
  strLog('\nrpn ' + cc.slice());
  var type = cc.type();
    switch(type) {
      case LITERAL:
        addr=flushLiteral(addr);
      break;
      case VAL:
        arg.push(cc.index());
        break;
      case NUM:
        x = JSON.parse(cc.slice());
        arg.push(x);
     break;
      case RP:
        while(oper.length > 0 )
          if (type = lastOper.type != LP)
            arg.push(oper.pop().type)
          else
            addr = flushExpression(addr);
          if(oper.length == 0)return syntaxError('no left parenth')
          oper.pop();
        break;
      case SEMI:  // The last argument
      if(oper.length==0) return(syntaxError('Semi-colon mismatch'));
        addr = flushExpression(addr);  // one last arg
        type = oper.pop().type;
        if((type != OP) && (type != MACRO))
          return(sytaxError('Line not closed'));
        // call the OP or MACRO process
        processOpcode(cc.index());
        break;
      break;
      case COMMA:
       addr = flushExpression(addr);
       break
      case ALPHA:
      case SYSOP:
        return syntaxError('Not prime');
      break;
      default:
        while( (oper.length != 0) &&  (operLast.type > type)  )
          arg.push(oper.pop().type);
    }
    return OK;
  }
</script>

  </html>

Monday, September 25, 2023

Progressive politicians on the take

 

Busted! Adam Schiff Funneled Millions To Defense Contractors After Taking Donations


Gavin Newsom, Liz Warren, Nancy and Diane, Menendez.  All of them believe they are allowed to steal from the poor.

Sunday, September 24, 2023

Commie rats are control freaks

EXCLUSIVE: Xi Jinping's centralisation of China's economy appears to be causing a stall - something which could spell doom for the CCP, a former senior White House official told Daily Express US.


Sounds a lot like California where the teacher's union rules the ship.

Tuesday, September 5, 2023

Cannot disrespect the great color genderizor

 

Biden Allies Say It Would Be Racist For Gavin Newsom To Run In 2024


The Kamalatic, a new kitchen tool we have to try out.  It may, in fact, be illegal in California for Gavin to run this term.  I think his unions have jurisdiction in this case. and they will vote for the color/genderizor.

Wednesday, August 30, 2023

Srokes in mid conference

Mitch McConnell freezes again during a press conference

Brains in the Swamp are turning to silly putty.

Tuesday, August 8, 2023

Prolife Reubs plan to spend trillions on artificial wombs

 The GOP awakened a broad coalition to turn out to vote against their referendum designed to hinder abortion. It could be a massive problem for the party for a long time.

It is like signaling that the Dems do.  The artificial wombs are just a few years away, it is easy to abort a fetus alive.  Put those two together and the most massive miscalculation ever was letting the Supremes treat women as womb slaves. An incredible level os stupidity that sets the Repubs back for many years.