Thursday, December 13, 2018

Default, Shunt and Console loop, all one file

I guess, still short, under 600 I think  But with one clib compile (gcc bus.c), you get universal access to all of linux via a simple but  swappable syntax, complete with variables and expressions.. But we keep shunt as a built in, Console loop will check it early for access from the Bus.

Getting access to linux commands is shared or piped, as long as it is cmd format. Anything, managed under your own syntax rules. All Xchars compatible on output.

Now Ncurses can emulate the Vintage Royal typewrite of 1930, but it requires 20,000 lines of text to just get ready to compile



And below is the entire thing, it compiles and needs a few days of test. A mere 600 lines, all I need, except no Xchars.  Calling Shunt across the Bus has two forms, one form you call it with a string pointer in arg1; the other, the args itself is the input stack, tokens preparsed. I have Shunt1 and Shunt2, though Hardly Default.  Later I will toss in Xchars, all 350 lines, making nearly a grand. But I get an automatic GUI for any of a thousand linux utilities, especially my favorite, gdb. In Xchars, one changes font, even font size. But I say if they want real graphic, load a graphics package, they are all loadable, else I will generate the xcb loadable version.  Unload Xchars, or any other graphic package loaded, then load your favorite. Use linux style command formaat. If the application wants to mix and match, then the application needs a window manager in its own syntax. I do windows like at old typewriter, pages fling all over uncontrolled, me cursing.



////// Scripting tags ///////////
// Finds all the points n a src that match on of the syntax tags
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <dlfcn.h>
#define MAX_SYM 100
#define CODEBASE 100
#define VARBASE 10
typedef struct {
char * str;
int form;
int len;
} Tag;
// Not all used, needs trimming
enum {null,operand, assign,keyterm,cast,open,close,variable,
integer,string,undefined,comment};
#define T(a,b) {a,b,sizeof(a)-1}
// Over defined but all included from a cut n paste from
// another source
Tag syntax[] = {
// The first variable types always first
//  Ordered by priority
  T("",integer), T("",string), T("",variable),
T("=",assign),
//T(">",operand),T("<",operand)),T( ">=",operand),T("<="operand), T("==",operand),
//T("||",operand),
T("+",operand),T("-",operand),T("^",operand),T("%",operand),
//T("!=",operand,),T("**",operand,,T("<<",binary), T(">>",binary),
T("*",operand),T("/",operand),T("!",operand),T("~",operand),
T("int",cast),T("char",cast),
T("{",open),T("}",close),T("(",operand),T(")",operand),
T("while",keyterm),
//T("break",keyterm), T("continue",keyterm),
T(";",keyterm),
//T("return",keyterm),
//T("&",unary),
// T("|",0),
//T("[",array),T("]",array),T(",",null)
T("//",comment)};
const int Ntags=  sizeof(syntax)/sizeof(Tag);
typedef struct {
Tag * tag;
int tid;
char * src;
int len; } List;
typedef List * PList;
// First pass of sript interpreter finds tags
// Just checks the list of syntax used by the language
// Dunno about symbols, still parsing
typedef struct {
char  *name;
int len;
int basetype;} Sym;
typedef  Sym* PSym;
Sym * PutName(char * name, int len);
Sym * GetName(char * name, int len);



int find_tag(char  * code) {
int i=3;  // First tags reserved
Tag * ptr;
while(i < Ntags) {
ptr = &syntax[i];
if(!strncmp(code,ptr->str,ptr->len))
return(i);
i++;
}
return(-1);
}
// Bottom of args has this structure
// this is likely to change mucho, careful
typedef struct {
long Code[CODEBASE];
long Accum;
long Start;
long End;
long Depth;
long Data[CODEBASE];
} Base;
typedef Base * PBase;
Base argslist;
// Entry point for processing script
// ParseArgs string_of_syntax
int  ParseArgs(int *argc,void * args[]) {
int idx=*argc;
char* src = args[idx+1];
Tag * nxt;
int len;
int tid;
PBase base = (PBase) args;
List * list = calloc(100,sizeof(List));
List * lstart=list;
base->Accum = (long) lstart;
*argc += 2;
while(*src) {
while(*src && isspace(*src) ) src++;
if(!*src) return(1);
tid = find_tag(src);// first entries are reserved
list->tid=tid;
if(tid >= 0) {
nxt = &syntax[tid];
if(nxt->form == comment)  {
while(*src != '\n') src++;
src++;
list->src=0;
list->tag=nxt;
list->len=0;
}
else {
list->src=nxt->str;  // point to the table string not src
list->tag=nxt;
list->len=nxt->len;
src += nxt->len;
list++;
}
} else { // Raw Text, varible or undefined pass thru
len=0;
if(isdigit(*src)) tid=0;
else tid=1;
list->tag = &syntax[tid];
list->tid=tid;
list->src=src;
// Valid linux command syntax
while(isalnum(*src) || *src == '-')  {
src++;
len++;
}
list->len=len;
list++;
}
}
return(1);
}

////// Symbols////////////

Sym symbols[MAX_SYM];
int symbols_index=0;

Sym * GetName(char * name,int len) {
int i;
for(i=0;i < symbols_index;i++){  // first entry reserved
if(!strncmp(symbols[i].name,name,len))
return(&symbols[i]);
}
return(0);
}

Sym * PutName(char * name, int len) {
Sym * p = &symbols[symbols_index];
symbols_index++;
p->name=name;
p->len=len;
return(p);
}
void ListSyms(void) {
int i;
char temp[20];
printf("Syms\n");
for(i=0;i < symbols_index;i++) {
temp[0]=0;
strncat(temp,symbols[i].name,symbols[i].len);
printf("%s %d %d\n",
temp,symbols[i].len,symbols[i].basetype);
}
}

typedef int EntryType(int *, void**);
EntryType  * ExecCommand;
int Entry(int *argc, void * args[]);


// Executes compiled Default
void syntax_error(char * error, char * src) {
printf("Syntax message: ");
if(error)
printf(" %s\n",error);
if(src)
printf(" %s\n",src);
printf("s\n");
exit(-1);
}

// Consume the shunting output
int Expr(int *argc,void * args[]) {
PBase base = &argslist;
long idx=*argc +1;
long accum= base->Accum; // Passing around accumulator
int x;
Tag * op1,op2;
long l,r;
char * op;
char * operand;
base->Accum = atoi((char *) base->Code[idx+1]);
idx++;
do {
if(!(op = (char *) base->Code[idx])) break;
if(*op == ';') break;
if(strcmp(op, "--")) {base->Accum--; idx += 1;}
if(strcmp(op, "++")) {base->Accum++; idx += 1;}
if(strcmp(op, "="))  break;
operand =(char *) base->Code[idx+1];
if(!operand) syntax_error("No operand", op);
r = atoi(operand);
idx += 2;
if(strcmp(op, "*") ) base->Accum *= r;
else if(strcmp(op, "/")) base->Accum /= r;
else if(strcmp(op, "+")) base->Accum += r;
else if(strcmp(op, "-")) base->Accum -= r;
else syntax_error("Expr error\n",op);
} while(*op );
base->Accum =  accum;
return(1);
}
// All the code needed to execute Default
// Hmm.. dunno yet
int Cast(int *argc,void* args[]) {
return(1);
 }

//  Handle a pair of {   }
int Block(int * argc,void* args[]) {
int idx=*argc;
PBase base = (PBase)args;
long end   = (long) base->End;
idx += 2;
*argc = idx;
while(*argc != end){
base->Start=*argc;
ExecCommand(argc,args);
*argc=base->Start;
}
return(1);
}
int While(int * argc,void * args[]) {
int idx;
PBase base = (PBase)args;
do {
Expr(argc,args); // get the condition
if(base->Accum)
Block(argc,args); // Just execute the enclosed code
else
return(1);
*argc = idx+3;
} while(1);
return(1);
}

// Check conditions and executer
void statement(int *argc, void * args[]) {
int i,end;
PBase base = (PBase) args;
if (!base->Depth || *argc == base->Start) return; // recurse or empty brackets
end = *argc;
*argc = base->Start;
i= ExecCommand(argc,args);
if(i < 0)
syntax_error("Command error",(char *) args[0]);
else if(i == 0) {
printf("Command not found");
*argc = end;  // skip past
}
base->Start=*argc;
}
// Process the tags list and generate cmd format sequences
PList  process_tags( PList list,int * argc,void *args[]) {
PBase base = (PBase) args;
Tag * tag;
int idx,argprev;
unsigned long lng;
printf("Parse %d  \n",*argc);
while(1) {
idx = *argc;
tag = list[0].tag;
if(!tag || tag->str == 0) {
statement(argc,args);
syntax_error("Normal exit\n",list->src); }
switch(tag->form) {
case keyterm:
if(tag->str[0] ==';' )
statement(argc,args);
else  // this must be the while
args[idx]=tag->str; (*argc)++; // handle it at execution time
list+=1;
break;
case assign: // Getting tricky
    base->Start = *argc;
list=process_tags(list+1,argc,args); // collect the expression
args[idx]="Shunt ";
statement(argc,args); // shunt will unfold the elements in place
break;

case close: // Closing bracket handled on exit from  push
base->Depth--;
(*argc) +=1;
if(!base->Depth)
statement(argc,args);
list++;
break;
case open:
base->Depth++;
(*argc) +=1;
list++;
break;
case cast:  // we have a cast function for this
args[idx] = "cast";
args[idx + 1]=(void *) list[0].src; // the cast name
args[idx+1] = list[1].src; // the variable being cast
(*argc)+=2;
list +=2;
while(list && list->src[0] != ';')  {
if(GetName(list->src,list->len))
syntax_error("Multiple defines\n",list->src);
PutName(list->src,list->len);
list++;  // Assuming the ';' is there
}
if(!list) syntax_error("No statement end",list->src);
Cast(argc,args); // set up any post processing
list++;
base->Start= *argc;
// the';' end will be caughtat lop top
break;
case null: // Not implemented or pass through
case operand: // part of expression
args[idx]=tag->str; (*argc)++;
list +=1;
break;
case integer:  // Immediate!
args[idx+1] = (void *) (long) atoi(list->src);
*argc += 1;
list+=1;
break;
default:
case variable:  // something got defined and is being used
case string:

args[idx+1] = list[1].src;
*argc += 1;
list+=1;
break;
}
// the cast command will resolve function definitions

}
}
int Init(int * argc, void * args[]);
int Shunt(argc,args);
int Entry1(int *argc, void * args[]) {
int ir=0;
int idx=*argc;
if(!strcmp(args[idx],"ParseArgs")) ir = ParseArgs(argc,args);
else if(!strcmp(args[idx],"While")) ir = While(argc,args);
else if(!strcmp(args[idx],"Expr")) ir = Expr(argc,args);
else if(!strcmp(args[idx],"Block")) ir = Block(argc,args);
else if(!strcmp(args[idx],"Init")) ir = Init(argc,args);
else if(strcmp(args[idx],"Shunt1 ")) ir= Shunt1(argc,args);
else if(strcmp(args[idx],"Shunt2 ")) ir= Shunt2(argc,args);
else ir=0; // Not found
return(ir);
}
#ifdef SHARED

int Init(int *argc, void * args[]) {
int idx = *argc;
ExecCommand = (EntryType *) args[idx];
*argc +=2;
return(1);
}
#else
int Init(int *argc, void * args[]){
ExecCommand = Entry; // No command bus in standalone test
}

// fake main for test only
int main(void) {
List * list;
PBase base;
void * args[200];

int argc=0;
char src[100]= " while(4)  {  }" ;
base =(PBase) args;
printf("%d\n",Ntags);
Init(&argc,args);
args[argc]= "ParseArgs";
args[argc+1]= src;
ParseArgs(&argc,args);
list = (PList) base->Accum;
argc=0;
memset(args,0,sizeof(args));
process_tags(list,&argc,args);
ListSyms();
}
#endif

/* This implementation does not implement functions and unary operators. */
typedef struct {
int op;
int prec;
int sort;
} Key;
#define Right 0
#define Left 1

Key keys[]= {
{'^',4,Right},
{'*',3,Left},
{'/',3,Left},
{'+',2,Left},
{'-',2,Left}
};
#define OPS "^ * / + -"
// Find precedence (inefficient design)
Key * find(char  op) {
int i=5;
do {
if(keys[i].op == op)
return(&keys[i]);
i--;
} while(i > 0);
}
int prec(char   op) {
Key *k=find(op);
if(k) return(k->prec);
else syntax_error(0,0);
}
// Find associative dummy
int left(char op) {
Key *k = find(op);
if(k) return(k->sort);
else syntax_error(0,0);
}
typedef struct {
long * list;
int index;
} Stack;
typedef Stack* PStack;
Stack oper;
Stack out;
Stack in;
void pr_stack(PStack s) {
for(int i=0;i < s->index;i++)
printf("%x ",(s->list[i]));
printf("\n");
}
long push(PStack s,long x) {
s->list[s->index]=x;
s->index++;
return(x);
}
long pop(PStack s) {
s->index--;
return(s->list[s->index]);
}
long pull(PStack s) {
int i=s->index;
s->index++;
return(s->list[i]);
}
long top(PStack s) {
return(s->list[s->index-1]);
}
char *  ParseToken(char * expr) {
char * ptr=0;
while(expr[0] && isspace(expr[0])) expr++;
ptr=expr;
while(expr[0] && !isspace(expr[0])) expr++;
if(!ptr) syntax_error(0,0);
return(ptr);
}
void Shunt1(int * argc, void * args[]) {
out.list = (long *) args[*argc + 1];
in.list = out.list;
in.index=0;out.index=0;
shunt(0,1); // argumens exernal
}
void Shunt2(int * argc, void * args[]) {
char * s = args[*argc + 1];
shunt(s,0);
}
#define More ( (mode && top(&in) !=';' ) || (!mode && expr[0]) )
void shunt(char *expr,int mode) {
while(More) {    // while there are tokens to be read:
char * token;
if(!mode) token = ParseToken(expr);     //read a token.
else token =  pull(&in);
printf("Tok %c Exp %s \n",*token,expr);
if(isdigit(token[0]))    //if the token is a number, then:
push(&out,token); //push it to the output queue.
// no functions
//if the token is a function then:
// push it onto the operator stack
    if(strchr("^ * / + -", token[0])) //if the token is an operator, then:
    { 
        while(       //while ((there is a function at the top of the operator stack) ignored
oper.index && token[0] != '(' &&
(
prec(token[0])  <

prec(top(&oper))   // (there is an operator at the top of the operator stack with greater precedence)
||
( prec(token[0]) == prec(top(&oper))  && left(top(&oper) ) )
//or (the operator at the top of the operator stack has equal precedence and is left associative))
)
  //and (the operator at the top of the operator stack is not a left bracket):

            )       
            push(&out,pop(&oper)); //pop operators from the operator stack onto the output queue.
        push(&oper,token);  //push it onto the operator stack.
}
     
    if(token[0] == '(') push(&oper,token);  //the token is a left bracket (i.e. "("), then: push it onto the operator stack.
    if(token[0] == ')') {  //if the token is a right bracket (i.e. ")"), then:
        while(oper.index && top(&oper) != '(')  //while the operator at the top of the operator stack is not a left bracket:
            push(&out,pop(&oper)); //pop the operator from the operator stack onto the output queue.
        pop(&oper); //pop the left bracket from the stack.
        if(oper.index==0) syntax_error(0,0); // if the stack runs out without finding a left bracket, then there are mismatched parentheses.
 }

if(!More) { //if there are no more tokens to read:
while(oper.index)    //while there are still operator tokens on the stack:
{
char * x = (char *) top(&oper);
if(strchr("()", *x) )
syntax_error(0,0);  //  if the operator token on the top of the stack is a bracket, then there are mismatched parentheses.
push(&out,pop(&oper));  //pop the operator from the operator stack onto the output queue.
}
}
}
return;
}
////////////////////////////////
#define SUCCESS 0
#define EXIT 2
#define MODULES 8


typedef struct {
void * handle;  //open libs
EntryType * entry;
char  name[20]; } Module;
Module modules[MODULES];
int modules_index=0;
void FreeModule(int i) {
dlclose(modules[i].handle);
}
void FreeModules() {
int i;
for(i=0;i < modules_index;i++)
FreeModule(i);
}
 int LoadModule(int *argc, void *args[]) {
        void *handle;
        char *error;
        char name[20];
        name[0]=0;
        // making "./name.so" all shareds are local for test
        strcat(name,"./");
        strcat(name,args[1]);
        strcat(name,".so");
        EntryType *entry;
        handle = dlopen (name, RTLD_LAZY);
        if (!handle) {
            fputs (dlerror(), stderr);
            exit(1);
        }
        modules[modules_index].entry = dlsym(handle, "Entry");
        if ((error = dlerror()) != NULL)  {
            fputs(error, stderr);
            exit(1);
        }
        modules[modules_index].handle =handle;
        strcpy(modules[modules_index].name,args[1]);

        args[0] = "Init";
        args[1]=Entry; // the return entry for executing on the command bus
printf ("%f\n", (modules[modules_index].entry)(argc,args)); // Init
modules_index++;
*argc += 2;
return(0);
    }
int UnloadModule(int *argc, void *args[]) {
char * name = args[1];
int i;
while(i < modules_index && strcmp(modules[i].name,name)) i++;
modules_index--;
while(i < modules_index)  {
modules[i]=modules[1+1];
i++;
}
}
int ConsoleLoop(FILE*);
int ExecFile(int * argc, void * args[]) {
char * filemacro = args[1];
char* p;
FILE* fin;
p = malloc(10000);
fin = fopen(filemacro,"rb");
if(!fin) {
printf("\n no file %s\n",filemacro);
return(0);
}
fread(p,1,10000,fin);
ConsoleLoop(fin);
return(1);
}
// Console loopingthrough to
// find an exeutable
int Entry(int *argc, void * args[]) {
int ir=0;
if(!strcmp(args[0],"quit")) exit(0);

else if(!strcmp(args[0],"Load")) ir = LoadModule(argc,args);
else if(!strcmp(args[0],"UnLoad")) ir = UnloadModule(argc,args);
else if(!strcmp(args[0],"ExecFile")) ir = ExecFile(argc,args);
else if(!strcmp(args[0],"Init")) ir = 1;
else if(!(ir = Entry1(argc,args))) // The parser and shunt commands
{
int i = 0;
while(i <  modules_index) {

ir=modules[i].entry(argc,args);
if(ir != 0)
return(ir);
if(i==0){
printf("Unknown\n");
return(-1);
}
i++;
}
}
return(-1);
}
int ConsoleLoop(FILE * fin){
int argc,ir;
char *ptr;
char str[1000];
void * args[100];
ir=0;
while(ir != EXIT) {
printf("::");
fgets(str,40,fin);
memset(args,0,sizeof(args));
argc=0;
args[0]="ParseArgs";
args[1]=str;
if(!Entry(&argc, args)) {
printf("No syntax engine\n");
exit(-1);
} else {
while(args[argc]) {
ir = Entry(&argc, args);
if(ir) break; // Commands processed
}
}
}
printf("%s %d\n","Exit",ir);
return(ir);
}

No comments: