aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShinya Sato <shinnya.sato@gmail.com>2021-09-24 16:42:54 +0900
committerShinya Sato <shinnya.sato@gmail.com>2021-09-24 16:42:54 +0900
commit6b3075d90d945d5e7e8fd4d28284ffd99dbeb82e (patch)
tree4d9e58166e36452bc3a19172d9cfb7a245f996b0 /src
parentdd62122ee43d2c388fb96518eaa527976fddfc38 (diff)
downloadinpla-6b3075d90d945d5e7e8fd4d28284ffd99dbeb82e.tar.gz
inpla-6b3075d90d945d5e7e8fd4d28284ffd99dbeb82e.zip
v0.4.1
Diffstat (limited to 'src')
-rw-r--r--src/ast.c331
-rw-r--r--src/ast.h62
-rw-r--r--src/cas_spinlock.h11
-rw-r--r--src/id_table.c171
-rw-r--r--src/id_table.h75
-rw-r--r--src/inpla.l191
-rw-r--r--src/inpla.y7606
-rw-r--r--src/linenoise/.gitignore3
-rw-r--r--src/linenoise/linenoise.c1225
-rw-r--r--src/linenoise/linenoise.h75
-rw-r--r--src/mytype.h49
-rw-r--r--src/name_table.c423
-rw-r--r--src/name_table.h50
-rw-r--r--src/timer.h31
14 files changed, 10303 insertions, 0 deletions
diff --git a/src/ast.c b/src/ast.c
new file mode 100644
index 0000000..ca46600
--- /dev/null
+++ b/src/ast.c
@@ -0,0 +1,331 @@
+//----------------------------------------
+// for AST
+//----------------------------------------
+//http://www.hpcs.cs.tsukuba.ac.jp/~msato/lecture-note/comp-lecture/tiny-c-note2.html
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ast.h"
+
+#define MAX_SYMBOLS 256
+typedef struct {
+ char* sym[MAX_SYMBOLS];
+ int val[MAX_SYMBOLS];
+ int nth;
+} SymbolTable;
+
+SymbolTable SymTable, ConstTable;
+
+
+void SymTable_init(SymbolTable *table) {
+ int i;
+ table->nth = 0;
+ for (i=0; i<MAX_SYMBOLS; i++) {
+ table->sym[i] = NULL;
+ }
+}
+
+char *recordSymbol(SymbolTable *table, char *name) {
+ int i;
+ char *result;
+
+ for (i=0; i< table->nth; i++) {
+ if (strcmp(table->sym[i], name) == 0) {
+
+ // The `name' has existed already,
+ // and table->sym[i] is used instead of that,
+ // so starduped memory for the `name' should be freed here.
+ free(name);
+
+ return table->sym[i];
+ }
+ }
+
+ // inpla.l で strdup されているので、
+ // ここでは stardup せずに、単に ポインタを格納するだけ。
+ table->sym[table->nth]=name;
+ result = table->sym[table->nth];
+ table->nth++;
+ if (table->nth > MAX_SYMBOLS) {
+ puts("ERROR: The SymbolTable in AST library is too small.");
+ exit(-1);
+ }
+
+ return result;
+}
+
+int lookupEntry(SymbolTable *table, char *name) {
+ int i;
+
+ for (i=0; i< table->nth; i++) {
+ if (strcmp(table->sym[i], name) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void recordVal(SymbolTable *table, char *name, int val) {
+ int i;
+
+ for (i=0; i< table->nth; i++) {
+ if (strcmp(table->sym[i], name) == 0) {
+
+ // The `name' has existed already,
+ // and table->sym[i] is used instead of that,
+ // so starduped memory for the `name' should be freed here.
+ free(name);
+
+ table->val[i] = val;
+ return;
+ }
+ }
+ //table->sym[table->nth]=strdup(name);
+ table->sym[table->nth]=name;
+ table->val[table->nth]=val;
+ table->nth++;
+ if (table->nth > MAX_SYMBOLS) {
+ puts("ERROR: The SymbolTable in AST library is too small.");
+ exit(-1);
+ }
+
+}
+
+
+static Ast *AstHeap;
+static int NextPtr_AstHeap;
+#define MAX_AST_HEAP 10000
+
+void ast_heapInit(void) {
+
+ NextPtr_AstHeap = 0;
+ AstHeap = malloc(sizeof(Ast)*MAX_AST_HEAP);
+ if (AstHeap == NULL) {
+ printf("Malloc error [AstHeap]\n");
+ exit(-1);
+ }
+
+ SymTable_init(&SymTable);
+ SymTable_init(&ConstTable);
+}
+
+void ast_heapReInit(void) {
+ NextPtr_AstHeap = 0;
+}
+
+static Ast *ast_myalloc(void) {
+ Ast *ptr;
+
+ if (NextPtr_AstHeap < MAX_AST_HEAP) {
+ ptr=&AstHeap[NextPtr_AstHeap];
+ NextPtr_AstHeap++;
+ } else {
+ printf("[Error] All memory for AST was run out.\n");
+ exit(-1);
+ }
+
+ return ptr;
+}
+
+
+Ast *ast_makeSymbol(char *name) {
+ Ast *ptr;
+ ptr = ast_myalloc();
+ ptr->id = AST_SYM;
+ ptr->sym = recordSymbol(&SymTable, name);
+ return ptr;
+}
+
+Ast *ast_makeInt(int num) {
+ Ast *ptr;
+ ptr = ast_myalloc();
+ ptr->id = AST_INT;
+ ptr->intval = num;
+ return ptr;
+}
+
+void ast_recordConst(char *name, int val) {
+ recordVal(&ConstTable, name, val);
+}
+
+
+Ast *ast_makeAST(AST_ID id, Ast *left, Ast *right) {
+ Ast *ptr;
+ if ((id == AST_AGENT) && (right == NULL)) {
+ int entry = lookupEntry(&ConstTable, left->sym);
+ if (entry != -1) {
+
+ ptr = ast_myalloc();
+ ptr->id = AST_INT;
+ ptr->intval = ConstTable.val[entry];
+ return ptr;
+ }
+ }
+
+ ptr = ast_myalloc();
+ ptr->id = id;
+ ptr->right = right;
+ ptr->left = left;
+ return ptr;
+}
+
+int count_elem(Ast *p) {
+ int count=0;
+ while (p!=NULL) {
+ p = ast_getTail(p);
+ count++;
+ }
+ return count;
+}
+
+Ast *ast_makeTuple(Ast *tuple) {
+ Ast *ptr;
+ ptr = ast_myalloc();
+ ptr->id = AST_TUPLE;
+ ptr->right = tuple;
+ ptr->intval = count_elem(tuple);
+ return ptr;
+}
+
+Ast *ast_paramToCons(Ast *ast) {
+ // ast は List(a, List(b,NULL)) という astlist が入ってくるとして、
+ // これを AST_CONS(nonsym, a, AST_CONS(nonsym, b, AST_NIL())) と変換する
+
+ Ast *at = ast;
+ while (ast != NULL) {
+ at->id = AST_CONS;
+ if (at->right == NULL) {
+ Ast *ptr;
+ ptr = ast_myalloc();
+ ptr->id = AST_NIL;
+ at->right = ptr;
+ break;
+ }
+ at=at->right;
+ }
+ return ast;
+}
+
+
+
+Ast *ast_addLast(Ast *l, Ast *p)
+{
+ Ast *q;
+
+ if(l == NULL) return ast_makeAST(AST_LIST,p,NULL);
+ q = l;
+ while(q->right != NULL) q = q->right;
+ q->right = ast_makeAST(AST_LIST,p,NULL);
+ return l;
+}
+
+Ast *ast_getNth(Ast *p,int nth)
+{
+ if(p->id != AST_LIST){
+ fprintf(stderr,"bad access to list\n");
+ exit(1);
+ }
+ if(nth > 0) return(ast_getNth(p->right,nth-1));
+ else return p->left;
+}
+
+Ast *ast_getTail(Ast *p)
+{
+ if(p->id != AST_LIST){
+ fprintf(stderr,"bad access to list\n");
+ exit(1);
+ }
+ else return p->right;
+}
+
+void puts_ast(Ast *p) {
+ static char *string_AstID[] = {
+ // basic
+ "SYM", "NAME", "INTNAME", "AGENT", "CNCT", "RULE",
+ "BODY", "IF", "THEN_ELSE",
+
+ // LIST
+ "LIST",
+
+ // annotation
+ "(*L)", "(*R)",
+
+ // extension
+ "TUPLE",
+ "INT", "LD", "ADD", "SUB", "MUL", "DIV", "MOD",
+ "LT", "LE", "EQ", "NE", "UNM",
+ "CONS", "NIL", "OPCONS",
+ "RAND", "SRAND",
+
+ // default
+ "UNDEFINED",
+ };
+
+ if (p==NULL) {printf("NULL"); return;}
+
+ switch(p->id) {
+ case AST_INT:
+ printf("int %d", p->intval);
+ break;
+ case AST_SYM:
+ printf("%s", p->sym);
+ break;
+ case AST_TUPLE:
+ printf("TUPLE(%d)(", p->intval);
+ puts_ast(p->right);
+ printf(")");
+ break;
+ case AST_NIL:
+ printf("NIL");
+ break;
+ case AST_ANNOTATION_L:
+ case AST_ANNOTATION_R:
+ printf("%s", string_AstID[p->id]);
+ puts_ast(p->left);
+ break;
+ default:
+ printf("%s(", string_AstID[p->id]);
+ puts_ast(p->left);
+ printf(",");
+ puts_ast(p->right);
+ printf(")");
+
+ }
+}
+
+
+Ast *ast_remove_tuple1(Ast *p) {
+
+ if (p==NULL) return p;
+
+ switch(p->id) {
+ case AST_INT:
+ return p;
+ break;
+ case AST_SYM:
+ return p;
+ break;
+ case AST_TUPLE:
+ if (p->intval == 1) {
+ // (AST_TUPLE NULL (LIST left right))
+ p = p->right->left;
+ }
+ p->right = ast_remove_tuple1(p->right);
+ return p;
+ break;
+ case AST_NIL:
+ return p;
+ break;
+ case AST_ANNOTATION_L:
+ case AST_ANNOTATION_R:
+ p->left = ast_remove_tuple1(p->left);
+ return p;
+ break;
+ default:
+ p->left = ast_remove_tuple1(p->left);
+ p->right = ast_remove_tuple1(p->right);
+ return p;
+
+ }
+}
diff --git a/src/ast.h b/src/ast.h
new file mode 100644
index 0000000..0acc5bb
--- /dev/null
+++ b/src/ast.h
@@ -0,0 +1,62 @@
+// http://www.hpcs.cs.tsukuba.ac.jp/~msato/lecture-note/comp-lecture/tiny-c/AST.h
+
+#ifndef _AST_
+#define _AST_
+
+typedef enum {
+ AST_SYM=0, AST_NAME, AST_INTVAR, AST_AGENT, AST_CNCT, AST_RULE,
+ AST_BODY, AST_IF, AST_THEN_ELSE,
+
+ // this is for ASTLIST
+ AST_LIST,
+
+ // annotation
+ AST_ANNOTATION_L, AST_ANNOTATION_R,
+
+ // builtin tuble
+ AST_TUPLE,
+
+ // operation
+ AST_INT, AST_LD, AST_PLUS, AST_SUB, AST_MUL, AST_DIV, AST_MOD,
+ AST_LT, AST_LE, AST_EQ, AST_NE, AST_UNM,
+
+ // for built-in lists
+ AST_CONS, AST_NIL, AST_OPCONS,
+
+ // for built-in agents
+
+ AST_RAND, AST_SRAND,
+
+} AST_ID;
+
+
+typedef struct abstract_syntax_tree {
+ AST_ID id;
+ int intval;
+ char *sym;
+ struct abstract_syntax_tree *left,*right;
+} Ast;
+
+void ast_heapInit(void);
+void ast_heapReInit(void);
+Ast *ast_makeSymbol(char *name);
+Ast *ast_makeInt(int num);
+Ast *ast_makeAST(AST_ID id, Ast *left, Ast *right);
+Ast *ast_makeTuple(Ast *tuple);
+Ast *ast_addLast(Ast *l, Ast *p);
+Ast *ast_getNth(Ast *p,int nth);
+Ast *ast_getTail(Ast *p);
+void puts_ast(Ast *p);
+Ast *ast_paramToCons(Ast *ast);
+void ast_recordConst(char *name, int val);
+Ast *ast_remove_tuple1(Ast *p);
+
+
+#define ast_makeCons(x1,x2) ast_makeAST(AST_LIST,x1,x2)
+#define ast_makeList1(x1) ast_makeAST(AST_LIST,x1,NULL)
+#define ast_makeList2(x1,x2) ast_makeAST(AST_LIST,x1,ast_makeAST(AST_LIST,x2,NULL))
+#define ast_makeList3(x1,x2,x3) ast_makeAST(AST_LIST,x1,ast_makeAST(AST_LIST,x2,ast_makeAST(AST_LIST,x3,NULL)))
+#define getFirst(p) getNth(p,0)
+
+
+#endif
diff --git a/src/cas_spinlock.h b/src/cas_spinlock.h
new file mode 100644
index 0000000..cb2dabd
--- /dev/null
+++ b/src/cas_spinlock.h
@@ -0,0 +1,11 @@
+//#define CAS_LOCK_USLEEP 4
+#define CAS_LOCK_USLEEP 200
+
+static inline void lock(volatile int *aexclusion) {
+ while (__sync_lock_test_and_set(aexclusion, 1))
+ while (*aexclusion)
+ usleep(CAS_LOCK_USLEEP);
+}
+static inline void unlock(volatile int *aexclusion) {
+ __sync_lock_release(aexclusion);
+}
diff --git a/src/id_table.c b/src/id_table.c
new file mode 100644
index 0000000..b7b267b
--- /dev/null
+++ b/src/id_table.c
@@ -0,0 +1,171 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ast.h"
+#include "id_table.h"
+
+
+static IdTableT IdTable[IDTABLE_SIZE];
+
+static int NextAgentId, NextGnameId;
+
+void IdTable_init() {
+
+ int i;
+ NextAgentId = START_ID_OF_AGENT -1;
+ NextGnameId = START_ID_OF_GNAME -1;
+ // 0 : ID_INT(used in expressions)
+ // 1 .. START_ID_OF_AGENT-1 : built-in agents
+ // START_IS_OF_AGENT .. NUM_AGENTS-1: user defined agents
+ // NUM_AGENTS(=ID_NAME) .. : names
+
+ for (i=0; i<IDTABLE_SIZE; i++) {
+ IdTable[i].arity = -1;
+ IdTable[i].name = NULL;
+ }
+
+ // built-in agent
+ IdTable[ID_TUPLE0].arity = 0;
+ IdTable[ID_TUPLE1].arity = 1;
+ IdTable[ID_TUPLE2].arity = 2;
+ IdTable[ID_TUPLE3].arity = 3;
+ IdTable[ID_TUPLE4].arity = 4;
+ IdTable[ID_TUPLE5].arity = 5;
+ IdTable[ID_NIL].arity = 0;
+ IdTable[ID_CONS].arity = 2;
+ IdTable[ID_INTAGENT].arity = 1;
+
+ IdTable[ID_ADD].arity = 2;
+ IdTable[ID_ADD2].arity = 2;
+ // IdTable[ID_APPEND].arity = 2;
+ // IdTable[ID_APPEND2].arity = 2;
+
+ IdTable[ID_INT].name = "int";
+ IdTable[ID_TUPLE0].name = "Tuple0";
+ IdTable[ID_TUPLE1].name = "Tuple1";
+ IdTable[ID_TUPLE2].name = "Tuple2";
+ IdTable[ID_TUPLE3].name = "Tuple3";
+ IdTable[ID_TUPLE4].name = "Tuple4";
+ IdTable[ID_TUPLE5].name = "Tuple5";
+ IdTable[ID_NIL].name = "[]";
+ IdTable[ID_CONS].name = "Cons";
+ IdTable[ID_INTAGENT].name = "Int";
+
+ IdTable[ID_ADD].name = "Add";
+ IdTable[ID_ADD2].name = "Add2";
+ IdTable[ID_APPEND].name = "Append";
+ IdTable[ID_APPEND2].name = "Append2";
+}
+
+
+int IdTable_getid_builtin_funcAgent(Ast *agent) {
+ // returns -1 if the agent is not built-in.
+
+ int id = -1;
+
+ if (agent->id != AST_AGENT) {
+ return -1;
+ }
+
+ if (strcmp((char *)agent->left->sym, "Add2") == 0) {
+ id = ID_ADD2;
+ } else if (strcmp((char *)agent->left->sym, "Add") == 0) {
+ id = ID_ADD;
+ } else if (strcmp((char *)agent->left->sym, "Append") == 0) {
+ id = ID_APPEND;
+ } else if (strcmp((char *)agent->left->sym, "Append2") == 0) {
+ id = ID_APPEND2;
+ } else if (strcmp((char *)agent->left->sym, "Int") == 0) {
+ id = ID_INTAGENT;
+ }
+
+ return id;
+}
+
+
+int IdTable_is_builtin_rule(Ast *agentL, Ast *agentR) {
+ // puts_ast(agentL);
+ // printf(" ");
+ // puts_ast(agentR);
+ // printf("\n");
+
+
+ if ( (agentL->id == AST_TUPLE) && (agentR->id == AST_TUPLE) ) {
+ // compare these arities
+ if (agentL->intval == agentR->intval) {
+ return 1;
+ }
+ return 0;
+ }
+
+ int idL = IdTable_getid_builtin_funcAgent(agentL);
+ if (agentR->id == AST_INT) {
+ if ((idL == ID_ADD) || (idL == ID_ADD2)) {
+ return 1;
+ }
+ return 0;
+ }
+
+ if (idL == ID_APPEND) {
+ if ((agentR->id == AST_CONS) || (agentR->id == AST_NIL)) {
+ return 1;
+ }
+ return 0;
+ }
+
+ return 0;
+}
+
+
+void IdTable_set_name(int id, char *symname)
+{
+ if (id > IDTABLE_SIZE) {
+ printf("Error: The given id %d was beyond of the size of IdTable (%d)\n",
+ id, IDTABLE_SIZE);
+ exit(-1);
+ }
+ IdTable[id].name = symname;
+}
+
+
+void IdTable_set_arity(int id, int arity)
+{
+ if ((IdTable[id].arity == -1) || (IdTable[id].arity == arity)) {
+ IdTable[id].arity = arity;
+ } else {
+ printf("Warning: The agent '%s' has been already defined as whose arity is %d, but now redefined as the arity is %d.\n",
+ IdTable[id].name, IdTable[id].arity, arity);
+ IdTable[id].arity = arity;
+ }
+}
+
+
+char *IdTable_get_name(int id)
+{
+ return IdTable[id].name;
+}
+
+int IdTable_get_arity(int id)
+{
+ return IdTable[id].arity;
+}
+
+int IdTable_new_agentid() {
+ NextAgentId++;
+ if (NextAgentId > ID_NAME) {
+ printf("ERROR: The number of agents exceeded the size of agents in SYMTABLE (%d)\n",
+ ID_NAME);
+ exit(-1);
+ }
+ return(NextAgentId);
+}
+
+int IdTable_new_gnameid() {
+ NextGnameId++;
+ if (NextAgentId > IDTABLE_SIZE) {
+ printf("ERROR: The number of agents exceeded the size of names in SYMTABLE (%d)\n",
+ ID_NAME);
+ exit(-1);
+ }
+ return(NextGnameId);
+}
diff --git a/src/id_table.h b/src/id_table.h
new file mode 100644
index 0000000..8dbdeef
--- /dev/null
+++ b/src/id_table.h
@@ -0,0 +1,75 @@
+#ifndef _ID_TABLE_
+#define _ID_TABLE_
+
+
+// When NUM_AGENT is 256:
+// 0 .. 255: AGENT
+// 256 : NAME,
+// 257 .. : GNAME
+
+
+#define ID_INT 0
+
+// builtin を加えたら void IdTable_init() 内で
+// IdTable に arity と 表示方法の登録を忘れないように!
+#define ID_TUPLE0 1
+#define ID_TUPLE1 2
+#define ID_TUPLE2 3
+#define ID_TUPLE3 4
+#define ID_TUPLE4 5
+#define ID_TUPLE5 6
+#define GET_TUPLEID(arity) (ID_TUPLE0+arity)
+#define IS_TUPLEID(id) ((id >= ID_TUPLE0) && (id <= ID_TUPLE5))
+#define GET_TUPLEARITY(id) (id - ID_TUPLE0)
+
+#define ID_NIL 7
+#define ID_CONS 8
+#define IS_LISTID(id) ((id == ID_NIL) && (id == ID_CONS))
+
+#define ID_INTAGENT 9
+
+#define START_ID_OF_BUILTIN_AGENT 10
+#define ID_ADD 10
+#define ID_ADD2 11
+#define ID_APPEND 12
+#define ID_APPEND2 13
+#define END_ID_OF_BUILTIN_AGENT 13
+
+
+#define START_ID_OF_AGENT 20
+//#define NUM_AGENTS 1024
+#define END_ID_OF_AGENT 255
+#define NUM_AGENTS END_ID_OF_AGENT+1 // 256
+
+#define ID_NAME NUM_AGENTS // 256
+#define START_ID_OF_GNAME ID_NAME+1
+#define IS_AGENTID(a) (a < ID_NAME)
+#define IS_NAMEID(a) (a >= ID_NAME)
+#define IS_GNAMEID(a) (a > ID_NAME)
+#define IS_LOCAL_NAMEID(a) (a == ID_NAME)
+#define IS_BUILTIN_AGENTID(a) (a <= END_ID_OF_BUILTIN_AGENT)
+#define SET_LOCAL_NAMEID(a) (a = ID_NAME)
+
+/**************************************
+ TABLE for SYMBOLS
+**************************************/
+typedef struct {
+ char *name;
+ int arity;
+} IdTableT;
+
+#define IDTABLE_SIZE (NUM_AGENTS)*2 // AGENT + NAME
+
+void IdTable_init();
+void IdTable_set_name(int id, char *symname);
+void IdTable_set_arity(int id, int arity);
+char *IdTable_get_name(int id);
+int IdTable_get_arity(int id);
+int IdTable_new_agentid();
+int IdTable_new_gnameid();
+
+int IdTable_getid_builtin_funcAgent(Ast *agent);
+int IdTable_is_builtin_rule(Ast *agentL, Ast *agentR);
+
+
+#endif
diff --git a/src/inpla.l b/src/inpla.l
new file mode 100644
index 0000000..5547d32
--- /dev/null
+++ b/src/inpla.l
@@ -0,0 +1,191 @@
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include "linenoise/linenoise.h"
+
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) result = mygetinput(buf, max_size);
+
+// lineno de kubetu?
+static int mygetinput(char *buf, int size) {
+ char *line;
+ if (feof(yyin)) return YY_NULL;
+
+ if (yyin!=stdin) {
+ int len;
+ char ch;
+ for (len = 0; len < size; len++) {
+ ch = getc(yyin);
+ if (ch == EOF)
+ break;
+ buf[len] = ch;
+ }
+ return len;
+ }
+
+ if (yylineno == 1) {
+ line = linenoise(">>> ");
+ } else {
+ line = linenoise("... ");
+ }
+ if(!line) return YY_NULL;
+ if(strlen(line) > size-2){
+ fprintf(stderr,"input line too long\n"); return YY_NULL; }
+ sprintf(buf,"%s\n",line);
+ linenoiseHistoryAdd(line);
+ //linenoiseHistorySave(".inpla.history.txt");
+ free(line);
+ return strlen(buf);
+}
+
+
+//#undef YY_INPUT
+//#define YYINPUT(buf, result, max_size) result = (c == EOF) ? YY_NULL : (buf[0] = c, 1);
+
+
+/************************************
+ Strings
+*************************************/
+#define MAX_STRING_LENGTH 1024
+static char ParseStringBuffer[MAX_STRING_LENGTH];
+static int nextPtr_ParseStringBuffer = 0;
+void Parse_StringBuffer_reInit() {
+ nextPtr_ParseStringBuffer = 0;
+}
+
+void Parse_addString(char ch) {
+ ParseStringBuffer[nextPtr_ParseStringBuffer] = ch;
+ nextPtr_ParseStringBuffer++;
+}
+
+char *Parse_closeStringBuffer() {
+ char *ret;
+ ParseStringBuffer[nextPtr_ParseStringBuffer]='\0';
+ ret = ParseStringBuffer;
+ return ret;
+}
+
+
+
+%}
+
+%option nounput
+%option yylineno
+%option noyywrap
+%x STRING_STATE COM_STATE
+%%
+<INITIAL>";" return (DELIMITER);
+<INITIAL>":" return (COLON);
+<INITIAL>"(" return (LP);
+<INITIAL>")" return (RP);
+<INITIAL>"{" return LC;
+<INITIAL>"}" return RC;
+<INITIAL>"[" return LB;
+<INITIAL>"]" return RB;
+<INITIAL>"," return (COMMA);
+<INITIAL>"><" return (CROSS);
+<INITIAL>"=>" return (TO);
+<INITIAL>"~" return (CNCT);
+<INITIAL>"-" return (SUB);
+<INITIAL>"|" return(PIPE);
+<INITIAL>"&" return(AMP);
+<INITIAL>"=" return(LD);
+<INITIAL>"==" return(EQUAL);
+<INITIAL>"!=" return(NE);
+<INITIAL>">" return(GT);
+<INITIAL>">=" return(GE);
+<INITIAL>"<" return(LT);
+<INITIAL>"<=" return(LE);
+<INITIAL>"+" return (ADD);
+<INITIAL>"*" return (MUL);
+<INITIAL>"/" return (DIV);
+<INITIAL>"%" return (MOD);
+<INITIAL>"_" return (ANY);
+<INITIAL>"?" return (QUE);
+
+<INITIAL>"int" return(INT);
+
+<INITIAL>"let" return(LET);
+<INITIAL>"in" return(IN);
+<INITIAL>"end" return(END);
+
+<INITIAL>"where" return(WHERE);
+
+<INITIAL>"if" return(IF);
+<INITIAL>"then" return(THEN);
+<INITIAL>"else" return(ELSE);
+
+<INITIAL>"interface" return(INTERFACE);
+<INITIAL>"ifce" return(IFCE);
+
+<INITIAL>"prnat" return(PRNAT);
+<INITIAL>"free" return(FREE);
+<INITIAL>"exit" return(EXIT);
+
+<INITIAL>"rand" return(RAND);
+
+<INITIAL>"const" return(DEF);
+
+<INITIAL>"use" return(USE);
+
+<INITIAL>"*L" return(ANNOTATE_L);
+<INITIAL>"*R" return(ANNOTATE_R);
+<INITIAL>[a-z][a-zA-Z0-9_'\.]* { yylval.chval = strdup(yytext);
+ return (NAME);}
+<INITIAL>[_A-Z][a-zA-Z0-9_'\.]* { yylval.chval = strdup(yytext);
+ return (AGENT);}
+<INITIAL>[0-9]+ { yylval.intval = atoi(yytext);
+ return (INT_LITERAL);}
+
+<INITIAL>"//"[^\n]* ; //comment
+<INITIAL>"/*" BEGIN(COM_STATE);
+<COM_STATE>. ;
+<COM_STATE>\n ;
+<COM_STATE>"*/" BEGIN INITIAL; //comment
+
+<INITIAL>\r\n {}
+<INITIAL>[\n|\r] {}
+<INITIAL>[ \t]+ ;
+<INITIAL><<EOF>> {return END_OF_FILE;}
+<INITIAL>\" {
+ Parse_StringBuffer_reInit();
+ BEGIN STRING_STATE;
+}
+
+<INITIAL>. {return yytext[0];}
+
+
+
+
+<STRING_STATE>\" {
+ yylval.chval = strdup(Parse_closeStringBuffer());
+ BEGIN INITIAL;
+ return STRING_LITERAL;
+}
+<STRING_STATE>\n {
+// Parse_addString('\n');
+yyerror("Unterminated string");
+BEGIN(INITIAL);
+return DELIMITER;
+}
+<STRING_STATE>\\\" Parse_addString('"');
+<STRING_STATE>\\n Parse_addString('\n');
+<STRING_STATE>\\t Parse_addString('\t');
+<STRING_STATE>\\\\ Parse_addString('\\');
+<STRING_STATE>. Parse_addString(yytext[0]);
+%%
+
+void pushFP(FILE *fp) {
+ yypush_buffer_state(yy_create_buffer(fp, YY_BUF_SIZE));
+}
+
+int popFP() {
+ yypop_buffer_state();
+ if (! YY_CURRENT_BUFFER ) {
+ yyterminate();
+ return 0;
+ }
+ return 1;
+}
+
+
diff --git a/src/inpla.y b/src/inpla.y
new file mode 100644
index 0000000..3de93c1
--- /dev/null
+++ b/src/inpla.y
@@ -0,0 +1,7606 @@
+%{
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sched.h>
+
+#include "ast.h"
+#include "id_table.h"
+#include "name_table.h"
+
+#include "timer.h" //#include <time.h>
+
+//#define DEBUG
+#define COUNT_INTERACTION // count of interaction
+
+//#define COUNT_CNCT // count of execution of JMP_CNCT
+
+//#define COUNT_MKAGENT // count of execution fo mkagent
+//#define CELL_USE_VERBOSE // count of memory access
+
+
+
+/**************************************
+ NAME TABLE
+**************************************/
+//#include "name_table.h"
+
+
+// ----------------------------------------------
+
+int MaxThreadNum=1;
+
+#ifdef THREAD
+#include <pthread.h>
+extern int pthread_setconcurrency(int concurrency);
+
+int ActiveThreadNum=0;
+
+// for cas spinlock
+#include "cas_spinlock.h"
+
+#endif
+
+//#define YYDEBUG 1
+
+#define VERSION "0.4.1"
+#define BUILT_DATE "22 Sept. 2021"
+
+extern FILE *yyin;
+
+
+
+// It means 'available' when its on 31bit flag is '1'
+#define FLAG_AVAIL 0x01 << 31
+#define IS_FLAG_AVAIL(a) ((a) & FLAG_AVAIL)
+#define SET_FLAG_AVAIL(a) ((a) = ((a) | FLAG_AVAIL))
+#define TOGGLE_FLAG_AVAIL(a) ((a) = ((a) ^ FLAG_AVAIL))
+
+
+#include "mytype.h"
+
+// Equation
+typedef struct EQ_tag {
+ VALUE l, r;
+} EQ;
+
+typedef struct EQList_tag {
+ EQ eq;
+ struct EQList_tag *next;
+} EQList;
+
+
+
+
+
+
+
+void makeRule(Ast *ast);
+void freeAgentRec(VALUE ptr);
+
+//static inline void freeName(VALUE ptr);
+void freeName(VALUE ptr);
+
+//static inline void freeAgent(VALUE ptr);
+void freeAgent(VALUE ptr);
+
+//void puts_name_port0(VALUE ptr);
+//void flush_name_port0(VALUE ptr);
+void puts_names_ast(Ast *ast);
+void free_names_ast(Ast *ast);
+void puts_name_port0_nat(VALUE ptr);
+void puts_term(VALUE ptr);
+void puts_aplist(EQList *at);
+void PushEQStack(VALUE l, VALUE r);
+
+
+int exec(Ast *st);
+int destroy(void);
+int AstHeap_MakeAgent(int arity, char *name, int *port);
+int AstHeap_MakeTerm(char *name);
+int AstHeap_MakeName(char *name);
+
+
+
+extern int yylex();
+int yyerror();
+#define YY_NO_INPUT
+extern int yylineno;
+
+#define MY_YYLINENO // For error message when nested source files are used.
+#ifdef MY_YYLINENO
+ typedef struct InfoLinenoType_tag {
+ char *fname;
+ int yylineno;
+ struct InfoLinenoType_tag *next;
+ } InfoLinenoType;
+static InfoLinenoType *InfoLineno;
+
+#define initInfoLineno() InfoLineno = NULL;
+
+void InfoLineno_Push(char *fname, int lineno) {
+ InfoLinenoType *aInfo;
+ aInfo = (InfoLinenoType *)malloc(sizeof(InfoLinenoType));
+ if (aInfo == NULL) {
+ printf("[InfoLineno]Malloc error\n");
+ exit(-1);
+ }
+ aInfo->next = InfoLineno;
+ aInfo->yylineno = lineno+1;
+ aInfo->fname = strdup(fname);
+
+ InfoLineno = aInfo;
+}
+
+void InfoLineno_Free() {
+ InfoLinenoType *aInfo;
+ free(InfoLineno->fname);
+ aInfo = InfoLineno;
+ InfoLineno = InfoLineno->next;
+ free(aInfo);
+}
+
+void InfoLineno_AllDestroy() {
+ // InfoLinenoType *aInfo;
+ while (InfoLineno != NULL) {
+ InfoLineno_Free();
+ }
+}
+
+#endif
+
+
+extern void pushFP(FILE *fp);
+extern int popFP();
+
+
+static char *Errormsg = NULL; // yyerror でメッセージが出ないように、ここに格納する
+
+
+//#define YYDEBUG 1
+//#define YYERROR_VERBOSE 1
+//int yydebug = 1;
+
+/*
+extern void eat_to_newline(void);
+void eat_to_newline(void)
+{
+ int c;
+ while ((c = getchar()) != EOF && c != '\n')
+ ;
+}
+*/
+
+%}
+%union{
+ int intval;
+ char *chval;
+ Ast *ast;
+}
+
+%token <chval> NAME AGENT
+%token <intval> INT_LITERAL
+%token <chval> STRING_LITERAL
+%token LP RP LC RC LB RB COMMA CROSS DELIMITER QUE
+%token COLON
+%token TO CNCT
+
+%token ANNOTATE_L ANNOTATE_R
+
+%token PIPE AMP LD EQUAL NE GT GE LT LE
+%token ADD SUB MUL DIV MOD INT LET IN END IF THEN ELSE ANY WHERE RAND DEF
+%token INTERFACE IFCE PRNAT FREE EXIT
+%token END_OF_FILE USE
+
+%type <ast> body astterm astterm_item nameterm agentterm astparam astparams
+val_declare
+rule
+ap aplist
+stm stmlist_nondelimiter
+stmlist
+expr additive_expr equational_expr relational_expr unary_expr
+multiplicative_expr primary_expr agent_tuple agent_list agent_cons
+bodyguard bd_else bd_elif bd_compound
+if_sentence if_compound
+name_params
+ //body
+
+%nonassoc REDUCE
+%nonassoc RP
+
+%right COLON
+ //%right LD
+ //%right EQ
+ //%left NE GE GT LT
+ //%left ADD SUB
+ //%left MULT DIV
+
+%%
+s
+: error DELIMITER {
+ yyclearin;
+ yyerrok;
+ puts(Errormsg);
+ free(Errormsg);
+ ast_heapReInit();
+ if (yyin == stdin) yylineno=0;
+ // YYACCEPT;
+ YYABORT;
+}
+| DELIMITER {
+ if (yyin == stdin) yylineno=0;
+ YYACCEPT;
+}
+| body DELIMITER
+{
+ exec($1); // $1 is a list such as [stmlist, aplist]
+ ast_heapReInit();
+ if (yyin == stdin) yylineno=0;
+ YYACCEPT;
+}
+| rule DELIMITER {
+ makeRule($1);
+ if (yyin == stdin) yylineno=0;
+ YYACCEPT;
+}
+| command {
+ if (yyin == stdin) yylineno=0;
+ YYACCEPT;
+}
+;
+
+
+
+// body は [stmlist, aplist] というリスト
+// ==> (AST_BODY stmlist aplist) に変更
+body
+: aplist { $$ = ast_makeAST(AST_BODY, NULL, $1); }
+| aplist WHERE stmlist_nondelimiter { $$ = ast_makeAST(AST_BODY, $3, $1);}
+| aplist WHERE { $$ = ast_makeAST(AST_BODY, NULL, $1);}
+| LET stmlist IN aplist END { $$ = ast_makeAST(AST_BODY, $2, $4);}
+| LET stmlist DELIMITER IN aplist END { $$ = ast_makeAST(AST_BODY, $2, $5);}
+| LET IN aplist END { $$ = ast_makeAST(AST_BODY, NULL, $3);}
+| LC stmlist RC aplist { $$ = ast_makeAST(AST_BODY, $2, $4);}
+| LC stmlist DELIMITER RC aplist { $$ = ast_makeAST(AST_BODY, $2, $5);}
+;
+
+// rule は下記に変更
+// (ASTRULE (AST_CNCT agentL agentR)
+// <if-sentence>)
+//
+// WHERE
+// <if-sentence> ::= (AST_IF guard (AST_BRANCH <then> <else>))
+// | <body>
+// | NULL
+// <then> ::= <if-sentence>
+// <else> ::= <if-sentence>
+
+
+rule
+: astterm CROSS astterm TO
+{ $$ = ast_makeAST(AST_RULE, ast_makeAST(AST_CNCT, $1, $3),
+ NULL); }
+
+| astterm CROSS astterm TO body
+{ $$ = ast_makeAST(AST_RULE, ast_makeAST(AST_CNCT, $1, $3),
+ $5); }
+
+
+| astterm CROSS astterm TO if_sentence
+{ $$ = ast_makeAST(AST_RULE, ast_makeAST(AST_CNCT, $1, $3),
+ $5); }
+
+
+| astterm CROSS astterm bodyguard
+{ $$ = ast_makeAST(AST_RULE, ast_makeAST(AST_CNCT, $1, $3),
+ $4); }
+;
+
+
+name_params
+: NAME
+{ $$ = ast_makeList1(ast_makeSymbol($1)); }
+| name_params NAME
+{ $$ = ast_addLast($1, ast_makeSymbol($2)); }
+;
+
+command:
+| FREE name_params DELIMITER
+{
+ free_names_ast($2);
+}
+| FREE DELIMITER
+| FREE IFCE DELIMITER
+{
+ NameTable_free_all();
+}
+| FREE INTERFACE DELIMITER
+{
+ NameTable_free_all();
+}
+| name_params DELIMITER
+{
+ puts_names_ast($1);
+}
+
+| PRNAT NAME DELIMITER
+{
+ puts_name_port0_nat(NameTable_get_heap($2));
+}
+| INTERFACE DELIMITER
+{
+ NameTable_puts_all();
+}
+| IFCE DELIMITER
+{
+ NameTable_puts_all();
+}
+| EXIT DELIMITER {destroy(); exit(0);}
+| USE STRING_LITERAL DELIMITER {
+ // http://flex.sourceforge.net/manual/Multiple-Input-Buffers.html
+ yyin = fopen($2, "r");
+ if (!yyin) {
+ printf("Error: The file '%s' does not exist.\n", $2);
+ free($2);
+ yyin = stdin;
+
+ } else {
+#ifdef MY_YYLINENO
+ InfoLineno_Push($2, yylineno+1);
+ yylineno = 0;
+#endif
+
+ pushFP(yyin);
+ }
+}
+| error END_OF_FILE {}
+| END_OF_FILE {
+ if (!popFP()) {
+ destroy(); exit(-1);
+ }
+#ifdef MY_YYLINENO
+ yylineno = InfoLineno->yylineno;
+ InfoLineno_Free();
+ destroy();
+#endif
+
+
+}
+| DEF AGENT LD INT_LITERAL DELIMITER {
+ ast_recordConst($2,$4);
+ }
+;
+
+
+bodyguard
+: PIPE expr TO bd_compound bd_elif
+{ $$ = ast_makeAST(AST_IF, $2, ast_makeAST(AST_THEN_ELSE, $4, $5));}
+;
+
+bd_compound
+: body
+| bodyguard
+;
+
+bd_elif
+: bd_else
+| PIPE expr TO bd_compound bd_elif
+{ $$ = ast_makeAST(AST_IF, $2, ast_makeAST(AST_THEN_ELSE, $4, $5));}
+;
+
+bd_else
+: PIPE ANY TO bd_compound
+{ $$ = $4; }
+;
+
+
+
+// if_sentence
+if_sentence
+: IF expr THEN if_compound ELSE if_compound
+{ $$ = ast_makeAST(AST_IF, $2, ast_makeAST(AST_THEN_ELSE, $4, $6));}
+;
+
+if_compound
+: if_sentence
+| body
+;
+
+
+
+// AST -----------------
+astterm
+: LP ANNOTATE_L RP astterm_item
+{ $$=ast_makeAST(AST_ANNOTATION_L, $4, NULL); }
+| LP ANNOTATE_R RP astterm_item
+{ $$=ast_makeAST(AST_ANNOTATION_R, $4, NULL); }
+//| astterm_item COLON astterm_item
+| astterm_item COLON astterm // h:t
+{$$ = ast_makeAST(AST_OPCONS, NULL, ast_makeList2($1, $3)); }
+| astterm_item
+;
+
+
+astterm_item
+ : agentterm
+ | agent_tuple
+ | agent_list
+ | agent_cons
+ | val_declare
+ | expr %prec REDUCE
+;
+
+val_declare
+: INT NAME { $$ = ast_makeAST(AST_INTVAR, ast_makeSymbol($2), NULL); }
+;
+
+agent_cons
+: LB astterm PIPE astterm RB
+{$$ = ast_makeAST(AST_OPCONS, NULL, ast_makeList2($2, $4)); }
+;
+
+agent_list
+: LB RB { $$ = ast_makeAST(AST_NIL, NULL, NULL); }
+| LB astparams RB { $$ = ast_paramToCons($2); }
+;
+
+agent_tuple
+: astparam { $$ = ast_makeTuple($1);}
+;
+
+nameterm
+: NAME {$$=ast_makeAST(AST_NAME, ast_makeSymbol($1), NULL);}
+
+agentterm
+: AGENT astparam
+{ $$=ast_makeAST(AST_AGENT, ast_makeSymbol($1), $2); }
+| NAME astparam
+{ $$=ast_makeAST(AST_AGENT, ast_makeSymbol($1), $2); }
+;
+
+
+astparam :
+LP RP { $$ = NULL; }
+| LP astparams RP { $$ = $2; }
+;
+
+astparams
+: astterm { $$ = ast_makeList1($1); }
+| astparams COMMA astterm { $$ = ast_addLast($1, $3); }
+;
+
+ap
+: astterm CNCT astterm { $$ = ast_makeAST(AST_CNCT, $1, $3); }
+;
+
+aplist
+: ap { $$ = ast_makeList1($1); }
+| aplist COMMA ap { $$ = ast_addLast($1, $3); }
+;
+
+stm
+: nameterm LD expr { $$ = ast_makeAST(AST_LD, $1, $3); }
+
+stmlist
+: stm { $$ = ast_makeList1($1); }
+| stmlist DELIMITER stm { $$ = ast_addLast($1, $3); }
+
+stmlist_nondelimiter
+: stm { $$ = ast_makeList1($1); }
+| stmlist_nondelimiter stm { $$ = ast_addLast($1, $2); }
+
+
+expr
+: equational_expr
+;
+
+equational_expr
+: relational_expr
+| equational_expr EQUAL relational_expr { $$ = ast_makeAST(AST_EQ, $1, $3); }
+| equational_expr NE relational_expr { $$ = ast_makeAST(AST_NE, $1, $3); }
+
+relational_expr
+: additive_expr
+| relational_expr LT additive_expr { $$ = ast_makeAST(AST_LT, $1, $3); }
+| relational_expr LE additive_expr { $$ = ast_makeAST(AST_LE, $1, $3); }
+| relational_expr GT additive_expr { $$ = ast_makeAST(AST_LT, $3, $1); }
+| relational_expr GE additive_expr { $$ = ast_makeAST(AST_LE, $3, $1); }
+;
+
+additive_expr
+: multiplicative_expr
+| additive_expr ADD multiplicative_expr { $$ = ast_makeAST(AST_PLUS, $1, $3); }
+| additive_expr SUB multiplicative_expr { $$ = ast_makeAST(AST_SUB, $1, $3); }
+;
+
+multiplicative_expr
+: unary_expr
+| multiplicative_expr MUL primary_expr { $$ = ast_makeAST(AST_MUL, $1, $3); }
+| multiplicative_expr DIV primary_expr { $$ = ast_makeAST(AST_DIV, $1, $3); }
+| multiplicative_expr MOD primary_expr { $$ = ast_makeAST(AST_MOD, $1, $3); }
+
+
+unary_expr
+: primary_expr
+| SUB primary_expr { $$ = ast_makeAST(AST_UNM, $2, NULL); }
+| RAND LP primary_expr RP { $$ = ast_makeAST(AST_RAND, $3, NULL); }
+;
+
+primary_expr
+: nameterm { $$ = $1;}
+| INT_LITERAL { $$ = ast_makeInt($1); }
+| AGENT { $$=ast_makeAST(AST_AGENT, ast_makeSymbol($1), NULL); }
+| LP expr RP { $$ = $2; }
+
+;
+
+%%
+
+
+
+int yyerror(char *s) {
+ extern char *yytext;
+ char msg[256];
+ //printf("%s\nSorry, this version does not support error recovery.\n",s);
+ // printf("%s\n",s);
+
+#ifdef MY_YYLINENO
+ if (InfoLineno != NULL) {
+ sprintf(msg, "%s:%d: %s near token '%s'.\n",
+ InfoLineno->fname, yylineno+1, s, yytext);
+ } else {
+ sprintf(msg, "%d: %s near token '%s'.\n",
+ yylineno, s, yytext);
+ }
+#else
+ sprintf(msg, "%d: %s near token '%s'.\n", yylineno, s, yytext);
+#endif
+
+ Errormsg = strdup(msg);
+ // printf("%d: %s near token '%s'\n", yylineno, s, yytext);
+
+ if (yyin != stdin) {
+ // puts(Errormsg);
+ destroy();
+ // exit(0);
+ }
+
+ return 0;
+}
+
+
+
+
+/**************************************
+ TABLE for SYMBOLS
+**************************************/
+//#include "id_table.h"
+
+
+
+
+/**********************************
+ Heap
+*********************************/
+
+typedef struct Heap_tag {
+ VALUE *heap;
+ int lastAlloc;
+ unsigned int size;
+} Heap;
+
+
+/**********************************
+ VIRTUAL MACHINE
+*********************************/
+#define VM_LOCALVAR_SIZE 200
+#define VM_OFFSET_META_L(a) (a)
+#define VM_OFFSET_META_R(a) (MAX_PORT+(a))
+#define VM_OFFSET_ANNOTATE_L (MAX_PORT*2)
+#define VM_OFFSET_ANNOTATE_R (MAX_PORT*2+1)
+#define VM_OFFSET_LOCALVAR (MAX_PORT*2+2)
+
+
+
+typedef struct {
+ // AgentHeap, nameHeap, valHeap
+ // Heap agentHeap, nameHeap, valHeap;
+ Heap agentHeap, nameHeap;
+
+ // EQStack
+ EQ *eqStack;
+ int nextPtr_eqStack;
+ unsigned int eqStack_size;
+
+
+ // code execution
+ VALUE agentReg[VM_LOCALVAR_SIZE+(MAX_PORT*2 + 2)];
+
+ unsigned int id;
+#ifdef COUNT_INTERACTION
+ unsigned int NumberOfInteraction;
+
+#endif
+
+} VirtualMachine;
+
+#ifndef THREAD
+static VirtualMachine VM;
+#endif
+
+#ifdef COUNT_MKAGENT
+ unsigned int NumberOfMkAgent;
+ // unsigned int id;
+#endif
+
+
+/*************************************
+ AGENT Heap
+**************************************/
+
+//#define MALLOC
+
+
+
+void VM_InitBuffer(VirtualMachine *vm, int size) {
+
+#ifndef MALLOC
+ int i;
+
+ // Agent Heap
+
+ //vm->agentHeap.lastAlloc = size-1;
+ vm->agentHeap.lastAlloc = 0;
+ vm->agentHeap.heap = (VALUE *)malloc(sizeof(Agent)*size);
+ vm->agentHeap.size = size;
+ if (vm->agentHeap.heap == (VALUE *)NULL) {
+ printf("[Heap]Malloc error\n");
+ exit(-1);
+ }
+ for (i=0; i<size; i++) {
+ SET_FLAG_AVAIL(((Agent *)(vm->agentHeap.heap))[i].basic.id);
+ }
+
+
+ // Name Heap
+
+ //size = size/2;
+ vm->nameHeap.lastAlloc = size-1;
+ //vm->nameHeap.lastAlloc = 0;
+ vm->nameHeap.heap = (VALUE *)malloc(sizeof(Name)*size);
+ vm->nameHeap.size = size;
+ if (vm->nameHeap.heap == (VALUE *)NULL) {
+ printf("[Heap]Malloc error\n");
+ exit(-1);
+ }
+ for (i=0; i<size; i++) {
+ ((Name *)(vm->nameHeap.heap))[i].basic.id = ID_NAME;
+ SET_FLAG_AVAIL(((Name *)(vm->nameHeap.heap))[i].basic.id);
+ // ((Name *)(vm->nameHeap.heap))[i].name = NULL;
+ }
+
+
+ /*
+ vm->valHeap.lastAlloc = VAL_HEAP_SIZE-1;
+ vm->valHeap.heap = (VALUE *)malloc(sizeof(Agent)*VAL_HEAP_SIZE);
+ vm->valHeap.size = VAL_HEAP_SIZE;
+ if (vm->valHeap.heap == (VALUE *)NULL) {
+ printf("[Val]Malloc error\n");
+ exit(-1);
+ }
+ for (i=0; i<VAL_HEAP_SIZE; i++) {
+ SET_FLAG_AVAIL(((Val *)(vm->valHeap.heap))[i].basic.id);
+ }
+ */
+
+#endif
+}
+
+
+
+static inline
+VALUE myallocAgent(Heap *hp) {
+
+#ifdef MALLOC
+ Agent *ptr;
+ ptr = malloc(sizeof(Agent));
+ return ptr;
+#else
+
+ int i, idx, hp_size;
+ Agent *hp_heap;
+
+ hp_size = hp->size;
+ hp_heap = (Agent *)(hp->heap);
+
+ idx = hp->lastAlloc-1;
+
+ for (i=0; i < hp_size; i++) {
+ // if (!IS_FLAG_AVAIL(((Agent *)hp_heap)[idx].basic.id)) {
+ if (!IS_FLAG_AVAIL(hp_heap[idx].basic.id)) {
+ idx++;
+ if (idx >= hp_size) {
+ idx -= hp_size;
+ }
+ continue;
+ }
+ // TOGGLE_FLAG_AVAIL(((Agent *)hp_heap)[idx].basic.id);
+ TOGGLE_FLAG_AVAIL(hp_heap[idx].basic.id);
+
+ hp->lastAlloc = idx;
+
+ // return (VALUE)&(((Agent *)hp_heap)[idx]);
+ return (VALUE)&(hp_heap[idx]);
+ }
+
+ printf("\nCritical ERROR: All %d term cells have been consumed.\n", hp->size);
+ printf("You should have more term cells with -c option.\n");
+ exit(-1);
+
+#endif
+
+}
+
+
+static inline
+VALUE myallocName(Heap *hp) {
+
+#ifdef MALLOC
+ Agent *ptr;
+ ptr = malloc(sizeof(Name));
+ return ptr;
+#else
+
+ int i,idx,hp_size;
+ Name *hp_heap;
+
+ hp_size = hp->size;
+ hp_heap = (Name *)(hp->heap);
+
+ idx = hp->lastAlloc;
+
+
+ for (i=0; i < hp_size; i++) {
+ // if (!IS_FLAG_AVAIL(((Name *)hp->heap)[idx].basic.id)) {
+ if (!IS_FLAG_AVAIL(hp_heap[idx].basic.id)) {
+ idx++;
+ if (idx >= hp_size) {
+ idx -= hp_size;
+ }
+ continue;
+ }
+ // TOGGLE_FLAG_AVAIL(((Name *)hp->heap)[idx].basic.id);
+ TOGGLE_FLAG_AVAIL(hp_heap[idx].basic.id);
+
+ hp->lastAlloc = idx;
+
+ // return (VALUE)&(((Name *)hp->heap)[idx]);
+ return (VALUE)&(hp_heap[idx]);
+ }
+
+ printf("\nCritical ERROR: All %d name cells have been consumed.\n", hp->size);
+ printf("You should have more term cells with -c option.\n");
+ exit(-1);
+
+#endif
+
+}
+
+
+unsigned long getNumOfAvailNameHeap(Heap *hp) {
+ int i;
+ unsigned long total=0;
+ for (i=0; i < hp->size; i++) {
+ if (IS_FLAG_AVAIL( ((Name *)hp->heap)[i].basic.id)) {
+ total++;
+ }
+ }
+ return total;
+}
+unsigned long getNumOfAvailAgentHeap(Heap *hp) {
+ int i;
+ unsigned long total=0;
+ for (i=0; i < hp->size; i++) {
+ if (IS_FLAG_AVAIL( ((Agent *)hp->heap)[i].basic.id)) {
+ total++;
+ }
+ }
+ return total;
+}
+
+
+
+
+/*
+VALUE myallocVal(Heap *hp) {
+
+#ifdef MALLOC
+ Agent *ptr;
+ ptr = malloc(sizeof(Agent));
+ return ptr;
+#else
+
+ int i,idx;
+
+ idx = hp->lastAlloc;
+
+ for (i=0; i < hp->size; i++) {
+ if (!IS_FLAG_AVAIL(((Val *)hp->heap)[idx].basic.id)) {
+ idx++;
+ if (idx >= hp->size) {
+ idx -= hp->size;
+ }
+ continue;
+ }
+ TOGGLE_FLAG_AVAIL(((Val *)hp->heap)[idx].basic.id);
+ hp->lastAlloc = idx;
+ return (VALUE)&(((Val *)hp->heap)[idx]);
+ }
+
+ printf("\nCritical ERROR: All %d term cells have been consumed.\n", hp->size);
+ printf("You should have more term cells with -c option.\n");
+ exit(-1);
+
+#endif
+
+}
+*/
+
+
+
+//static inline
+void myfree(VALUE ptr) {
+
+#ifdef MALLOC
+
+ if (ptr == NULL) return;
+ free(ptr);
+ ptr = NULL;
+#else
+
+ TOGGLE_FLAG_AVAIL(BASIC(ptr)->id);
+#endif
+
+}
+
+
+//static inline
+VALUE makeAgent(VirtualMachine *vm, int id) {
+ VALUE ptr;
+ ptr = myallocAgent(&vm->agentHeap);
+
+#ifdef COUNT_MKAGENT
+ NumberOfMkAgent++;
+#endif
+
+ AGENT(ptr)->basic.id = id;
+ return ptr;
+}
+
+
+
+static inline
+VALUE makeName(VirtualMachine *vm) {
+ VALUE ptr;
+
+ ptr = myallocName(&vm->nameHeap);
+ // AGENT(ptr)->basic.id = ID_NAME;
+ NAME(ptr)->port = (VALUE)NULL;
+
+ return ptr;
+}
+
+
+/*
+VALUE makeVal_int(VirtualMachine *vm, int num) {
+ VALUE ptr;
+ ptr = myallocVal(&vm->agentHeap);
+
+ BASIC(ptr)->id = ID_INT;
+ RVAL(ptr)->u.intval = num;
+ return ptr;
+}
+*/
+
+
+/**********************************
+ Counter for Interaction times
+*********************************/
+#ifdef COUNT_INTERACTION
+int VM_GetInteractionNum(VirtualMachine *vm) {
+ return(vm->NumberOfInteraction);
+}
+
+void VM_ClearInteractionNum(VirtualMachine *vm) {
+ vm->NumberOfInteraction = 0;
+}
+#endif
+
+
+
+
+
+
+
+
+
+
+//-----------------------------------------
+// Pretty printing for terms
+//-----------------------------------------
+
+static VALUE ShowNameHeap=(VALUE)NULL; // showname で表示するときの cyclic 防止
+// showname 時に、呼び出し変数の heap num を入れておく。
+// showname 呼び出し以外は NULL に。
+
+void puts_name(VALUE ptr) {
+
+ if (ptr == (VALUE)NULL) {
+ printf("[NULL]");
+ return;
+ }
+
+ if (IS_GNAMEID(BASIC(ptr)->id)) {
+ printf("%s", IdTable_get_name(BASIC(ptr)->id));
+ } else if (BASIC(ptr)->id == ID_NAME) {
+ printf("<var%lu>", (unsigned long)(ptr));
+ } else {
+ puts_term(ptr);
+ }
+
+}
+
+
+#define PRETTY_VAR
+#ifdef PRETTY_VAR
+typedef struct PrettyList_tag {
+ VALUE id;
+ char *name;
+ struct PrettyList_tag *next;
+} PrettyList;
+
+typedef struct {
+ PrettyList *list;
+ int alphabet;
+ int index;
+ char namebuf[10];
+} PrettyStruct;
+
+PrettyStruct Pretty;
+
+#define MAX_PRETTY_ALPHABET 26
+void Pretty_init(void) {
+ Pretty.alphabet = -1;
+ Pretty.list = NULL;
+ Pretty.index = 1;
+}
+
+PrettyList *PrettyList_new(void) {
+ PrettyList *alist;
+ alist = malloc(sizeof(PrettyList));
+ if (alist == NULL) {
+ printf("[PrettyList] Malloc error\n");
+ exit(-1);
+ }
+ return alist;
+}
+
+char *Pretty_newName(void) {
+ Pretty.alphabet++;
+ if (Pretty.alphabet >= MAX_PRETTY_ALPHABET) {
+ Pretty.alphabet = 0;
+ Pretty.index++;
+ }
+ sprintf(Pretty.namebuf, "%c%d", 'a'+Pretty.alphabet, Pretty.index);
+ return(Pretty.namebuf);
+}
+
+PrettyList *PrettyList_recordName(VALUE a) {
+ PrettyList *alist;
+ alist = PrettyList_new();
+ alist->id = a;
+ alist->name = strdup(Pretty_newName());
+ alist->next = Pretty.list;
+ Pretty.list = alist;
+ return (alist);
+}
+
+char *Pretty_Name(VALUE a) {
+ PrettyList *alist;
+ if (Pretty.list == NULL) {
+ alist = PrettyList_recordName(a);
+ Pretty.list = alist;
+ return (alist->name);
+ } else {
+ PrettyList *at = Pretty.list;
+ while (at != NULL) {
+ if (at->id == a) {
+ return (at->name);
+ }
+ at = at->next;
+ }
+
+ alist = PrettyList_recordName(a);
+ Pretty.list = alist;
+ return (alist->name);
+ }
+}
+#endif
+
+
+#define PUTS_ELEMENTS_NUM 12
+static int Puts_list_element=0;
+
+
+
+static int PutIndirection = 1; // put t for x->t when it is 1
+void puts_term(VALUE ptr) {
+ if (IS_FIXNUM(ptr)) {
+ printf("%d", FIX2INT(ptr));
+ return;
+ } else if (BASIC(ptr) == NULL) {
+ printf("[NULL]");
+ return;
+ }
+
+ if (IS_NAMEID(BASIC(ptr)->id)) {
+ if (NAME(ptr)->port == (VALUE)NULL) {
+ if (IS_GNAMEID(BASIC(ptr)->id)) {
+ //printf("%s", NAME(ptr)->name);
+ printf("%s", IdTable_get_name(BASIC(ptr)->id));
+ } else {
+#ifndef PRETTY_VAR
+ printf("<var%lu>", (unsigned long)(ptr));
+#else
+ printf("<%s>", Pretty_Name(ptr));
+#endif
+ }
+ } else {
+ if (ptr == ShowNameHeap) {
+ printf("<Warning:%s is cyclic>", IdTable_get_name(BASIC(ptr)->id));
+ return;
+ }
+
+ if ((PutIndirection) &&
+ (IdTable_get_name(BASIC(ptr)->id) != NULL)) {
+ printf("%s", IdTable_get_name(BASIC(ptr)->id));
+ } else {
+ puts_term(NAME(ptr)->port);
+ }
+
+ }
+
+ } else if (IS_TUPLEID(BASIC(ptr)->id)) {
+ int i, arity;
+ arity = GET_TUPLEARITY(BASIC(ptr)->id);
+ printf("(");
+ for (i=0; i<arity; i++) {
+ puts_term(AGENT(ptr)->port[i]);
+ if (i != arity - 1) {
+ printf(",");
+ }
+ }
+ printf(")");
+
+ } else if (BASIC(ptr)->id == ID_NIL) {
+ printf("[]");
+
+ } else if (BASIC(ptr)->id == ID_CONS) {
+ printf("[");
+
+ while (ptr != (VALUE)NULL) {
+ puts_term(AGENT(ptr)->port[0]);
+
+ ptr = AGENT(ptr)->port[1];
+ while ((IS_NAMEID(BASIC(ptr)->id)) && (NAME(ptr)->port != (VALUE)NULL)) {
+ ptr = NAME(ptr)->port;
+ }
+ if (BASIC(ptr)->id == ID_NIL) {
+ printf("]");
+ Puts_list_element=0;
+ break;
+ }
+
+ if ((IS_NAMEID(BASIC(ptr)->id)) && (NAME(ptr)->port == (VALUE)NULL)) {
+ // for WHNF
+ printf(",");
+ puts_term(ptr);
+ printf("...");
+ break;
+ }
+
+ printf(",");
+
+ Puts_list_element++;
+ if (Puts_list_element > PUTS_ELEMENTS_NUM) {
+ printf("...]");
+ break;
+ }
+
+ }
+
+ } else {
+ // Agent
+ int i, arity;
+
+ arity = IdTable_get_arity(AGENT(ptr)->basic.id);
+ printf("%s", IdTable_get_name(AGENT(ptr)->basic.id));
+ if (arity != 0) {
+ printf("(");
+ }
+ for (i=0; i<arity; i++) {
+ puts_term(AGENT(ptr)->port[i]);
+ if (i != arity - 1) {
+ printf(",");
+ }
+ }
+ if (arity != 0) {
+ printf(")");
+ }
+ }
+}
+
+
+void puts_name_port0(VALUE ptr) {
+
+ if (ptr == (VALUE)NULL) {
+ printf("<NON-DEFINED>");
+
+ } else if (IS_NAMEID(BASIC(ptr)->id)) {
+ if (NAME(ptr)->port == (VALUE)NULL) {
+ printf("<EMPTY>");
+ } else {
+ ShowNameHeap=ptr;
+ puts_term(NAME(ptr)->port);
+ ShowNameHeap=(VALUE)NULL;
+ }
+ } else {
+ puts("ERROR: it is not a name.");
+ }
+
+}
+
+void puts_names_ast(Ast *ast) {
+ Ast *param = ast;
+
+ int preserve = PutIndirection;
+ PutIndirection = 0;
+
+ while (param != NULL) {
+ char *sym = param->left->sym;
+ puts_name_port0(NameTable_get_heap(sym));
+ param = ast_getTail(param);
+ if (param != NULL)
+ printf(" ");
+
+ }
+ puts("");
+
+ PutIndirection = preserve;
+}
+
+void flush_name_port0(VALUE ptr) {
+ if (ptr == (VALUE)NULL) {
+ return;
+ }
+
+ if (IS_FIXNUM(ptr)) {
+ return;
+ }
+
+ // 使っている name を管理する Hash に記録があるなら flush しない
+ VALUE connected_from;
+ if (keynode_exists_in_another_term(ptr, &connected_from) >= 1) {
+ printf("Error: '%s' cannot be freed because it is referred to by '%s'.\n",
+ IdTable_get_name(BASIC(ptr)->id),
+ IdTable_get_name(BASIC(connected_from)->id));
+
+ return;
+ }
+
+
+ if (NAME(ptr)->port == (VALUE)NULL) {
+ freeName(ptr);
+ } else {
+ ShowNameHeap=ptr;
+ freeAgentRec(NAME(ptr)->port);
+ freeName(ptr);
+ ShowNameHeap=(VALUE)NULL;
+ }
+
+
+#ifdef CELL_USE_VERBOSE
+#ifndef THREAD
+ printf("(%lu agents and %lu names cells are used.)\n",
+ VM.agentHeap.size - getNumOfAvailAgentHeap(&VM.agentHeap),
+ VM.nameHeap.size - getNumOfAvailNameHeap(&VM.nameHeap));
+#endif
+#endif
+
+}
+
+void free_names_ast(Ast *ast) {
+ Ast *param = ast;
+
+ while (param != NULL) {
+ char *sym = param->left->sym;
+ flush_name_port0(NameTable_get_heap(sym));
+ param = ast_getTail(param);
+ }
+}
+
+
+void puts_name_port0_nat(VALUE a1) {
+ int result=0;
+ int idS, idZ;
+ idS = NameTable_get_set_id("S");
+ idZ = NameTable_get_set_id("Z");
+
+ if (a1 == (VALUE)NULL) {
+ printf("<NUll>");
+ } else if (!IS_NAMEID(BASIC(a1)->id)) {
+ printf("<NON-NAME>");
+ } else {
+ if (NAME(a1)->port == (VALUE)NULL) {
+ printf("<EMPTY>");
+ } else {
+
+ a1=NAME(a1)->port;
+ while (BASIC(a1)->id != idZ) {
+ if (BASIC(a1)->id == idS) {
+ result++;
+ a1=AGENT(a1)->port[0];
+ } else if (IS_NAMEID(BASIC(a1)->id)) {
+ a1=NAME(a1)->port;
+ } else {
+ puts("ERROR: puts_name_port0_nat");
+ exit(-1);
+ }
+ }
+ printf("%d\n", result);
+ }
+ }
+
+}
+
+
+
+void puts_eqlist(EQList *at) {
+ while (at != NULL) {
+ puts_term(at->eq.l);
+ printf("~");
+ puts_term(at->eq.r);
+ printf(",");
+ at=at->next;
+ }
+}
+
+
+/**************************************
+ Free node allocation
+**************************************/
+
+//static inline
+void freeAgent(VALUE ptr) {
+
+ if (ptr == (VALUE)NULL) {puts("ERROR: NULL is applied to freeAgent."); return;}
+
+ myfree(ptr);
+}
+
+//static inline
+void freeName(VALUE ptr) {
+ if (ptr == (VALUE)NULL) {puts("ERROR: NULL is applied to freeName."); return;}
+
+ if (IS_LOCAL_NAMEID(BASIC(ptr)->id)) {
+ myfree(ptr);
+ } else {
+ // Global name
+
+ NameTable_erase(IdTable_get_name(BASIC(ptr)->id));
+ // BASIC(ptr)->id = ID_NAME;
+ SET_LOCAL_NAMEID(BASIC(ptr)->id);
+ myfree(ptr);
+ }
+
+}
+
+
+void freeAgentRec(VALUE ptr) {
+
+ loop:
+ if ((IS_FIXNUM(ptr)) || (ptr == (VALUE)NULL)) {
+ return;
+ } else if (IS_NAMEID(BASIC(ptr)->id)) {
+ if (ptr == ShowNameHeap) return;
+
+ if (NAME(ptr)->port != (VALUE)NULL) {
+ VALUE port = NAME(ptr)->port;
+ freeName(ptr);
+ ptr = port; goto loop;
+ } else {
+
+ // The name is kept living if it occurs anywhere as a global.
+ if (keynode_exists_in_another_term(ptr, NULL) < 2) {
+ freeName(ptr);
+ }
+ }
+ } else {
+ if (BASIC(ptr)->id == ID_CONS) {
+ if (IS_FIXNUM(AGENT(ptr)->port[0])) {
+ VALUE port1 = AGENT(ptr)->port[0];
+ freeAgent(ptr);
+ ptr = port1; goto loop;
+ }
+ }
+
+
+ int arity;
+ arity = IdTable_get_arity(AGENT(ptr)->basic.id);
+ if (arity == 1) {
+ VALUE port1 = AGENT(ptr)->port[0];
+ freeAgent(ptr);
+ ptr = port1; goto loop;
+ } else {
+ freeAgent(ptr);
+ // printf(" .");
+ int i;
+ for(i=0; i<arity; i++) {
+ freeAgentRec(AGENT(ptr)->port[i]);
+ }
+ }
+ }
+}
+
+
+
+
+
+
+
+/**************************************
+ NAME TABLE
+**************************************/
+//#include "name_table.h"
+// Just include it, because the bbject file version causes *inefficiency* !
+#include "name_table.c"
+
+
+
+/*************************************
+ Exec STACK
+**************************************/
+
+#ifdef THREAD
+static pthread_cond_t EQStack_not_empty = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t Sleep_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t AllSleep_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+
+
+// GlobalEQStack for execution with threads
+#ifdef THREAD
+typedef struct {
+ EQ *stack;
+ int nextPtr;
+ int size;
+ volatile int lock; // for lightweight spin lock
+} EQStack;
+static EQStack GlobalEQS;
+#endif
+
+
+#ifdef THREAD
+void GlobalEQStack_Init(int size) {
+ GlobalEQS.nextPtr = -1;
+ GlobalEQS.stack = malloc(sizeof(EQ)*size);
+ GlobalEQS.size = size;
+ if (GlobalEQS.stack == NULL) {
+ printf("Malloc error\n");
+ exit(-1);
+ }
+ // for cas_lock
+ GlobalEQS.lock = 0;
+}
+#endif
+
+void VM_EQStackInit(VirtualMachine *vm, int size) {
+ vm->nextPtr_eqStack = -1;
+ vm->eqStack = malloc(sizeof(EQ)*size);
+ vm->eqStack_size = size;
+ if (vm->eqStack == NULL) {
+ printf("Malloc error\n");
+ exit(-1);
+ }
+}
+
+
+void VM_PushEQStack(VirtualMachine *vm, VALUE l, VALUE r) {
+
+ vm->nextPtr_eqStack++;
+
+ if (vm->nextPtr_eqStack >= vm->eqStack_size) {
+ printf("Critical ERROR: Overflow of the EQ stack.\n");
+ printf("You should have larger size by '-x option'.\n");
+ printf("Please see help by using -h option.\n");
+ exit(-1);
+ }
+ vm->eqStack[vm->nextPtr_eqStack].l = l;
+ vm->eqStack[vm->nextPtr_eqStack].r = r;
+
+#ifdef DEBUG
+ //DEBUG
+ printf(" PUSH:");
+ puts_term(l);
+ puts("");
+ puts(" ><");
+ printf(" ");puts_term(r);
+ puts("");
+#endif
+
+
+ // printf("VM%d:pushed\n", vm->id);
+}
+
+int VM_PopEQStack(VirtualMachine *vm, VALUE *l, VALUE *r) {
+ if (vm->nextPtr_eqStack >= 0) {
+ *l = vm->eqStack[vm->nextPtr_eqStack].l;
+ *r = vm->eqStack[vm->nextPtr_eqStack].r;
+ vm->nextPtr_eqStack--;
+ return 1;
+ }
+ return 0;
+}
+
+
+#ifdef THREAD
+void PushEQStack(VALUE l, VALUE r) {
+
+
+
+ lock(&GlobalEQS.lock);
+
+ GlobalEQS.nextPtr++;
+ if (GlobalEQS.nextPtr >= GlobalEQS.size) {
+ printf("Critical ERROR: Overflow of the execution (coequation) stack.\n");
+ printf("You should have larger size.\n");
+ printf("Please see help by using -h option.\n");
+ exit(-1);
+ }
+ GlobalEQS.stack[GlobalEQS.nextPtr].l = l;
+ GlobalEQS.stack[GlobalEQS.nextPtr].r = r;
+
+ unlock(&GlobalEQS.lock);
+
+ if (ActiveThreadNum < MaxThreadNum) {
+ pthread_mutex_lock(&Sleep_lock);
+ pthread_cond_signal(&EQStack_not_empty);
+ pthread_mutex_unlock(&Sleep_lock);
+ }
+
+}
+#endif
+
+
+int PopEQStack(VirtualMachine *vm, VALUE *l, VALUE *r) {
+
+ if (vm->nextPtr_eqStack >= 0) {
+ *l = vm->eqStack[vm->nextPtr_eqStack].l;
+ *r = vm->eqStack[vm->nextPtr_eqStack].r;
+ vm->nextPtr_eqStack--;
+
+ /*
+#ifdef DEBUG
+ puts("");
+ puts("====================================");
+ puts("POP");
+ puts("====================================");
+ puts_term(*l);
+ puts("");
+ puts("><");
+ puts_term(*r);
+ puts("");
+ puts("====================================");
+#endif
+ */
+
+ return 1;
+ }
+#ifndef THREAD
+ return 0;
+#else
+
+ lock(&GlobalEQS.lock);
+
+ if (GlobalEQS.nextPtr < 0) {
+ // GlobalEQStack is empty
+ unlock(&GlobalEQS.lock);
+ return 0;
+ }
+
+ *l = GlobalEQS.stack[GlobalEQS.nextPtr].l;
+ *r = GlobalEQS.stack[GlobalEQS.nextPtr].r;
+ GlobalEQS.nextPtr--;
+
+ unlock(&GlobalEQS.lock);
+
+ return 1;
+#endif
+}
+
+
+#ifdef DEBUG
+void VM_EQStack_allputs(VirtualMachine *vm) {
+ int i;
+ if (vm->nextPtr_eqStack == -1) return;
+ for (i=0; i<=vm->nextPtr_eqStack+1; i++) {
+ printf("%02d: ", i); puts_term(vm->eqStack[i].l);
+ puts("");
+ printf(" ");
+ puts_term(vm->eqStack[i].r);
+ puts("");
+ }
+}
+#endif
+
+
+/* --------------------
+// Linearity check
+
+#ifdef DEBUG
+int VM_EQStack_name_occur(VALUE a, VALUE t) {
+ if (IS_NAMEID(BASIC(t)->id)) {
+ if (a == t) {
+ // puts_term(a); printf(" occurs in "); puts_term(t);puts("");
+ return 1;
+ }
+ return 0;
+ } else {
+ // Agent
+ int i, arity;
+
+ arity = IdTable_get_arity(AGENT(t)->basic.id);
+ for (i=0; i<arity; i++) {
+ if (VM_EQStack_name_occur(a, AGENT(t)->port[i])) {
+ // puts_term(a); printf(" occurs in the term "); puts_term(t);puts("");
+ return 1;
+ }
+ }
+ return 0;
+ }
+}
+
+int VM_EQStack_has_name(VALUE l, VALUE r) {
+
+ if (IS_FIXNUM(l)) {
+ return 1;
+ } else if (BASIC(l) == NULL) {
+ puts("has_name ERROR");
+ exit(-1);
+ }
+ if (IS_NAMEID(BASIC(l)->id)) {
+ if (NAME(l)->port == (VALUE)NULL) {
+ return VM_EQStack_name_occur(l, r);
+ } else {
+ return 0;
+ }
+ } else {
+ // Agent
+ int i, arity;
+ int success = 0;
+ arity = IdTable_get_arity(AGENT(l)->basic.id);
+ for (i=0; i<arity; i++) {
+ if (VM_EQStack_has_name(AGENT(l)->port[i],r)) {
+ success++;
+ } else {
+ // printf("?:");
+ // puts_term(AGENT(l)->port[i]);
+ // puts("");
+ }
+ }
+ printf("??:");
+ puts_term(l);
+ printf("\n ");
+ puts_term(r);
+ puts("");
+ return success;
+ }
+}
+
+int VM_EQStack_has_name_own(VALUE l) {
+ if (IS_FIXNUM(l)) {
+ return 0;
+ }
+ if (IS_NAMEID(BASIC(l)->id)) {
+ if (NAME(l)->port == (VALUE)NULL) {
+ return 0;
+ } else {
+ printf("!");puts_term(l);printf("->");
+ puts_term(NAME(l)->port); puts(""); puts("");
+ printf("id=%d\n", BASIC(l)->id);
+ return 1; //VM_EQStack_has_name_own(NAME(l)->port);
+ }
+ } else {
+ // Agent
+ int i, arity;
+ int success = 0;
+
+ arity = IdTable_get_arity(AGENT(l)->basic.id);
+ printf("Arity of "); puts_term(l);
+ printf(" is %d\n", arity);
+ for (i=0; i<arity; i++) {
+ int j;
+ for (j=0; j<arity; j++) {
+ if (j==i) {
+ printf("* :");
+ puts_term(AGENT(l)->port[j]);
+ puts("");
+ success+=VM_EQStack_has_name_own(AGENT(l)->port[j]);
+ continue;
+ }
+ printf("**:");
+ puts_term(AGENT(l)->port[i]);
+ puts("");
+ puts_term(AGENT(l)->port[j]);
+ puts("");
+ success+=VM_EQStack_has_name(AGENT(l)->port[i], AGENT(l)->port[j]);
+
+ }
+ }
+
+ printf("? :");
+ puts_term(l);
+ puts("");
+
+ return success;
+ }
+}
+
+
+
+int VM_EQStack_check_linearity(VirtualMachine *vm) {
+ int i,j;
+ VALUE l,r;
+ if (vm->nextPtr_eqStack == -1) return 1;
+ for (i=0; i<=vm->nextPtr_eqStack+1; i++) {
+
+ int success = 0;
+ int arity;
+
+ l = vm->eqStack[i].l;
+ r = vm->eqStack[i].r;
+ arity = IdTable_get_arity(AGENT(l)->basic.id);
+ success+=VM_EQStack_has_name_own(l);
+ printf("score=%d\n\n", success);
+
+ success+=VM_EQStack_has_name(l,r);
+ printf("score=%d\n\n", success);
+
+ success+=VM_EQStack_has_name_own(r);
+ printf("score=%d\n\n", success);
+
+ success+=VM_EQStack_has_name(r,l);
+ printf("score=%d\n\n", success);
+
+ if (success == 2) return 1;
+
+ success = 0;
+ for (j=0; j<=vm->nextPtr_eqStack+1; j++) {
+ if (i==j) continue;
+ success +=VM_EQStack_has_name(l, vm->eqStack[j].l);
+ printf("score=%d\n\n", success);
+ success +=VM_EQStack_has_name(l, vm->eqStack[j].r);
+ printf("score=%d\n\n", success);
+
+ success += VM_EQStack_has_name(r, vm->eqStack[j].l);
+ printf("score=%d\n\n", success);
+ success += VM_EQStack_has_name(r, vm->eqStack[j].r);
+ printf("score=%d\n\n", success);
+ }
+
+ printf("score=%d\n\n", success);
+
+ if (success == IdTable_get_arity(AGENT(l)->basic.id) +
+ IdTable_get_arity(AGENT(r)->basic.id)) {
+ return 1;
+ }
+ puts("Linearty ERROR:");
+ puts_term(l);
+ puts("");
+ puts_term(r);
+ puts("");
+ puts("");
+ // VM_EQStack_allputs(vm);
+ return 0;
+ }
+ return 0;
+}
+#endif
+*/
+
+
+/**************************************
+ CODE
+**************************************/
+// *** The occurrence order must be the same in labels in ExecCode. ***
+typedef enum {
+ PUSH=0,
+ PUSHI,
+ MKNAME,
+ MKGNAME,
+ MKAGENT,
+ REUSEAGENT,
+ MYPUSH,
+
+ RET,
+ RET_FREE_LR,
+ RET_FREE_L,
+ RET_FREE_R,
+
+ LOOP,
+ LOOP_RREC,
+ LOOP_RREC1,
+ LOOP_RREC2,
+
+ LOADI,
+ LOAD,
+ LOADP,
+ OP_ADD,
+ OP_SUB,
+ OP_SUBI,
+ OP_MUL,
+ OP_DIV,
+ OP_MOD,
+ OP_LT,
+ OP_LE,
+ OP_EQ,
+ OP_EQI,
+ OP_NE,
+ OP_JMPEQ0,
+ OP_JMPCNCT_CONS,
+ OP_JMPCNCT,
+ OP_JMP,
+ OP_UNM,
+ OP_RAND,
+
+ // connect operation for global names in given nets in the interactive mode.
+ CNCTGN,
+ SUBSTGN,
+
+ NOP,
+} Code;
+
+
+// The real addresses for the `Code':
+static void* CodeAddr[NOP+1];
+
+
+typedef enum {
+ NB_NAME=0,
+ NB_META,
+ NB_INTVAR,
+} NB_TYPE;
+
+
+// NBIND 数は meta数(MAX_PORT*2) + 一つの rule(や eqlist) における
+// 最大name出現数(100)
+#define MAX_NBIND MAX_PORT*2+100
+typedef struct {
+ char *name;
+ int reg;
+ int refnum; // 0: global name (thus created only),
+ // >0: local name
+ // (for the bind names: should be 1)
+ // (for the int names: not paticular)
+ NB_TYPE type; // NB_NAME, NB_META or NB_INTVAR
+} NameBind;
+
+
+
+#define MAX_CODE_SIZE 1024
+typedef struct {
+
+ // Management table for local and global names
+ NameBind bind[MAX_NBIND];
+ int bindPtr; // its index
+ int bindPtr_metanames; // The max index that stores info of meta names
+ // (default: -1)
+
+
+ // Index for local and global names in Regs
+ int localNamePtr; // It starts from VM_OFFSET_LOCALVAR
+ int vmStackSize; // the array size of the Regs.
+
+
+ // Compiled code and its index
+ void *code[MAX_CODE_SIZE];
+ int codeptr;
+
+
+ // For rule agents
+ int idL, idR; // ids of ruleAgentL and ruleAgentR
+ int reg_agentL, reg_agentR; // Beginning reg nums for args of
+ // ruleAgentL, ruleAgentR
+ int annotateL, annotateR; // `Annotation properties' such as (*L) (*R) (int)
+
+} CmEnvironment;
+
+// The annotation properties
+#define ANNOTATE_NOTHING 0 // The rule agent is not reused,
+#define ANNOTATE_REUSE 1 // annotation (*L), (*R) is specified,
+#define ANNOTATE_AS_INT_AGENT 2 // (int i), therefore it should not be freed.
+
+
+static CmEnvironment CmEnv;
+
+//void *ExecCode(int arg, VirtualMachine *vm, void **code);
+void *ExecCode(int mode, VirtualMachine *restrict vm, void *restrict *code);
+
+
+void CmEnv_clear_all();
+
+
+void CmEnv_Init(int vm_heapsize) {
+ CmEnv.vmStackSize = vm_heapsize;
+
+ void **table;
+ table = ExecCode(0, NULL, NULL);
+ for (int i=0; i<NOP; i++) {
+ CodeAddr[i] = table[i];
+ }
+
+ CmEnv_clear_all();
+}
+
+
+static inline
+void CmEnv_clear_localnamePtr() {
+ CmEnv.localNamePtr = VM_OFFSET_LOCALVAR;
+}
+
+void CmEnv_clear_bind(int preserve_idx) {
+ // clear reference counter only, until preserve_idx
+ for (int i=0; i<=preserve_idx; i++) {
+ CmEnv.bind[i].refnum = 0;
+ }
+
+ // after that, clear everything
+ for (int i=preserve_idx+1; i<MAX_NBIND; i++) {
+ CmEnv.bind[i].name = NULL;
+ CmEnv.bind[i].refnum = 0;
+ CmEnv.bind[i].reg = 0;
+ }
+
+ // new name information will be stored from preserve_idx+1
+ CmEnv.bindPtr = preserve_idx+1;
+}
+
+
+void CmEnv_clear_all()
+{
+ // clear all the information of names.
+ CmEnv_clear_bind(-1);
+
+ // reset the annotation properties for rule agents.
+ CmEnv.bindPtr_metanames = -1;
+ CmEnv.annotateL = ANNOTATE_NOTHING;
+ CmEnv.annotateR = ANNOTATE_NOTHING;
+
+ // reset the beginning number for local vars.
+ CmEnv_clear_localnamePtr();
+
+ // reset the index of code array in CmEnv.
+ CmEnv.codeptr = 0;
+
+}
+
+void CmEnv_clear_keeping_rule_properties()
+{
+ // clear the information of names EXCEPT meta ones.
+ CmEnv_clear_bind(CmEnv.bindPtr_metanames);
+
+ if (CmEnv.annotateL != ANNOTATE_AS_INT_AGENT) {
+ CmEnv.annotateL = ANNOTATE_NOTHING;
+ }
+ if (CmEnv.annotateR != ANNOTATE_AS_INT_AGENT) {
+ CmEnv.annotateR = ANNOTATE_NOTHING;
+ }
+
+
+ // reset the beginning number for local vars.
+ CmEnv_clear_localnamePtr();
+
+ // reset the index of code array in CmEnv.
+ CmEnv.codeptr = 0;
+
+}
+
+
+
+
+int CmEnv_set_symbol_as_name(char *name) {
+ // return: a regnum for the given name.
+
+ int result;
+
+ if (name != NULL) {
+ CmEnv.bind[CmEnv.bindPtr].name = name;
+ CmEnv.bind[CmEnv.bindPtr].reg = CmEnv.localNamePtr;
+ CmEnv.bind[CmEnv.bindPtr].refnum = 0;
+ CmEnv.bind[CmEnv.bindPtr].type = NB_NAME;
+
+ CmEnv.bindPtr++;
+ if (CmEnv.bindPtr > MAX_NBIND) {
+ puts("SYSTEM ERROR: CmEnv.bindPtr exceeded MAX_NBIND.");
+ exit(-1);
+ }
+
+ result = CmEnv.localNamePtr;
+ CmEnv.localNamePtr++;
+ if (CmEnv.localNamePtr > CmEnv.vmStackSize) {
+ puts("SYSTEM ERROR: CmEnv.localNamePtr exceeded CmEnv.vmStackSize.");
+ exit(-1);
+ }
+
+ return result;
+ }
+ return -1;
+}
+
+
+void CmEnv_set_symbol_as_meta(char *name, int reg, NB_TYPE type) {
+
+ if (name != NULL) {
+ CmEnv.bind[CmEnv.bindPtr].name = name;
+ CmEnv.bind[CmEnv.bindPtr].reg = reg;
+ CmEnv.bind[CmEnv.bindPtr].refnum = 0;
+ CmEnv.bind[CmEnv.bindPtr].type = type;
+
+ // update the last index for metanames
+ CmEnv.bindPtr_metanames = CmEnv.bindPtr;
+
+ CmEnv.bindPtr++;
+ if (CmEnv.bindPtr > MAX_NBIND) {
+ puts("SYSTEM ERROR: CmEnv.bindPtr exceeded MAX_NBIND.");
+ exit(-1);
+ }
+ }
+}
+
+
+int CmEnv_set_as_INTVAR(char *name) {
+ int result;
+
+ if (name != NULL) {
+ CmEnv.bind[CmEnv.bindPtr].name = name;
+ CmEnv.bind[CmEnv.bindPtr].reg = CmEnv.localNamePtr;
+ CmEnv.bind[CmEnv.bindPtr].refnum = 0;
+ CmEnv.bind[CmEnv.bindPtr].type = NB_INTVAR;
+ result = CmEnv.localNamePtr;
+
+ CmEnv.bindPtr++;
+ if (CmEnv.bindPtr > MAX_NBIND) {
+ puts("SYSTEM ERROR: CmEnv.bindPtr exceeded MAX_NBIND.");
+ exit(-1);
+ }
+
+ CmEnv.localNamePtr++;
+ if (CmEnv.localNamePtr > CmEnv.vmStackSize) {
+ puts("SYSTEM ERROR: CmEnv.localNamePtr exceeded CmEnv.vmStackSize.");
+ exit(-1);
+ }
+
+ return result;
+ }
+ return -1;
+}
+
+
+int CmEnv_reg_search(char *key) {
+ int i;
+ for (i=0; i<CmEnv.bindPtr; i++) {
+ if (strcmp(key, CmEnv.bind[i].name) == 0) {
+ CmEnv.bind[i].refnum++;
+ return CmEnv.bind[i].reg;
+ }
+ }
+ return -1;
+}
+
+int CmEnv_gettype_forname(char *key, NB_TYPE *type) {
+ int i;
+ for (i=0; i<CmEnv.bindPtr; i++) {
+ if (strcmp(key, CmEnv.bind[i].name) == 0) {
+ *type = CmEnv.bind[i].type;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+// Agent用の RegNo を取得する (just for newreg)
+//(これらは、Envコンパイル時に mkName、mkGname の対象にならないため
+// 一時的な変数として使われる)
+int CmEnv_newreg() {
+
+ int result;
+ result = CmEnv.localNamePtr;
+ CmEnv.localNamePtr++;
+ if (CmEnv.localNamePtr > CmEnv.vmStackSize) {
+ puts("SYSTEM ERROR: CmEnv.localNamePtr exceeded CmEnv.vmStackSize.");
+ exit(-1);
+ }
+
+ return result;
+}
+
+
+
+#define EnvAddCode(c)\
+ if (CmEnv.codeptr >= MAX_CODE_SIZE) {\
+ puts("SYSTEM ERROR: The codeptr exceeded MAX_CODE_SIZE");\
+ exit(-1);\
+ }\
+ CmEnv.code[CmEnv.codeptr] = c;\
+ CmEnv.codeptr++;
+
+#define EnvAddCode2(c1,c2) \
+ if (CmEnv.codeptr+1 >= MAX_CODE_SIZE) {\
+ puts("SYSTEM ERROR: The codeptr exceeded MAX_CODE_SIZE");\
+ exit(-1);\
+ }\
+ CmEnv.code[CmEnv.codeptr++] = c1;\
+ CmEnv.code[CmEnv.codeptr++] = c2;
+
+#define EnvAddCode3(c1,c2,c3) \
+ if (CmEnv.codeptr+2 >= MAX_CODE_SIZE) {\
+ puts("SYSTEM ERROR: The codeptr exceeded MAX_CODE_SIZE");\
+ exit(-1);\
+ }\
+ CmEnv.code[CmEnv.codeptr++] = c1;\
+ CmEnv.code[CmEnv.codeptr++] = c2;\
+ CmEnv.code[CmEnv.codeptr++] = c3;
+
+#define EnvAddCode4(c1,c2,c3,c4) \
+ if (CmEnv.codeptr+3 >= MAX_CODE_SIZE) {\
+ puts("SYSTEM ERROR: The codeptr exceeded MAX_CODE_SIZE");\
+ exit(-1);\
+ }\
+ CmEnv.code[CmEnv.codeptr++] = c1;\
+ CmEnv.code[CmEnv.codeptr++] = c2;\
+ CmEnv.code[CmEnv.codeptr++] = c3;\
+ CmEnv.code[CmEnv.codeptr++] = c4;
+
+#define EnvAddCode5(c1,c2,c3,c4,c5) \
+ if (CmEnv.codeptr+4 >= MAX_CODE_SIZE) {\
+ puts("SYSTEM ERROR: The codeptr exceeded MAX_CODE_SIZE");\
+ exit(-1);\
+ }\
+ CmEnv.code[CmEnv.codeptr++] = c1;\
+ CmEnv.code[CmEnv.codeptr++] = c2;\
+ CmEnv.code[CmEnv.codeptr++] = c3;\
+ CmEnv.code[CmEnv.codeptr++] = c4;\
+ CmEnv.code[CmEnv.codeptr++] = c5;
+
+
+#define EnvAddCode6(c1,c2,c3,c4,c5,c6) \
+ if (CmEnv.codeptr+5 >= MAX_CODE_SIZE) {\
+ puts("SYSTEM ERROR: The codeptr exceeded MAX_CODE_SIZE");\
+ exit(-1);\
+ }\
+ CmEnv.code[CmEnv.codeptr++] = c1;\
+ CmEnv.code[CmEnv.codeptr++] = c2;\
+ CmEnv.code[CmEnv.codeptr++] = c3;\
+ CmEnv.code[CmEnv.codeptr++] = c4;\
+ CmEnv.code[CmEnv.codeptr++] = c5;\
+ CmEnv.code[CmEnv.codeptr++] = c6;
+
+
+
+#define EnvCodeClear() CmEnv.codeptr=0
+
+
+void EnvAddCodePUSH(void* c1, void* c2) {
+ EnvAddCode3(CodeAddr[PUSH],c1,c2);
+}
+
+
+void EnvAddCodeMYPUSH(void* c1, void* c2) {
+ EnvAddCode3(CodeAddr[MYPUSH],c1,c2);
+}
+
+void EnvAddCodeCNCTGN(void* c1, void* c2) {
+ EnvAddCode3(CodeAddr[CNCTGN],c1,c2);
+}
+
+void EnvAddCodeSUBSTGN(void* c1, void* c2) {
+ EnvAddCode3(CodeAddr[SUBSTGN],c1,c2);
+}
+
+
+int CmEnv_check_meta_occur_once() {
+ int i;
+
+ for (i=0; i<CmEnv.bindPtr; i++) {
+
+ if (CmEnv.bind[i].type == NB_META) {
+ if (CmEnv.bind[i].refnum != 1) { // Be just once!
+ printf("ERROR: '%s' is referred not once in the right-hand side of the rule definition", CmEnv.bind[i].name);
+ return 0;
+ }
+ // } else if (CmEnv.bind[i].type == NB_INTVAR) {
+ // if (CmEnv.bind[i].refnum == 0) {
+ // printf("Error: %s does not occur at RHS.\n", CmEnv.bind[i].name);
+ // return 0;
+ // }
+ }
+ }
+
+ return 1;
+
+}
+
+
+int CmEnv_check_name_reference_times() {
+ int i;
+ for (i=0; i<CmEnv.bindPtr; i++) {
+ if (CmEnv.bind[i].type == NB_NAME) {
+ if (CmEnv.bind[i].refnum > 2) {
+ printf("ERROR: The name '%s' occurs more than twice.\n",
+ CmEnv.bind[i].name);
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+int CmEnv_generate_code_with_nameinfo(void **code, int offset) {
+ // return: the number of produced codes
+
+ int i;
+
+ /*
+ // check whether the code size estimation is exceeded.
+ {
+ int count_names=0;
+ for (i=0; i<CmEnv.bindPtr; i++) {
+ if (CmEnv.bind[i].type == NB_NAME) {
+ count_names++;
+ }
+ }
+ if (offset + count_names*3 > MAX_CODE_SIZE) {
+ puts("System ERROR: Generated codes were too big.");
+ return -1;
+ }
+ }
+ */
+
+
+ {
+ int ptr=offset;
+
+ for (i=0; i<CmEnv.bindPtr; i++) {
+
+ if (CmEnv.bind[i].type == NB_NAME) {
+
+ if (CmEnv.bind[i].refnum > 0) {
+ code[ptr++] = CodeAddr[MKNAME];
+
+ } else {
+ code[ptr++] = CodeAddr[MKGNAME];
+ code[ptr++] = CmEnv.bind[i].name;
+ }
+ code[ptr++] = (void *)(unsigned long)CmEnv.bind[i].reg;
+ }
+ }
+
+ if (ptr + CmEnv.codeptr > MAX_CODE_SIZE) {
+ puts("System ERROR: Generated codes were too big.");
+ return -1;
+ }
+
+ for (i=0; i<CmEnv.codeptr; i++) {
+ code[ptr++] = CmEnv.code[i];
+ }
+
+ return (ptr-offset);
+ }
+}
+
+
+int CmEnv_generate_code(void **code, int offset) {
+ int ptr=offset;
+ int i;
+ for (i=0; i<CmEnv.codeptr; i++) {
+ code[ptr] = CmEnv.code[i];
+ ptr++;
+ }
+
+ return CmEnv.codeptr;
+}
+
+
+void CopyCode(int byte, void **source, void **target) {
+ int i;
+ for (i=0; i<byte; i++) {
+ target[i]=source[i];
+ }
+}
+
+
+/*
+void EnvPutsCode() {
+ int i,j,arity;
+ for (i=0; i<CmEnv.localNamePtr; i++) {
+ printf("var%d=mkName\n", i);
+ }
+ for (i=0; i<CmEnv.codeptr; i++) {
+ switch (CmEnv.code[i]) {
+ case RET:
+ puts("ret");
+ break;
+ case PUSH:
+ printf("push var%d var%d\n", CmEnv.code[i+1], CmEnv.code[i+2]);
+ i +=2;
+ break;
+ case MKNAME:
+ printf("var%d=mkname\n", CmEnv.code[i+1]);
+ i +=1;
+ break;
+ case MKAGENT:
+ printf("var%d=mkagent %d %d",
+ CmEnv.code[i+1], CmEnv.code[i+2], CmEnv.code[i+3]);
+ arity = CmEnv.code[i+3];
+ i +=3;
+ for(j=0; j<arity; j++) {
+ i++;
+ printf(" var%d", CmEnv.code[i]);
+ }
+ puts("");
+ break;
+ default:
+ printf("CODE %d\n", CmEnv.code[i]);
+
+ }
+ }
+}
+
+*/
+
+
+void PutsCodeN(void **code, int n) {
+ int i,j;
+ unsigned long arity;
+ i=0;
+
+ puts("[PutsCode]");
+ if (n==-1) n = MAX_CODE_SIZE;
+ for (i=0; i<n; i++) {
+ printf("%2d: ", i);
+ if (code[i] == CodeAddr[MKNAME]) {
+ printf("var%lu=mkname\n", (unsigned long)code[i+1]);
+ i +=1;
+ } else if (code[i] == CodeAddr[MKGNAME]) {
+ printf("var%lu=mkgname %s\n", (unsigned long)code[i+2], (char *)code[i+1]);
+ i +=2;
+ } else if (code[i] == CodeAddr[MKAGENT]) {
+ printf("MKAGENT var%lu id:%lu ar:%lu",
+ (unsigned long)code[i+1], (unsigned long)code[i+2], (unsigned long)code[i+3]);
+ arity = (unsigned long)code[i+3];
+ i +=3;
+ for(j=0; j<arity; j++) {
+ i++;
+ printf(" var%lu", (unsigned long)code[i]);
+ }
+ puts("");
+ } else if (code[i] == CodeAddr[REUSEAGENT]) {
+ printf("reuseagent var%lu as id=%lu arity=%lu",
+ (unsigned long)code[i+1], (unsigned long)code[i+2], (unsigned long)code[i+3]);
+ arity = (unsigned long)code[i+3];
+ i +=3;
+ for(j=0; j<arity; j++) {
+ i++;
+ printf(" var%lu", (unsigned long)code[i]);
+ }
+ puts("");
+ } else if (code[i] == CodeAddr[PUSH]) {
+ printf("PUSH var%lu var%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2]);
+ i +=2;
+ } else if (code[i] == CodeAddr[PUSHI]) {
+ printf("PUSHI var%lu $%d\n", (unsigned long)code[i+1], FIX2INT((unsigned long)code[i+2]));
+ i +=2;
+ } else if (code[i] == CodeAddr[MYPUSH]) {
+ printf("MYPUSH var%lu var%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2]);
+ i +=2;
+ } else if (code[i] == CodeAddr[RET]) {
+ puts("RET");
+ if (n==MAX_CODE_SIZE) {
+ return;
+ }
+ } else if (code[i] == CodeAddr[RET_FREE_L]) {
+ puts("RET_FREE_L");
+ if (n==MAX_CODE_SIZE) {
+ return;
+ }
+ } else if (code[i] == CodeAddr[RET_FREE_R]) {
+ puts("RET_FREE_R");
+ if (n==MAX_CODE_SIZE) {
+ return;
+ }
+ } else if (code[i] == CodeAddr[RET_FREE_LR]) {
+ puts("RET_FREE_LR");
+ if (n==MAX_CODE_SIZE) {
+ return;
+ }
+ } else if (code[i] == CodeAddr[LOADI]) {
+ printf("LOADI var%lu $%lu\n", (unsigned long)code[i+1],
+ (unsigned long)code[i+2]);
+ i+=2;
+ } else if (code[i] == CodeAddr[LOOP]) {
+ printf("LOOP\n");
+
+ } else if (code[i] == CodeAddr[LOOP_RREC]) {
+ printf("LOOP_RREC var%lu $%lu\n",
+ (unsigned long)code[i+1],
+ (unsigned long)code[i+2]);
+ i+=2;
+
+ } else if (code[i] == CodeAddr[LOOP_RREC1]) {
+ printf("LOOP_RREC1 var%lu\n",
+ (unsigned long)code[i+1]);
+ i+=1;
+
+ } else if (code[i] == CodeAddr[LOOP_RREC2]) {
+ printf("LOOP_RREC2 var%lu\n",
+ (unsigned long)code[i+1]);
+ i+=1;
+
+ } else if (code[i] == CodeAddr[LOAD]) {
+ printf("LOAD var%lu var%lu\n", (unsigned long)code[i+1],
+ (unsigned long)code[i+2]);
+ i+=2;
+ } else if (code[i] == CodeAddr[LOADP]) {
+ printf("LOADP var%lu var%lu[%lu]\n",
+ (unsigned long)code[i+1],
+ (unsigned long)code[i+2],
+ (unsigned long)code[i+3]);
+ i+=3;
+ } else if (code[i] == CodeAddr[OP_ADD]) {
+ printf("ADD var%lu var%lu var%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2], (unsigned long)code[i+3]);
+ i+=3;
+ } else if (code[i] == CodeAddr[OP_SUB]) {
+ printf("SUB var%lu var%lu var%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2], (unsigned long)code[i+3]);
+ i+=3;
+ } else if (code[i] == CodeAddr[OP_SUBI]) {
+ printf("SUBI var%lu var%lu $%ld\n", (unsigned long)code[i+1], (unsigned long)code[i+2], (long int)code[i+3]);
+ i+=3;
+ } else if (code[i] == CodeAddr[OP_MUL]) {
+ printf("MUL var%lu var%lu var%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2], (unsigned long)code[i+3]);
+ i+=3;
+ } else if (code[i] == CodeAddr[OP_DIV]) {
+ printf("DIV var%lu var%lu var%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2], (unsigned long)code[i+3]);
+ i+=3;
+ } else if (code[i] == CodeAddr[OP_MOD]) {
+ printf("MOD var%lu var%lu var%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2], (unsigned long)code[i+3]);
+ i+=3;
+ } else if (code[i] == CodeAddr[OP_LT]) {
+ printf("LT var%lu var%lu var%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2], (unsigned long)code[i+3]);
+ i+=3;
+ } else if (code[i] == CodeAddr[OP_LE]) {
+ printf("LE var%lu var%lu var%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2], (unsigned long)code[i+3]);
+ i+=3;
+ } else if (code[i] == CodeAddr[OP_EQ]) {
+ printf("EQ var%lu var%lu var%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2], (unsigned long)code[i+3]);
+ i+=3;
+ } else if (code[i] == CodeAddr[OP_EQI]) {
+ printf("EQI var%lu var%lu $%ld\n", (unsigned long)code[i+1], (unsigned long)code[i+2], (long int)code[i+3]);
+ i+=3;
+ } else if (code[i] == CodeAddr[OP_NE]) {
+ printf("NE var%lu var%lu var%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2], (unsigned long)code[i+3]);
+ i+=3;
+ } else if (code[i] == CodeAddr[OP_JMPEQ0]) {
+ printf("JMPEQ0 var%lu $%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2]);
+ i+=2;
+ } else if (code[i] == CodeAddr[OP_JMPCNCT_CONS]) {
+ printf("JMPCNCT_CONS var%lu $%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2]);
+ i+=2;
+ } else if (code[i] == CodeAddr[OP_JMPCNCT]) {
+ printf("JMPCNCT var%lu $%lu $%lu\n",
+ (unsigned long)code[i+1],
+ (unsigned long)code[i+2],
+ (unsigned long)code[i+3]);
+ i+=3;
+ } else if (code[i] == CodeAddr[OP_JMP]) {
+ printf("JMP $%lu\n", (unsigned long)code[i+1]);
+ i+=1;
+ } else if (code[i] == CodeAddr[OP_UNM]) {
+ printf("UNM var%lu var%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2]);
+ i+=2;
+ } else if (code[i] == CodeAddr[OP_RAND]) {
+ printf("RND var%lu var%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2]);
+ i+=2;
+ } else if (code[i] == CodeAddr[CNCTGN]) {
+ printf("CNCTGN var%lu var%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2]);
+ i +=2;
+ } else if (code[i] == CodeAddr[SUBSTGN]) {
+ printf("SUBSTGN var%lu var%lu\n", (unsigned long)code[i+1], (unsigned long)code[i+2]);
+ i +=2;
+ } else if (code[i] == CodeAddr[NOP]) {
+ printf("NOP\n");
+ } else {
+ printf("CODE %lu\n", (unsigned long)code[i]);
+ }
+ }
+}
+
+
+void PutsCode(void **code) {
+ PutsCodeN(code, -1);
+}
+
+
+
+int is_expr(Ast *ptr) {
+
+ if (ptr == NULL) {
+ return 0;
+ }
+
+ switch (ptr->id) {
+ case AST_INT:
+ return 1;
+ break;
+
+ case AST_NAME: {
+ NB_TYPE type;
+ int result = CmEnv_gettype_forname(ptr->left->sym, &type);
+ if (result == 0) {
+ return 9;
+ }
+ if (type != NB_INTVAR) {
+ return 0;
+ }
+
+ return 1;
+ break;
+ }
+
+ case AST_RAND:
+ case AST_UNM: {
+ if (!is_expr(ptr->left)) return 0;
+
+ return 1;
+ break;
+ }
+
+ case AST_PLUS:
+ case AST_SUB:
+ case AST_MUL:
+ case AST_DIV:
+ case AST_MOD:
+ case AST_LT:
+ case AST_LE:
+ case AST_EQ:
+ case AST_NE: {
+ if (!is_expr(ptr->left)) return 0;
+ if (!is_expr(ptr->right)) return 0;
+
+ return 1;
+ break;
+ }
+ default:
+ return 0;
+ }
+}
+
+
+
+int CompileExprFromAst(int target, Ast *ptr) {
+
+ if (ptr == NULL) {
+ return 1;
+ }
+
+ switch (ptr->id) {
+ case AST_INT:
+ EnvAddCode3(CodeAddr[LOADI],
+ (void *)(unsigned long)target,
+ (void *)(unsigned long)(ptr->intval));
+ return 1;
+ break;
+
+ case AST_NAME: {
+ int result = CmEnv_reg_search(ptr->left->sym);
+ if (result == -1) {
+ // result=CmEnv_set_as_INTVAR(ptr->left->sym);
+ printf("ERROR: '%s' has not been defined previously.\n",
+ ptr->left->sym);
+ return 0;
+ }
+ EnvAddCode3(CodeAddr[LOAD],
+ (void *)(unsigned long)target,
+ (void *)(unsigned long)result);
+ return 1;
+ break;
+ }
+ case AST_RAND: {
+ int newreg = CmEnv_newreg();
+ if (!CompileExprFromAst(newreg, ptr->left)) return 0;
+ EnvAddCode3(CodeAddr[OP_RAND],
+ (void *)(unsigned long)target,
+ (void *)(unsigned long)newreg);
+
+ return 1;
+ break;
+ }
+ case AST_UNM: {
+ int newreg = CmEnv_newreg();
+ if (!CompileExprFromAst(newreg, ptr->left)) return 0;
+ EnvAddCode3(CodeAddr[OP_UNM],
+ (void *)(unsigned long)target,
+ (void *)(unsigned long)newreg);
+
+ return 1;
+ break;
+ }
+ case AST_PLUS:
+ case AST_SUB:
+ case AST_MUL:
+ case AST_DIV:
+ case AST_MOD:
+ case AST_LT:
+ case AST_LE:
+ case AST_EQ:
+ case AST_NE: {
+ int newreg = CmEnv_newreg();
+ int newreg2 = CmEnv_newreg();
+ if (!CompileExprFromAst(newreg, ptr->left)) return 0;
+ if (!CompileExprFromAst(newreg2, ptr->right)) return 0;
+
+ switch (ptr->id) {
+ case AST_PLUS:
+ EnvAddCode(CodeAddr[OP_ADD]);
+ break;
+ case AST_SUB:
+ EnvAddCode(CodeAddr[OP_SUB]);
+ break;
+ case AST_MUL:
+ EnvAddCode(CodeAddr[OP_MUL]);
+ break;
+ case AST_DIV:
+ EnvAddCode(CodeAddr[OP_DIV]);
+ break;
+ case AST_MOD:
+ EnvAddCode(CodeAddr[OP_MOD]);
+ break;
+ case AST_LT:
+ EnvAddCode(CodeAddr[OP_LT]);
+ break;
+ case AST_LE:
+ EnvAddCode(CodeAddr[OP_LE]);
+ break;
+ case AST_EQ:
+ EnvAddCode(CodeAddr[OP_EQ]);
+ break;
+ case AST_NE:
+ EnvAddCode(CodeAddr[OP_NE]);
+ break;
+ default:
+ EnvAddCode(CodeAddr[OP_MOD]);
+ }
+ EnvAddCode3((void *)(unsigned long)target,
+ (void *)(unsigned long)newreg,
+ (void *)(unsigned long)newreg2);
+
+ return 1;
+ break;
+ }
+ default:
+ puts("System ERROR: Wrong AST was given to CompileExpr.");
+ return 0;
+
+ }
+
+}
+
+// Rule や eq の中の term をコンパイルするときに使う
+int CompileTermFromAst(Ast *ptr, int target) {
+ // input:
+ // target == -1 => a new cell is allocated from localHeap.
+ // othereise => a cell denoted by the `target' is reused as a new cell.
+ //
+ // output:
+ // return: offset in localHeap
+
+ int result, mkagent;
+ int i, arity;
+
+ int alloc[MAX_PORT];
+
+ if (ptr == NULL) {
+ return -1;
+ }
+
+ switch (ptr->id) {
+ case AST_NAME:
+
+ result = CmEnv_reg_search(ptr->left->sym);
+ if (result == -1) {
+ result=CmEnv_set_symbol_as_name(ptr->left->sym);
+ }
+ return result;
+ break;
+
+ case AST_INT:
+ result = CmEnv_newreg();
+ EnvAddCode3(CodeAddr[LOADI],
+ (void *)(unsigned long)result,
+ (void *)(unsigned long)(ptr->intval));
+ return result;
+ break;
+
+ case AST_NIL:
+ if (target == -1) {
+ result = CmEnv_newreg();
+ mkagent = MKAGENT;
+ } else {
+ result = target;
+ mkagent = REUSEAGENT;
+ }
+ EnvAddCode4(CodeAddr[mkagent],
+ (void *)(unsigned long)result,
+ (void *)(unsigned long)(ID_NIL),
+ (void *)(unsigned long)0);
+ return result;
+ break;
+
+ case AST_CONS:
+ if (target == -1) {
+ result = CmEnv_newreg();
+ mkagent = MKAGENT;
+ } else {
+ result = target;
+ mkagent = REUSEAGENT;
+ }
+ alloc[0] = CompileTermFromAst(ptr->left, -1);
+ alloc[1] = CompileTermFromAst(ptr->right, -1);
+ EnvAddCode6(CodeAddr[mkagent],
+ (void *)(unsigned long)result,
+ (void *)(unsigned long)(ID_CONS),
+ (void *)(unsigned long)(2),
+ (void *)(unsigned long)alloc[0],
+ (void *)(unsigned long)alloc[1]);
+ return result;
+ break;
+
+ case AST_OPCONS:
+ if (target == -1) {
+ result = CmEnv_newreg();
+ mkagent = MKAGENT;
+ } else {
+ result = target;
+ mkagent = REUSEAGENT;
+ }
+ ptr = ptr->right;
+ alloc[0] = CompileTermFromAst(ptr->left, -1);
+ alloc[1] = CompileTermFromAst(ptr->right->left, -1);
+ EnvAddCode6(CodeAddr[mkagent],
+ (void *)(unsigned long)result,
+ (void *)(unsigned long)(ID_CONS),
+ (void *)(unsigned long)(2),
+ (void *)(unsigned long)alloc[0],
+ (void *)(unsigned long)alloc[1]);
+ return result;
+ break;
+
+ /*
+ case AST_TUPLE:
+ if (target == -1) {
+ result = CmEnv_newreg();
+ mkagent = MKAGENT;
+ } else {
+ result = target;
+ mkagent = REUSEAGENT;
+ }
+ arity = ptr->intval;
+ ptr=ptr->right;
+ for(i=0; i< MAX_PORT; i++) {
+ if (ptr == NULL) break;
+ alloc[i] = CompileTermFromAst(ptr->left, -1);
+ ptr = ast_getTail(ptr);
+ }
+
+ EnvAddCode4(CodeAddr[mkagent],
+ (void *)(unsigned long)result,
+ (void *)(unsigned long)(GET_TUPLEID(arity)),
+ (void *)(unsigned long)(arity));
+ for(i=0; i< arity; i++) {
+ EnvAddCode((void *)(unsigned long)alloc[i]);
+ }
+ return result;
+ break;
+ */
+
+
+ case AST_TUPLE:
+ arity = ptr->intval;
+
+ if (arity == 1) {
+ // The case of (A),
+ // `A' is recognised not as an argument, as a first-class object.
+ ptr=ptr->right;
+ alloc[0] = CompileTermFromAst(ptr->left, target);
+ result = alloc[0];
+
+ } else {
+ // normal case
+
+ if (target == -1) {
+ result = CmEnv_newreg();
+ mkagent = MKAGENT;
+ } else {
+ result = target;
+ mkagent = REUSEAGENT;
+ }
+
+ ptr=ptr->right;
+ /*
+ for(i=0; i< MAX_PORT; i++) {
+ if (ptr == NULL) break;
+ alloc[i] = CompileTermFromAst(ptr->left, -1);
+ ptr = ast_getTail(ptr);
+ }
+ */
+ for(i=0; i< arity; i++) {
+ alloc[i] = CompileTermFromAst(ptr->left, -1);
+ ptr = ast_getTail(ptr);
+ }
+
+ EnvAddCode4(CodeAddr[mkagent],
+ (void *)(unsigned long)result,
+ (void *)(unsigned long)(GET_TUPLEID(arity)),
+ (void *)(unsigned long)(arity));
+ for(i=0; i< arity; i++) {
+ EnvAddCode((void *)(unsigned long)alloc[i]);
+ }
+
+ }
+
+ return result;
+ break;
+
+
+
+ case AST_AGENT:
+
+ if (target == -1) {
+ result = CmEnv_newreg();
+ mkagent = MKAGENT;
+ } else {
+ result = target;
+ mkagent = REUSEAGENT;
+ }
+
+ int id = IdTable_getid_builtin_funcAgent(ptr);
+ if (id == -1) {
+ id = NameTable_get_set_id((char *)ptr->left->sym);
+ }
+
+ /* For arity */
+ // result->arity = ptr->arity;
+ arity=0;
+ ptr=ptr->right;
+ for(i=0; i< MAX_PORT; i++) {
+ if (ptr == NULL) break;
+ alloc[i] = CompileTermFromAst(ptr->left, -1);
+ arity++;
+ ptr = ast_getTail(ptr);
+ }
+ // MKAGENT var ID ARITY var0 var1 ...
+ EnvAddCode4(CodeAddr[mkagent],
+ (void *)(unsigned long)result,
+ (void *)(unsigned long)id,
+ (void *)(unsigned long)arity);
+ IdTable_set_arity(id, arity);
+
+ for(i=0; i< arity; i++) {
+ EnvAddCode((void *)(unsigned long)alloc[i]);
+ }
+ return result;
+ break;
+
+ case AST_ANNOTATION_L:
+ case AST_ANNOTATION_R:
+ if (ptr->id == AST_ANNOTATION_L) {
+ CmEnv.annotateL = ANNOTATE_REUSE; // *L が出現したことを示す
+ result = CmEnv.reg_agentL; //VM_OFFSET_ANNOTATE_L;
+ } else {
+ CmEnv.annotateR = ANNOTATE_REUSE; // *L が出現したことを示す
+ result = CmEnv.reg_agentR; // VM_OFFSET_ANNOTATE_R;
+ }
+
+
+ result = CompileTermFromAst(ptr->left, result);
+ return result;
+ break;
+
+
+
+ default:
+ // expression case
+ result = CmEnv_newreg();
+ int compile_result = CompileExprFromAst(result, ptr);
+ if (compile_result != 0) {
+ return result;
+ } else {
+ puts("ERROR: something strange in CompileTermFromAst.");
+ puts_ast(ptr);
+ exit(1);
+ }
+ }
+
+}
+
+
+
+
+// rule の中の eqs をコンパイルするときに使う
+// この関数が呼ばれる前に、rule agents の meta names は
+// Environment に積まれている。
+int check_invalid_occurrence_as_rule(Ast *ast) {
+ NB_TYPE type;
+
+ if (ast->id == AST_NAME) {
+
+ if (CmEnv_gettype_forname(ast->left->sym, &type)) {
+ /*
+ if (type == NB_INTVAR) {
+ printf("ERROR: The variable '%s' for an integer cannot be used as an agent ",
+ ast->left->sym);
+ return 0;
+ }
+ */
+ } else {
+ // printf("ERROR: The name '%s' is not bound ", ast->left->sym);
+ // return 0;
+ }
+ } else if (ast->id == AST_INT) {
+ // printf("ERROR: The integer '%d' is used as an agent ",
+ // ast->intval);
+ // return 0;
+ }
+
+ return 1;
+}
+
+
+int check_invalid_occurrence(Ast *ast) {
+ // communication with global names
+ int count;
+
+ if (ast->id == AST_NAME) {
+ char *sym = ast->left->sym;
+
+
+ VALUE aheap = NameTable_get_heap(sym);
+ if (aheap != (VALUE)NULL) {
+ // already exists as a global
+
+ /*
+ // it is connected with something.
+ if (NAME(aheap)->port != (VALUE)NULL) {
+ printf("ERROR: '%s' is already connected with ", sym);
+ puts_term(NAME(aheap)->port);
+ puts(".");
+ return 1;
+ }
+ */
+
+ count = keynode_exists_in_another_term(aheap, NULL);
+ if (count == 2) {
+ // already twice
+ printf("ERROR: '%s' occurs twice already. \n", sym);
+ printf(" Use 'ifce' command to see the occurrence.\n");
+ return 1;
+ }
+
+ }
+ }
+
+
+ return 0;
+}
+
+
+
+int CompileEQListFromAst(Ast *at) {
+ int t1,t2;
+ Ast *next;
+
+ while (at!=NULL) {
+ if (!check_invalid_occurrence_as_rule(at->left->left) ||
+ !check_invalid_occurrence_as_rule(at->left->right)) {
+ return 0;
+ }
+
+ t1 = CompileTermFromAst(at->left->left, -1);
+ t2 = CompileTermFromAst(at->left->right, -1);
+
+ next = ast_getTail(at);
+
+ // 2021/9/6: It seems, always EnvAddCodePUSH is selected
+ // because at is not NULL in this step. Should be (next == NULL)?
+ //
+ // 2021/9/12: It is found that at==NULL faster than next==NULL
+ // in parallel execution.
+
+ /*
+ if (at == NULL) {
+ EnvAddCodeMYPUSH((void *)(unsigned long)t1, (void *)(unsigned long)t2);
+ } else {
+ EnvAddCodePUSH((void *)(unsigned long)t1, (void *)(unsigned long)t2);
+ }
+ */
+ EnvAddCodePUSH((void *)(unsigned long)t1, (void *)(unsigned long)t2);
+
+ at = next;
+ }
+
+ return 1;
+}
+
+void Compile_Put_Ret_ForRuleBody() {
+
+ if ((CmEnv.annotateL == ANNOTATE_NOTHING) &&
+ (CmEnv.annotateR == ANNOTATE_NOTHING)) {
+ EnvAddCode(CodeAddr[RET_FREE_LR]);
+
+ } else if ((CmEnv.annotateL == ANNOTATE_NOTHING) &&
+ (CmEnv.annotateR != ANNOTATE_NOTHING)) {
+ // FreeL
+ if (CmEnv.reg_agentL == VM_OFFSET_ANNOTATE_L) {
+ EnvAddCode(CodeAddr[RET_FREE_L]);
+ } else {
+ EnvAddCode(CodeAddr[RET_FREE_R]);
+ }
+
+ } else if ((CmEnv.annotateL != ANNOTATE_NOTHING) &&
+ (CmEnv.annotateR == ANNOTATE_NOTHING)) {
+ // FreeR
+ if (CmEnv.reg_agentL == VM_OFFSET_ANNOTATE_L) {
+ EnvAddCode(CodeAddr[RET_FREE_R]);
+ } else {
+ EnvAddCode(CodeAddr[RET_FREE_L]);
+ }
+ } else {
+ EnvAddCode(CodeAddr[RET]);
+ }
+
+}
+
+
+int CompileStmListFromAst(Ast *at) {
+ Ast *ptr;
+ int toRegLeft;
+
+ while (at!=NULL) {
+ ptr=at->left;
+
+ // (AST_LD (AST_NAME sym NULL) some)
+ if (ptr->id != AST_LD) {
+ puts("System ERROR: The given StmList contains something besides statements.");
+ exit(-1);
+ }
+ // operation of x=y:
+ // for the x
+ toRegLeft = CmEnv_reg_search(ptr->left->left->sym);
+ if (toRegLeft == -1) {
+ toRegLeft = CmEnv_set_as_INTVAR(ptr->left->left->sym);
+ } else {
+ printf("Warning: '%s' has been already defined.\n", ptr->left->left->sym);
+ }
+
+ // for the y
+ if (ptr->right->id == AST_NAME) {
+ // y is a name
+ int toRegRight = CmEnv_reg_search(ptr->right->left->sym);
+ if (toRegRight == -1) {
+ toRegRight = CmEnv_set_as_INTVAR(ptr->right->left->sym);
+ }
+ EnvAddCode3(CodeAddr[LOAD],
+ (void *)(unsigned long)toRegLeft,
+ (void *)(unsigned long)toRegRight);
+
+ } else if (ptr->right->id == AST_INT) {
+ // y is an integer
+ EnvAddCode3(CodeAddr[LOADI],
+ (void *)(unsigned long)toRegLeft,
+ (void *)(unsigned long)ptr->right->intval);
+
+ } else {
+ // y is an expression
+ if (!CompileExprFromAst(toRegLeft, ptr->right)) return 0;
+
+ }
+
+
+
+ at = ast_getTail(at);
+ }
+
+ return 1;
+}
+
+
+
+
+// --- RewriteEQListOnAst ---
+
+Ast* SubstAst(char *sym, Ast *aterm, Ast *target, int *result) {
+ // target is astterm: (AST asttermL asttermR)
+ // this function replaces sym with aterm in target, i.e. tgs[aterm/sym].
+
+ if (target->id == AST_NAME) {
+ if (strcmp(target->left->sym, sym) == 0) {
+ *result = 1;
+ return aterm;
+
+ } else {
+ return target;
+ }
+
+ } else if (target->id == AST_OPCONS) {
+ target->right = SubstAst(sym, aterm, target->right, result);
+ return target;
+
+ } else if (target->id == AST_CONS) {
+ target->left = SubstAst(sym, aterm, target->left, result);
+ if (*result) {
+ return target;
+ } else {
+ target->right = SubstAst(sym, aterm, target->right, result);
+ return target;
+ }
+
+ } else if ((target->id == AST_TUPLE) ||
+ (target->id == AST_AGENT)) {
+ // (AST_AGENT (ID_SYM sym NULL) paramlist)
+
+ Ast *port = target->right;
+
+ for(int i=0; i< MAX_PORT; i++) {
+ if (port == NULL) break;
+
+ port = SubstAst(sym, aterm, port, result);
+ if (*result) break;
+
+ port = ast_getTail(port);
+ }
+ return target;
+
+ } else if (target->id == AST_LIST) {
+ Ast *elem = target->right;
+
+ while (elem != NULL) {
+ elem = SubstAst(sym, aterm, elem, result);
+ if (*result) break;
+
+ elem = ast_getTail(elem);
+ }
+ return target;
+
+ } else {
+ return target;
+ }
+
+}
+
+
+int SubstASTList(int nth, char *sym, Ast *aterm, Ast *eqs) {
+ // eqs[aterm/sym] except nth-eq
+
+ Ast *eq, *at = eqs;
+ int ct = 0;
+ int result;
+
+ while (at != NULL) {
+ eq = at->left;
+
+ if (ct == nth) {
+ ct++;
+ at = ast_getTail(at);
+ continue;
+ }
+
+ result=0;
+ eq->left = SubstAst(sym, aterm, eq->left, &result);
+ if (result) {
+ return 1;
+ }
+
+ result=0;
+ eq->right = SubstAst(sym, aterm, eq->right, &result);
+ if (result) {
+ return 1;
+ }
+
+ ct++;
+ at = ast_getTail(at);
+
+ }
+
+ return 0;
+}
+
+
+void RewriteEQListOnAST(Ast *eqs) {
+ // eqs : (AST_LIST eq1 (AST_LIST eq2 (AST_LIST eq3 NULL)))
+ // eq : (AST_CNCT astterm1 astterm2)
+
+ Ast *at, *prev, *target, *term;
+ char *sym;
+ int nth = 0;
+
+ at = prev = eqs;
+
+ while (at != NULL) {
+ // (id, left, right)
+ // at : (AST_LIST, x1, NULL)
+ // at : (AST_LIST, x1, (AST_LIST, x2, NULL))
+ target = at->left;
+
+ // printf("\n[target] "); puts_ast(target);
+ // printf("\n%dnth in ", nth); puts_ast(eqs); printf("\n\n");
+
+
+ if (target->left->id == AST_NAME) {
+ sym = target->left->left->sym;
+ term = target->right;
+
+ if (SubstASTList(nth, sym, term, eqs)) {
+ // printf("=== hit %dth\n", nth);
+
+ if (prev != at) {
+
+ // 前のリストの接続先を、現在地を省いて、その次の要素に変更。
+ prev->right = at->right;
+ at = at->right;
+
+ } else {
+ // 先頭の要素が代入に使われたので、
+ // body 内の eqs から先頭を削除
+ // (AST_LIST, x1, (AST_LIST, x2, *next)) ==> (AST_LIST, x2, *next)
+ eqs->left = eqs->right->left;
+ eqs->right = eqs->right->right;
+ eqs = eqs->right;
+ // 対象 at を次の要素に更新し、prev も at とする
+ prev = at = at->right;
+ }
+
+ continue;
+ }
+ }
+
+
+
+ if (target->right->id == AST_NAME) {
+ sym = target->right->left->sym;
+ term = target->left;
+
+
+ if (SubstASTList(nth, sym, term, eqs)) {
+ // printf("=== hit %dth\n", nth);
+
+ if (prev != at) {
+
+ // 前のリストの接続先を、現在地を省いて、その次の要素に変更。
+ prev->right = at->right;
+ at = at->right;
+
+ } else {
+ // 先頭の要素が代入に使われたので、
+ // body 内の eqs から先頭を削除
+ // (AST_LIST, x1, (AST_LIST, x2, *next)) ==> (AST_LIST, x2, *next)
+ eqs->left = eqs->right->left;
+ eqs->right = eqs->right->right;
+ eqs = eqs->right;
+ // 対象 at を次の要素に更新し、prev も at とする
+ prev = at = at->right;
+ }
+
+ continue;
+
+ }
+
+ }
+
+ nth++;
+ prev = at;
+ at = at->right;
+
+ }
+}
+
+
+
+int CompileBodyFromAst(Ast *body) {
+ Ast *stms, *eqs;
+
+ if (body == NULL) return 1;
+
+ stms = body->left;
+ eqs = body->right;
+
+ RewriteEQListOnAST(eqs);
+
+ if (!CompileStmListFromAst(stms)) return 0;
+ if (!CompileEQListFromAst(eqs)) {
+ printf("in the rule:\n %s >< %s\n",
+ IdTable_get_name(CmEnv.idL),
+ IdTable_get_name(CmEnv.idR));
+ return 0;
+ }
+
+ return 1;
+}
+
+
+
+
+
+
+/**************************************
+ TABLE for RULES
+**************************************/
+typedef struct RuleList {
+ int sym;
+ int available;
+ void* code[MAX_CODE_SIZE];
+ struct RuleList *next;
+} RuleList;
+
+RuleList *RuleList_new() {
+ RuleList *alist;
+ alist = malloc(sizeof(RuleList));
+ if (alist == NULL) {
+ printf("Malloc error\n");
+ exit(-1);
+ }
+ alist->available = 0;
+ return alist;
+}
+
+void RuleList_set_code(RuleList *at, int sym, void **code, int byte, RuleList *next) {
+ at->sym = sym;
+ at->available = 1;
+ CopyCode(byte, code, at->code);
+ at->next = next;
+}
+
+void RuleList_inavailable(RuleList *at) {
+ at->available = 0;
+}
+
+
+#define RULEHASH_SIZE NUM_AGENTS
+static RuleList *RuleTable[RULEHASH_SIZE];
+
+void RuleTable_init() {
+ int i;
+ for (i=0; i<RULEHASH_SIZE; i++) {
+ RuleTable[i] = NULL;
+ }
+}
+
+
+void RuleTable_record(int symlID, int symrID, int byte, void **code) {
+
+ RuleList *add;
+
+ if (RuleTable[symlID] == NULL) { /* もしテーブルが空ならば */
+ add = RuleList_new(); /* データノードを作成し */
+
+ RuleList_set_code(add, symrID, code, byte, NULL);
+ RuleTable[symlID] = add; /* 単にセット */
+ return;
+
+ }
+
+ /* 線形探査が必要 */
+ RuleList *at = RuleTable[symlID]; // 先頭をセット
+
+ while( at != NULL ) {
+ if( at->sym == symrID) { // すでにあれば書き換える
+ CopyCode(byte, code, at->code);
+ return;
+ }
+ at = at->next;
+ }
+
+ // key がなかったら、 先頭に追加
+
+ /* 以前の先頭を自分の次にする */
+ add = RuleList_new();
+ RuleList_set_code(add, symrID, code, byte, RuleTable[symlID]);
+ RuleTable[symlID] = add;
+ return;
+}
+
+
+
+void RuleTable_delete(int symlID, int symrID) {
+
+ if (RuleTable[symlID] == NULL) { /* もしテーブルが空ならば */
+ // 何もしない
+ return;
+
+ }
+
+ /* 線形探査が必要 */
+ RuleList *at = RuleTable[symlID]; /* 先頭をセット */
+
+ while( at != NULL ) {
+ if( at->sym == symrID) { /* すでにあれば書き換える */
+ RuleList_inavailable(at);
+ return;
+ }
+ at = at->next; /* 次のチェーンを辿る */
+ }
+
+}
+
+
+
+
+
+// -------------------------------------------------------------
+
+int getArityFromAST(Ast *ast) {
+ int i;
+ Ast *ptr;
+
+ ptr = ast->right;
+ for (i=0; i<MAX_PORT; i++) {
+ if (ptr == NULL) break;
+ ptr = ast_getTail(ptr);
+ }
+ return i;
+}
+
+
+// setMetaL(Ast *ast)
+// A(x1,x2) が ast に与えられれば、rule 内で x1, x2 が
+// VM のレジスタである VM_OFFSET_META_L(0)番、VM_OFFSET_META_L(1)番を
+// 参照できるようにする。
+void setMetaL(Ast *ast) {
+ int i;
+ Ast *ptr;
+ NB_TYPE type;
+
+ ptr = ast->right;
+ for (i=0; i<MAX_PORT; i++) {
+ if (ptr == NULL) break;
+ if (ptr->left->id == AST_NAME) {
+ type = NB_META;
+ } else {
+ type = NB_INTVAR;
+ }
+ CmEnv_set_symbol_as_meta(ptr->left->left->sym, VM_OFFSET_META_L(i), type);
+
+ ptr = ast_getTail(ptr);
+ }
+}
+void setMetaR(Ast *ast) {
+ int i;
+ Ast *ptr;
+ NB_TYPE type;
+
+ ptr = ast->right;
+ for (i=0; i<MAX_PORT; i++) {
+ if (ptr == NULL) break;
+ if (ptr->left->id == AST_NAME) {
+ type = NB_META;
+ } else {
+ type = NB_INTVAR;
+ }
+ CmEnv_set_symbol_as_meta(ptr->left->left->sym, VM_OFFSET_META_R(i), type);
+ ptr = ast_getTail(ptr);
+ }
+}
+
+void setMetaL_asIntName(Ast *ast) {
+ //CmEnv_set_symbol_as_meta(ast->left->sym, VM_OFFSET_META_L(0), NB_INTVAR);
+ CmEnv_set_symbol_as_meta(ast->left->sym, CmEnv.reg_agentL, NB_INTVAR);
+
+}
+
+void setMetaR_asIntName(Ast *ast) {
+ // CmEnv_set_symbol_as_meta(ast->left->sym, VM_OFFSET_META_R(0), NB_INTVAR);
+ CmEnv_set_symbol_as_meta(ast->left->sym, CmEnv.reg_agentR, NB_INTVAR);
+}
+
+
+
+void setAnnotateLR(int left, int right) {
+ CmEnv.reg_agentL = left;
+ CmEnv.reg_agentR = right;
+}
+
+
+
+int getRuleAgentID(Ast *ruleAgent) {
+ // Returns agents ids of ast type.
+ // This is called from makeRule to get ids of rule agents.
+
+ int id;
+
+ if (ruleAgent->id == AST_TUPLE) {
+ id = GET_TUPLEID(ruleAgent->intval);
+
+ } else if (ruleAgent->id == AST_OPCONS) {
+ id = ID_CONS;
+
+ } else if (ruleAgent->id == AST_NIL) {
+ id = ID_NIL;
+
+ } else if (ruleAgent->id == AST_INTVAR) {
+ id = ID_INT;
+
+ } else if (strcmp((char *)ruleAgent->left->sym, "Int") == 0) {
+ id = ID_INTAGENT;
+ } else {
+
+ id = IdTable_getid_builtin_funcAgent(ruleAgent);
+ if (id == -1) {
+ id=NameTable_get_set_id(ruleAgent->left->sym);
+ }
+ }
+
+ return id;
+}
+
+
+
+
+int CompileGuardBodiesFromAST(Ast *guard_bodies_top,
+ void **code, int offset_code) {
+ // return codesize
+ // -1 : compile error
+ Ast *guard_bodies, *guard_body, *body, *guard;
+ int code_size = offset_code;
+
+ int generated_codesize; // コンパイルで生成されたコード数保存用
+
+ guard_bodies = guard_bodies_top;
+
+ do {
+
+ guard_body = guard_bodies->left;
+
+ guard = guard_body->left;
+ body = guard_body->right;
+
+ CmEnv_clear_keeping_rule_properties();
+
+
+ if (guard != NULL) {
+ int label; // 飛び先指定用
+
+ // Gurad のコンパイル
+ int newreg = CmEnv_newreg();
+ if (!CompileExprFromAst(newreg, guard)) return -1;
+ generated_codesize = CmEnv_generate_code(code,code_size);
+ code_size+=generated_codesize;
+
+ //JMPEQ0 用コードを作成
+ code[code_size++] = CodeAddr[OP_JMPEQ0];
+ code[code_size++] = (void *)(unsigned long)newreg;
+ label = code_size++; // 飛び先を格納するアドレスを記憶しておく
+
+ // stms と eqs のコンパイル
+ EnvCodeClear();
+ CmEnv_clear_localnamePtr(); // 局所変数としての reg番号を初期化
+
+ if (!CompileBodyFromAst(body)) return -1;
+ Compile_Put_Ret_ForRuleBody();
+
+ generated_codesize = CmEnv_generate_code_with_nameinfo(code,code_size);
+ if (generated_codesize < 0) {
+ puts("System ERROR: Generated codes were too big.");
+ return -1;
+ }
+
+ // 次の guard コンパイルで &code[code_size] にて指定できるように
+ // code_size を更新しておく。
+ code_size += generated_codesize;
+ if (code_size > MAX_CODE_SIZE) {
+ puts("System ERROR: Generated codes were too big.");
+ return -1;
+ }
+
+ // JMPEQ0 のとび先を格納
+ code[label]=(void *)(unsigned long)generated_codesize;
+
+
+ // puts("");
+ // PutsCodeN(code, code_size);
+ // puts("");
+
+ } else {
+ // 通常コンパイル
+ if (!CompileBodyFromAst(body)) return -1;
+ Compile_Put_Ret_ForRuleBody();
+
+ generated_codesize = CmEnv_generate_code_with_nameinfo(code,code_size);
+
+ code_size += generated_codesize;
+ if (generated_codesize < 0) {
+ puts("System ERROR: Generated codes were too long.");
+ return -1;
+ }
+
+ }
+
+
+
+ if (!CmEnv_check_meta_occur_once()) {
+ printf("in the rule:\n %s >< %s.\n",
+ IdTable_get_name(CmEnv.idL),
+ IdTable_get_name(CmEnv.idR));
+
+ // puts_ast(ruleL); printf("><");
+ // puts_ast(ruleR); puts("");
+ return -1;
+ }
+ guard_bodies = ast_getTail(guard_bodies);
+ } while (guard_bodies != NULL);
+
+
+ return code_size;
+
+
+}
+
+
+
+int CompileIfSentenceFromAST(Ast *if_sentence_top,
+ void **code, int offset_code) {
+ // return
+ // generated codesize
+ // -1 : compile error
+
+ // <if-sentence> ::= (AST_IF guard (AST_BRANCH <then> <else>))
+ // | <body>
+ // <then> ::= <if-sentence>
+ // <else> ::= <if-sentence>
+
+ Ast *if_sentence;
+
+ int generated_codesize; // コンパイルで生成されたコード数保存用
+
+ if_sentence = if_sentence_top;
+
+ CmEnv_clear_keeping_rule_properties();
+
+
+ if ((if_sentence == NULL) || (if_sentence->id == AST_BODY)) {
+ // 通常コンパイル
+ Ast *body = if_sentence;
+
+ if (!CompileBodyFromAst(body)) return -1;
+ Compile_Put_Ret_ForRuleBody();
+
+ generated_codesize = CmEnv_generate_code_with_nameinfo(code, offset_code);
+
+ //code_size += generated_codesize;
+ if (generated_codesize < 0) {
+ puts("System ERROR: Generated codes were too long.");
+ return -1;
+ }
+
+ if (!CmEnv_check_meta_occur_once()) {
+ printf("in the rule:\n %s >< %s.\n",
+ IdTable_get_name(CmEnv.idL),
+ IdTable_get_name(CmEnv.idR));
+ return -1;
+ }
+
+ return generated_codesize;
+
+ } else {
+ // if_sentence
+ Ast *guard, *then_branch, *else_branch;
+ int label; // 飛び先指定用
+
+ int offset = offset_code;
+
+ guard = if_sentence->left;
+ then_branch = if_sentence->right->left;
+ else_branch = if_sentence->right->right;
+
+ // Gurad のコンパイル
+ int newreg = CmEnv_newreg();
+ if (!CompileExprFromAst(newreg, guard)) return -1;
+ generated_codesize = CmEnv_generate_code(code, offset);
+ offset += generated_codesize;
+
+
+ //JMPEQ0 用コードを作成
+ code[offset++] = CodeAddr[OP_JMPEQ0];
+ code[offset++] = (void *)(unsigned long)newreg;
+ label = offset++; // 飛び先を格納するアドレスを記憶しておく
+
+ // then_branch のコンパイル
+ EnvCodeClear();
+ CmEnv_clear_localnamePtr(); // 局所変数としての reg番号を初期化
+
+ generated_codesize = CompileIfSentenceFromAST(then_branch, code, offset);
+ if (generated_codesize < 0) return -1;
+
+ offset += generated_codesize;
+
+ if (offset > MAX_CODE_SIZE) {
+ puts("System ERROR: Generated codes were too big.");
+ return -1;
+ }
+
+ // JMPEQ0 のとび先を格納(相対ジャンプ)
+ code[label]=(void *)(unsigned long)generated_codesize;
+
+
+ // else_branch のコンパイル
+ EnvCodeClear();
+ CmEnv_clear_localnamePtr(); // 局所変数としての reg番号を初期化
+
+ generated_codesize = CompileIfSentenceFromAST(else_branch, code, offset);
+ if (generated_codesize < 0) return -1;
+
+ offset += generated_codesize;
+
+ if (offset > MAX_CODE_SIZE) {
+ puts("System ERROR: Generated codes were too big.");
+ return -1;
+ }
+
+ return offset - offset_code;
+ }
+
+
+}
+
+
+
+
+void makeRule(Ast *ast) {
+ // (ASTRULE (AST_CNCT agentL agentR)
+ // <if-sentence>)
+ //
+ // WHERE
+ // <if-sentence> ::= (AST_IF guard (AST_BRANCH <then> <else>))
+ // | <body>
+ // <then> ::= <if-sentence>
+ // <else> ::= <if-sentence>
+
+
+ int idR, idL;
+ Ast *ruleL, *ruleR, *if_sentence;
+
+ void* code[MAX_CODE_SIZE];
+ int code_size=0;
+
+ ruleL = ast->left->left;
+ ruleR = ast->left->right;
+
+ if (ruleL->id == AST_NAME) {
+ printf("ERROR: The name '%s' was specified as the left-hand side of rule agents. It should be an agent.\n", ruleL->left->sym);
+ return;
+ }
+ if (ruleR->id == AST_NAME) {
+ printf("ERROR: The name '%s' was specified as the right-hand side of rule agents. It should be an agent.\n", ruleR->left->sym);
+ return;
+ }
+
+
+ if_sentence = ast->right;
+
+ ruleL = ast_remove_tuple1(ruleL);
+ ruleR = ast_remove_tuple1(ruleR);
+
+
+ // #define MYDEBUG1
+#ifdef MYDEBUG1
+ puts_ast(ruleL); puts("");
+ puts_ast(ruleR); puts("");
+ puts_ast(bodies);
+ exit(1);
+#endif
+
+
+
+ // store ids of rule agent
+ idL = getRuleAgentID(ruleL);
+ idR = getRuleAgentID(ruleR);
+
+
+ /*
+ // prevent re-defining of built-in agents.
+ if (IdTable_is_builtin_rule(ruleL, ruleR)) {
+ printf("Warning: %s >< %s is already defined as built-in.\n",
+ IdTable_get_name(idL), IdTable_get_name(idR));
+
+ } else {
+
+ if (IdTable_is_builtin_rule(ruleR, ruleL)) {
+ printf("Warning: %s >< %s is already defined as built-in.\n",
+ IdTable_get_name(idR), IdTable_get_name(idL));
+ }
+
+ }
+ */
+
+
+ // >< (int i) 対策
+ // int i は (AST_INTVAR (AST_SYM sym NULL) NULL) として構築されているので
+ // ID_TUPLE1 である間は読み飛ばす
+ while (idL == ID_TUPLE1) {
+ ruleL = ruleL->right->left;
+ idL = getRuleAgentID(ruleL);
+ }
+ while (idR == ID_TUPLE1) {
+ ruleR = ruleR->right->left;
+ idR = getRuleAgentID(ruleR);
+ }
+
+
+ // Annotation (*L)、(*R) の処理があるため
+ // 単純に ruleAgentL、ruleAgentR を入れ替えれば良いわけではない。
+
+ if (idL > idR) {
+ // 標準では Append(xs, r) >< [y|ys] なので
+ // idL の方が大きくなって欲しい
+
+ // annotation が (*L) なら左側、(*R) なら右側を指すものとする
+ setAnnotateLR(VM_OFFSET_ANNOTATE_L, VM_OFFSET_ANNOTATE_R);
+
+ } else {
+ Ast *tmp;
+ tmp = ruleL;
+ ruleL = ruleR;
+ ruleR = tmp;
+
+ int idTmp;
+ idTmp = idL;
+ idL = idR;
+ idR = idTmp;
+
+ // aplist 内の (*L) (*R) はそのままにしておき、
+ // annotation が (*L) なら右側、(*R) なら左側を指すものとする
+ setAnnotateLR(VM_OFFSET_ANNOTATE_R, VM_OFFSET_ANNOTATE_L);
+ }
+
+ {
+ int arity;
+
+ // code の先頭2つは idL、idR の arity を格納する
+ if (idL == ID_INT) {
+ arity = 0;
+ } else {
+ arity = getArityFromAST(ruleL);
+ }
+ IdTable_set_arity(idL, arity);
+ code[0] = (void *)(unsigned long)arity;
+
+ if (idR == ID_INT) {
+ arity = 0;
+ } else {
+ arity = getArityFromAST(ruleR);
+ }
+ IdTable_set_arity(idR, arity);
+ code[1] = (void *)(unsigned long)arity;
+
+ code_size = 2;
+ }
+
+
+
+ CmEnv_clear_all();
+
+ if (idL == ID_INT) {
+ setMetaL_asIntName(ruleL);
+ CmEnv.annotateL = ANNOTATE_AS_INT_AGENT; // FreeL 出力を防ぐ
+ } else {
+ setMetaL(ruleL);
+ }
+
+ if (idR == ID_INT) {
+ setMetaR_asIntName(ruleR);
+ CmEnv.annotateR = ANNOTATE_AS_INT_AGENT; // FreeR 出力を防ぐ
+ } else {
+ setMetaR(ruleR);
+ }
+
+ CmEnv.idL = idL;
+ CmEnv.idR = idR;
+
+
+
+ //code_size = CompileGuardBodiesFromAST(guard_bodies, code, code_size);
+ code_size += CompileIfSentenceFromAST(if_sentence, code, code_size);
+ if (code_size < 0)
+ return;
+
+
+#ifdef MYDEBUG
+ PutsCodeN(code, code_size); exit(1);
+#endif
+
+ /*
+ printf("Rule: %s(id:%d) >< %s(id:%d).\n",
+ IdTable_get_name(idL), idL,
+ IdTable_get_name(idR), idR);
+ PutsCodeN(&code[2], code_size-2);
+ //exit(1);
+ */
+
+
+// --------------------------------------------------------------
+// For Fibonacci (as much as possible)
+// #define HAND_FIB_AS_MUCH_AS_POSSIBLE
+// --------------------------------------------------------------
+#ifdef HAND_FIB_AS_MUCH_AS_POSSIBLE
+ if ((strcmp(IdTable_get_name(idL), "Fib") == 0) &&
+ (idR == ID_INT)) {
+
+ printf("Rule is optimised: %s >< %s.\n",
+ IdTable_get_name(idL),
+ IdTable_get_name(idR));
+
+ // PutsCodeN(&code[2], code_size-2);
+
+ int i=2;
+ // code[i++] = CodeAddr[MKVAL];
+ // code[i++] = (void *)14;
+ // code[i++] = (void *)0;
+ // code[i++] = (void *)0;
+ //
+ // code[i++] = CodeAddr[OP_EQ];
+ // code[i++] = (void *)12;
+ // code[i++] = (void *)11;
+ // code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[OP_EQI];
+ //code[i++] = (void *)11; // ここで 11(OFFSET_R)を壊してしまうと他で影響あり
+ code[i++] = (void *)12;
+ code[i++] = (void *)11;
+ code[i++] = (void *)0;
+
+ code[i++] = CodeAddr[OP_JMPEQ0];
+ code[i++] = (void *)12;
+ // code[i++] = (void *)8;
+ code[i++] = (void *)4;
+
+ // code[i++] = CodeAddr[MKVAL];
+ // code[i++] = (void *)12;
+ // code[i++] = (void *)0;
+ // code[i++] = (void *)1;
+ //
+ // code[i++] = CodeAddr[PUSH];
+ // code[i++] = (void *)0;
+ // code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[PUSHI];
+ code[i++] = (void *)0;
+ code[i++] = (void *)INT2FIX(1);
+
+ code[i++] = CodeAddr[RET_FREE_L];
+
+
+
+
+ // code[i++] = CodeAddr[MKVAL];
+ // code[i++] = (void *)14;
+ // code[i++] = (void *)0;
+ // code[i++] = (void *)1;
+ //
+ // code[i++] = CodeAddr[OP_EQ];
+ // code[i++] = (void *)12;
+ // code[i++] = (void *)11;
+ // code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[OP_EQI];
+ code[i++] = (void *)12;
+ code[i++] = (void *)11;
+ code[i++] = (void *)1;
+
+ code[i++] = CodeAddr[OP_JMPEQ0];
+ code[i++] = (void *)12;
+ // code[i++] = (void *)8;
+ code[i++] = (void *)4;
+
+ // code[i++] = CodeAddr[MKVAL];
+ // code[i++] = (void *)12;
+ // code[i++] = (void *)0;
+ // code[i++] = (void *)1;
+ //
+ // code[i++] = CodeAddr[PUSH];
+ // code[i++] = (void *)0;
+ // code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[PUSHI];
+ code[i++] = (void *)0;
+ code[i++] = (void *)INT2FIX(1);
+
+
+ code[i++] = CodeAddr[RET_FREE_L];
+
+
+
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)16;
+
+
+ // code[i++] = CodeAddr[MKVAL];
+ // code[i++] = (void *)14;
+ // code[i++] = (void *)0;
+ // code[i++] = (void *)1;
+ //
+ // code[i++] = CodeAddr[OP_SUB];
+ // code[i++] = (void *)12;
+ // code[i++] = (void *)11;
+ // code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[OP_SUBI];
+ code[i++] = (void *)12;
+ code[i++] = (void *)11;
+ code[i++] = (void *)1;
+
+
+ // code[i++] = CodeAddr[MKVAL];
+ // code[i++] = (void *)17;
+ // code[i++] = (void *)0;
+ // code[i++] = (void *)2;
+ //
+ // code[i++] = CodeAddr[OP_SUB];
+ // code[i++] = (void *)15;
+ // code[i++] = (void *)11;
+ // code[i++] = (void *)17;
+
+ code[i++] = CodeAddr[OP_SUBI];
+ code[i++] = (void *)13;
+ code[i++] = (void *)11;
+ code[i++] = (void *)2;
+
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)14;
+ code[i++] = (void *)10;
+ code[i++] = (void *)2;
+ code[i++] = (void *)16;
+ code[i++] = (void *)0;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)14;
+ code[i++] = (void *)20;
+ code[i++] = (void *)1;
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)14;
+ code[i++] = (void *)12;
+
+
+ // code[i++] = CodeAddr[REUSEAGENT];
+ // code[i++] = (void *)10;
+ // code[i++] = (void *)21;
+ // code[i++] = (void *)1;
+ // code[i++] = (void *)20;
+ //
+ // code[i++] = CodeAddr[PUSH];
+ // code[i++] = (void *)10;
+ // code[i++] = (void *)15;
+ //
+ // code[i++] = CodeAddr[RET];
+
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)16;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_ANNOTATE_R;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[LOOP];
+
+ code_size = i;
+
+ // PutsCodeN(&code[2], i-2);
+ // exit(1);
+ }
+#endif
+
+
+// --------------------------------------------------------------
+// For Fibonacci (naive)
+// #define HAND_FIB
+// --------------------------------------------------------------
+#ifdef HAND_FIB
+ if ((strcmp(IdTable_get_name(idL), "Fib") == 0) &&
+ (idR == ID_INT)) {
+
+ printf("Rule is optimised: %s >< %s.\n",
+ IdTable_get_name(idL),
+ IdTable_get_name(idR));
+
+ // PutsCodeN(&code[2], code_size-2);
+
+ int i=2;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)13;
+ code[i++] = (void *)VM_OFFSET_ANNOTATE_R;
+
+ code[i++] = CodeAddr[LOADI];
+ code[i++] = (void *)14;
+ code[i++] = (void *)0;
+
+ code[i++] = CodeAddr[OP_EQ];
+ code[i++] = (void *)12;
+ code[i++] = (void *)13;
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[OP_JMPEQ0];
+ code[i++] = (void *)12;
+ code[i++] = (void *)7;
+
+ code[i++] = CodeAddr[LOADI];
+ code[i++] = (void *)12;
+ code[i++] = (void *)0;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)0;
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[RET_FREE_L];
+
+
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)13;
+ code[i++] = (void *)VM_OFFSET_ANNOTATE_R;
+
+ code[i++] = CodeAddr[LOADI];
+ code[i++] = (void *)14;
+ code[i++] = (void *)1;
+
+ code[i++] = CodeAddr[OP_EQ];
+ code[i++] = (void *)12;
+ code[i++] = (void *)13;
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[OP_JMPEQ0];
+ code[i++] = (void *)12;
+ code[i++] = (void *)7;
+
+ code[i++] = CodeAddr[LOADI];
+ code[i++] = (void *)12;
+ code[i++] = (void *)1;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)0;
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[RET_FREE_L];
+
+
+
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)13;
+ code[i++] = (void *)21;
+ code[i++] = (void *)2;
+ code[i++] = (void *)0;
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)20;
+ code[i++] = (void *)1;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)16;
+ code[i++] = (void *)VM_OFFSET_ANNOTATE_R;
+
+ code[i++] = CodeAddr[LOADI];
+ code[i++] = (void *)17;
+ code[i++] = (void *)1;
+
+ code[i++] = CodeAddr[OP_SUB];
+ code[i++] = (void *)15;
+ code[i++] = (void *)16;
+ code[i++] = (void *)17;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)12;
+ code[i++] = (void *)15;
+
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)20;
+ code[i++] = (void *)VM_OFFSET_ANNOTATE_R;
+
+ code[i++] = CodeAddr[LOADI];
+ code[i++] = (void *)21;
+ code[i++] = (void *)2;
+
+ code[i++] = CodeAddr[OP_SUB];
+ code[i++] = (void *)19;
+ code[i++] = (void *)20;
+ code[i++] = (void *)21;
+
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_ANNOTATE_R;
+ code[i++] = (void *)19;
+
+ code[i++] = CodeAddr[LOOP];
+
+ code_size = i;
+
+ // PutsCodeN(&code[2], i-2);
+ // exit(1);
+ }
+#endif
+
+
+
+// --------------------------------------------------------------
+// For Fibonacci (naive)
+// #define HAND_FIB_INT
+// --------------------------------------------------------------
+#ifdef HAND_FIB_INT
+ if ((strcmp(IdTable_get_name(idL), "Fibi") == 0) &&
+ (strcmp(IdTable_get_name(idR), "Int") == 0)) {
+
+ printf("Rule is optimised: %s >< %s.\n",
+ IdTable_get_name(idL),
+ IdTable_get_name(idR));
+
+ // PutsCodeN(&code[2], code_size-2);
+
+ int i=2;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)13;
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+
+ code[i++] = CodeAddr[LOADI];
+ code[i++] = (void *)14;
+ code[i++] = (void *)0;
+
+ code[i++] = CodeAddr[OP_EQ];
+ code[i++] = (void *)12;
+ code[i++] = (void *)13;
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[OP_JMPEQ0];
+ code[i++] = (void *)12;
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[LOADI];
+ code[i++] = (void *)13;
+ code[i++] = (void *)0;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)(unsigned long)idR;
+ code[i++] = (void *)1;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)0;
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[RET_FREE_LR];
+
+
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)13;
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+
+ code[i++] = CodeAddr[LOADI];
+ code[i++] = (void *)14;
+ code[i++] = (void *)1;
+
+ code[i++] = CodeAddr[OP_EQ];
+ code[i++] = (void *)12;
+ code[i++] = (void *)13;
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[OP_JMPEQ0];
+ code[i++] = (void *)12;
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[LOADI];
+ code[i++] = (void *)13;
+ code[i++] = (void *)1;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)(unsigned long)idR;
+ code[i++] = (void *)1;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)0;
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[RET_FREE_LR];
+
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)20;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)13;
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+
+ code[i++] = CodeAddr[LOADI];
+ code[i++] = (void *)14;
+ code[i++] = (void *)1;
+
+ code[i++] = CodeAddr[OP_SUB];
+ code[i++] = (void *)12;
+ code[i++] = (void *)13;
+ code[i++] = (void *)14;
+
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)16;
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+
+ code[i++] = CodeAddr[LOADI];
+ code[i++] = (void *)17;
+ code[i++] = (void *)2;
+
+ code[i++] = CodeAddr[OP_SUB];
+ code[i++] = (void *)15;
+ code[i++] = (void *)16;
+ code[i++] = (void *)17;
+
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)19;
+ code[i++] = (void *)21;
+ code[i++] = (void *)2;
+ code[i++] = (void *)0;
+ code[i++] = (void *)20;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)18;
+ code[i++] = (void *)20;
+ code[i++] = (void *)1;
+ code[i++] = (void *)19;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)21;
+ code[i++] = (void *)9;
+ code[i++] = (void *)1;
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)18;
+ code[i++] = (void *)21;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)20;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+ code[i++] = (void *)15;
+
+ code[i++] = CodeAddr[LOOP];
+
+
+ code_size = i;
+
+ // PutsCodeN(&code[2], i-2);
+ // exit(1);
+ }
+#endif
+
+
+// --------------------------------------------------------------
+// For Fibonacci (tail call version)
+// #define HAND_FIB_TAIL
+// --------------------------------------------------------------
+#ifdef HAND_FIB_TAIL
+ if (strcmp(IdTable_get_name(idL), "Fibt") == 0) {
+ printf("Rule is optimised: %s >< %s.\n",
+ IdTable_get_name(idL),
+ IdTable_get_name(idR));
+
+ // PutsCodeN(&code[2], code_size-2);
+
+ int i=2;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)13;
+ code[i++] = (void *)VM_OFFSET_ANNOTATE_R;
+
+ code[i++] = CodeAddr[LOADI];
+ code[i++] = (void *)14;
+ code[i++] = (void *)0;
+
+ code[i++] = CodeAddr[OP_EQ];
+ code[i++] = (void *)12;
+ code[i++] = (void *)13;
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[OP_JMPEQ0];
+ code[i++] = (void *)12;
+ code[i++] = (void *)7;
+
+ code[i++] = CodeAddr[LOADI];
+ code[i++] = (void *)12;
+ code[i++] = (void *)1;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)0;
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[RET_FREE_L];
+
+
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)13;
+ code[i++] = (void *)VM_OFFSET_ANNOTATE_R;
+
+ code[i++] = CodeAddr[LOADI];
+ code[i++] = (void *)14;
+ code[i++] = (void *)1;
+
+ code[i++] = CodeAddr[OP_EQ];
+ code[i++] = (void *)12;
+ code[i++] = (void *)13;
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[OP_JMPEQ0];
+ code[i++] = (void *)12;
+ code[i++] = (void *)4;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)0;
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+
+ code[i++] = CodeAddr[RET_FREE_L];
+
+
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)14;
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)15;
+ code[i++] = (void *)VM_OFFSET_META_L(2);
+
+ code[i++] = CodeAddr[OP_ADD];
+ code[i++] = (void *)13;
+ code[i++] = (void *)14;
+ code[i++] = (void *)15;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)16;
+ code[i++] = (void *)VM_OFFSET_ANNOTATE_R;
+
+ code[i++] = CodeAddr[LOADI];
+ code[i++] = (void *)17;
+ code[i++] = (void *)1;
+
+ code[i++] = CodeAddr[OP_SUB];
+ code[i++] = (void *)18;
+ code[i++] = (void *)16;
+ code[i++] = (void *)17;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)19;
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(2);
+ code[i++] = (void *)19;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_ANNOTATE_R;
+ code[i++] = (void *)18;
+
+ code[i++] = CodeAddr[LOOP];
+
+ code_size = i;
+
+ // PutsCodeN(&code[2], i-2);
+ // exit(1);
+ }
+#endif
+
+
+
+// --------------------------------------------------------------
+// For Insersion Sort
+// #define HAND_I_CONS
+// #define HAND_IS_CONS
+// --------------------------------------------------------------
+#ifdef HAND_I_CONS
+ if ((strcmp(IdTable_get_name(idL), "I") == 0) &&
+ (strcmp(IdTable_get_name(idR), "Cons") == 0)) {
+
+ printf("Rule is optimised: %s >< %s.\n",
+ IdTable_get_name(idL),
+ IdTable_get_name(idR));
+
+ // PutsCodeN(&code[2], code_size-2);
+
+ int i=2;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)13;
+ code[i++] = (void *)1;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)14;
+ code[i++] = (void *)5;
+
+ code[i++] = CodeAddr[OP_LE];
+ code[i++] = (void *)12;
+ code[i++] = (void *)13;
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[OP_JMPEQ0];
+ code[i++] = (void *)12;
+ code[i++] = (void *)16;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)13;
+ code[i++] = (void *)8;
+ code[i++] = (void *)2;
+ code[i++] = (void *)5;
+ code[i++] = (void *)6;
+
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)8;
+ code[i++] = (void *)2;
+ code[i++] = (void *)1;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)0;
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[RET_FREE_LR];
+
+
+
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)8;
+ code[i++] = (void *)2;
+ code[i++] = (void *)5;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)0;
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[OP_JMPCNCT_CONS];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+ code[i++] = (void *)10;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)14;
+ code[i++] = (void *)21;
+ code[i++] = (void *)2;
+ code[i++] = (void *)13;
+ code[i++] = (void *)1;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)14;
+ code[i++] = (void *)6;
+
+ code[i++] = CodeAddr[RET_FREE_LR];
+
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[LOOP_RREC2];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+
+ code_size = i;
+
+ // PutsCodeN(&code[2], i-2);
+ // exit(1);
+ }
+#endif
+
+
+
+#ifdef HAND_IS_CONS
+ if ((strcmp(IdTable_get_name(idL), "IS") == 0) &&
+ (strcmp(IdTable_get_name(idR), "Cons") == 0)) {
+
+ printf("Rule is optimised: %s >< %s.\n",
+ IdTable_get_name(idL),
+ IdTable_get_name(idR));
+
+ // PutsCodeN(&code[2], code_size-2);
+
+ int i=2;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)13;
+ code[i++] = (void *)21;
+ code[i++] = (void *)2;
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+
+ code[i++] = CodeAddr[OP_JMPCNCT_CONS];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+ code[i++] = (void *)9;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)20;
+ code[i++] = (void *)1;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)12;
+ code[i++] = (void *)VM_OFFSET_META_R(1);;
+
+ code[i++] = CodeAddr[RET_FREE_LR];
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[LOOP_RREC2];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+
+ code_size = i;
+
+ // PutsCodeN(&code[2], i-2);
+ // exit(1);
+ }
+#endif
+
+
+// --------------------------------------------------------------
+// For Quick Sort
+// #define HAND_Apnd_CONS
+// #define HAND_Part_CONS
+// --------------------------------------------------------------
+
+#ifdef HAND_Apnd_CONS
+ if ((strcmp(IdTable_get_name(idL), "Apnd") == 0) &&
+ (idR == ID_CONS)) {
+
+ printf("Rule is optimised: %s >< %s.\n",
+ IdTable_get_name(idL),
+ IdTable_get_name(idR));
+
+ // PutsCodeN(&code[2], code_size-2);
+
+ int i=2;
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)8;
+ code[i++] = (void *)2;
+ code[i++] = (void *)5;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)0;
+ code[i++] = (void *)12;
+
+
+ code[i++] = CodeAddr[OP_JMPCNCT_CONS];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+ code[i++] = (void *)10;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)14;
+ code[i++] = (void *)(unsigned long)idL;
+ code[i++] = (void *)2;
+ code[i++] = (void *)13;
+ code[i++] = (void *)1;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)14;
+ code[i++] = (void *)6;
+
+ code[i++] = CodeAddr[RET_FREE_LR];
+
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[LOOP_RREC2];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+
+ code_size = i;
+
+ // PutsCodeN(&code[2], i-2);
+ // exit(1);
+ }
+#endif
+
+
+#ifdef HAND_Part_CONS
+ if ((strcmp(IdTable_get_name(idL), "Part") == 0) &&
+ (strcmp(IdTable_get_name(idR), "Cons") == 0)) {
+
+ printf("Rule is optimised: %s >< %s.\n",
+ IdTable_get_name(idL),
+ IdTable_get_name(idR));
+
+ // PutsCodeN(&code[2], code_size-2);
+
+ int i=2;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)13;
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)14;
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+
+ code[i++] = CodeAddr[OP_LT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)13;
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[OP_JMPEQ0];
+ code[i++] = (void *)12;
+ code[i++] = (void *)30;
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)8;
+ code[i++] = (void *)2;
+ code[i++] = (void *)5;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)VM_OFFSET_META_L(2);
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[OP_JMPCNCT_CONS];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+ code[i++] = (void *)11;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)14;
+ code[i++] = (void *)(unsigned long)idL;
+ code[i++] = (void *)3;
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)14;
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+
+ code[i++] = CodeAddr[RET_FREE_LR];
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(2);
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[LOOP_RREC2];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+
+
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)8;
+ code[i++] = (void *)2;
+ code[i++] = (void *)5;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[OP_JMPCNCT_CONS];
+ code[i++] = (void *)VM_OFFSET_META_L(2);
+ code[i++] = (void *)11;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)14;
+ code[i++] = (void *)(unsigned long)idL;
+ code[i++] = (void *)3;
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)13;
+ code[i++] = (void *)VM_OFFSET_META_L(2);
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)14;
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+
+ code[i++] = CodeAddr[RET_FREE_LR];
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[LOOP_RREC2];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+
+
+
+ code_size = i;
+
+ // PutsCodeN(&code[2], i-2);
+ // exit(1);
+ }
+#endif
+
+
+
+// --------------------------------------------------------------
+// For Merge Sort
+// #define HAND_Split_CONS
+// #define HAND_MergeCC_CONS
+// --------------------------------------------------------------
+
+#ifdef HAND_Split_CONS
+ if ((strcmp(IdTable_get_name(idL), "Split") == 0) &&
+ (strcmp(IdTable_get_name(idR), "Cons") == 0)) {
+
+ printf("Rule is optimised: %s >< %s.\n",
+ IdTable_get_name(idL),
+ IdTable_get_name(idR));
+
+ //PutsCodeN(&code[2], code_size-2);
+
+ int i=2;
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)8;
+ code[i++] = (void *)2;
+ code[i++] = (void *)5;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)0;
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[OP_JMPCNCT_CONS];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+ code[i++] = (void *)10;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)14;
+ code[i++] = (void *)22;
+ code[i++] = (void *)2;
+ code[i++] = (void *)1;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)14;
+ code[i++] = (void *)6;
+
+ code[i++] = CodeAddr[RET_FREE_LR];
+
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[LOOP_RREC2];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+
+ code_size = i;
+
+ // PutsCodeN(&code[2], i-2);
+ // exit(1);
+ }
+#endif
+
+
+ // #define HAND_MergeCC_CONS
+#ifdef HAND_MergeCC_CONS
+ if ((strcmp(IdTable_get_name(idL), "MergeCC") == 0) &&
+ (strcmp(IdTable_get_name(idR), "Cons") == 0)) {
+
+ printf("Rule is optimised: %s >< %s.\n",
+ IdTable_get_name(idL),
+ IdTable_get_name(idR));
+
+ PutsCodeN(&code[2], code_size-2);
+ exit(1);
+
+ int i=2;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)13;
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)14;
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+
+ code[i++] = CodeAddr[OP_LE];
+ code[i++] = (void *)12;
+ code[i++] = (void *)13;
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[OP_JMPEQ0];
+ code[i++] = (void *)12;
+ code[i++] = (void *)30;
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)8;
+ code[i++] = (void *)2;
+ code[i++] = (void *)5;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)0;
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[OP_JMPCNCT_CONS];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+ code[i++] = (void *)11;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)14;
+ code[i++] = (void *)(unsigned long)idL;
+ code[i++] = (void *)3;
+ code[i++] = (void *)13;
+ code[i++] = (void *)1;
+ code[i++] = (void *)2;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)14;
+ code[i++] = (void *)6;
+
+ code[i++] = CodeAddr[RET_FREE_LR];
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[LOOP_RREC2];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+
+
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)8;
+ code[i++] = (void *)2;
+ code[i++] = (void *)1;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)0;
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[OP_JMPCNCT_CONS];
+ code[i++] = (void *)VM_OFFSET_META_L(2);
+ code[i++] = (void *)11;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)14;
+ code[i++] = (void *)(unsigned long)idL;
+ code[i++] = (void *)3;
+ code[i++] = (void *)13;
+ code[i++] = (void *)5;
+ code[i++] = (void *)6;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)14;
+ code[i++] = (void *)2;
+
+ code[i++] = CodeAddr[RET_FREE_LR];
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)14;
+ code[i++] = (void *)VM_OFFSET_META_L(2); // ys
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(2);
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+
+ code[i++] = CodeAddr[LOOP_RREC2];
+ code[i++] = (void *)14;
+
+
+
+
+ code_size = i;
+
+ // PutsCodeN(&code[2], i-2);
+ // exit(1);
+ }
+#endif
+
+
+
+
+// --------------------------------------------------------------
+// For Bubble Sort
+// #define HAND_B_CONS
+// --------------------------------------------------------------
+
+#ifdef HAND_B_CONS
+ if ((strcmp(IdTable_get_name(idL), "B") == 0) &&
+ (strcmp(IdTable_get_name(idR), "Cons") == 0)) {
+
+ printf("Rule is optimised: %s >< %s.\n",
+ IdTable_get_name(idL),
+ IdTable_get_name(idR));
+
+ // PutsCodeN(&code[2], code_size-2);
+
+ int i=2;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)13;
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)14;
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+
+ code[i++] = CodeAddr[OP_LT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)13;
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[OP_JMPEQ0];
+ code[i++] = (void *)12;
+ code[i++] = (void *)32;
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)8;
+ code[i++] = (void *)2;
+ code[i++] = (void *)1;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)0;
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[OP_JMPCNCT_CONS];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+ code[i++] = (void *)10;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)14;
+ code[i++] = (void *)(unsigned long)idL;
+ code[i++] = (void *)2;
+ code[i++] = (void *)13;
+ code[i++] = (void *)5;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)14;
+ code[i++] = (void *)6;
+
+ code[i++] = CodeAddr[RET_FREE_LR];
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+
+ code[i++] = CodeAddr[LOOP_RREC2];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+
+
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)8;
+ code[i++] = (void *)2;
+ code[i++] = (void *)5;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)0;
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[OP_JMPCNCT_CONS];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+ code[i++] = (void *)10;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)14;
+ code[i++] = (void *)(unsigned long)idL;
+ code[i++] = (void *)2;
+ code[i++] = (void *)13;
+ code[i++] = (void *)1;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)14;
+ code[i++] = (void *)6;
+
+ code[i++] = CodeAddr[RET_FREE_LR];
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[LOOP_RREC2];
+ code[i++] = (void *)VM_OFFSET_META_R(1);
+
+
+
+
+ code_size = i;
+
+ // PutsCodeN(&code[2], i-2);
+ // exit(1);
+ }
+#endif
+
+
+
+
+// --------------------------------------------------------------
+// For Dup_SZ
+// #define HAND_DUP_S
+// --------------------------------------------------------------
+#ifdef HAND_DUP_S
+ if ((strcmp(IdTable_get_name(idL), "Dup") == 0) &&
+ (strcmp(IdTable_get_name(idR), "S") == 0)) {
+
+ printf("Rule is optimised: %s >< %s.\n",
+ IdTable_get_name(idL),
+ IdTable_get_name(idR));
+ // PutsCodeN(&code[2], code_size-2);
+
+ int i=2;
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)15;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)(unsigned long)idR;
+ code[i++] = (void *)1;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)14;
+ code[i++] = (void *)(unsigned long)idR;
+ code[i++] = (void *)1;
+ code[i++] = (void *)15;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+ code[i++] = (void *)14;
+
+
+ code[i++] = CodeAddr[OP_JMPCNCT];
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+ code[i++] = (void *)(unsigned long)idR;
+ code[i++] = (void *)10;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)16;
+ code[i++] = (void *)(unsigned long)idL;
+ code[i++] = (void *)2;
+ code[i++] = (void *)13;
+ code[i++] = (void *)15;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)16;
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+
+ code[i++] = CodeAddr[RET_FREE_LR];
+
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+ code[i++] = (void *)15;
+
+ code[i++] = CodeAddr[LOOP_RREC1];
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+ //code[i++] = (void *)1;
+
+ code_size = i;
+
+ //PutsCodeN(&code[2], i-2);
+ // exit(1);
+ }
+#endif
+
+
+
+// --------------------------------------------------------------
+// For ADD_SZ
+//#define HAND_ADD_S
+// --------------------------------------------------------------
+#ifdef HAND_ADD_S
+ if ((strcmp(IdTable_get_name(idL), "AddSZ") == 0) &&
+ (strcmp(IdTable_get_name(idR), "S") == 0)) {
+
+ printf("Rule is optimised: %s >< %s.\n",
+ IdTable_get_name(idL),
+ IdTable_get_name(idR));
+ //PutsCodeN(&code[2], code_size-2);
+
+ int i=2;
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)(unsigned long)idR;
+ code[i++] = (void *)1;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)VM_OFFSET_META_L(0);;
+ code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[OP_JMPCNCT];
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+ code[i++] = (void *)(unsigned long)idR;
+ code[i++] = (void *)10;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)14;
+ code[i++] = (void *)(unsigned long)idL;
+ code[i++] = (void *)2;
+ code[i++] = (void *)13;
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)14;
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+
+ code[i++] = CodeAddr[RET_FREE_LR];
+
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[LOOP_RREC1];
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+
+ code_size = i;
+ // PutsCodeN(&code[2], i-2);
+ // exit(1);
+ }
+#endif
+
+
+// --------------------------------------------------------------
+// For ACK_Sx
+// #define HAND_ACK_S
+// --------------------------------------------------------------
+#ifdef HAND_ACK_S
+ if ((strcmp(IdTable_get_name(idL), "Ack_Sx") == 0) &&
+ (strcmp(IdTable_get_name(idR), "S") == 0)) {
+
+ printf("Rule is optimised: %s >< %s.\n",
+ IdTable_get_name(idL),
+ IdTable_get_name(idR));
+ // PutsCodeN(&code[2], code_size-2);
+
+ int i=2;
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)15;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)13;
+ code[i++] = (void *)20; // Ack
+ code[i++] = (void *)2;
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)12;
+ code[i++] = (void *)24; // Dup
+ code[i++] = (void *)2;
+ code[i++] = (void *)13;
+ code[i++] = (void *)15;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)12;
+ code[i++] = (void *)1;
+
+ code[i++] = CodeAddr[OP_JMPCNCT];
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+ code[i++] = (void *)(unsigned long)idR;
+ code[i++] = (void *)10;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)16;
+ code[i++] = (void *)(unsigned long)idL;
+ code[i++] = (void *)2;
+ code[i++] = (void *)14;
+ code[i++] = (void *)15;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)16;
+ code[i++] = (void *)5;
+
+ code[i++] = CodeAddr[RET_FREE_LR];
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(1);
+ code[i++] = (void *)15;
+
+ code[i++] = CodeAddr[LOOP_RREC1];
+ code[i++] = (void *)VM_OFFSET_META_R(0);
+
+ code_size = i;
+ // PutsCodeN(&code[2], i-2);
+ // exit(1);
+ }
+#endif
+
+
+
+
+ // #define HAND_FIB2
+#ifdef HAND_FIB2
+ PutsCodeN(&code[2], code_size-2);
+ int i=2;
+ // code[i++] = CodeAddr[MKVAL];
+ // code[i++] = (void *)14;
+ // code[i++] = (void *)0;
+ // code[i++] = (void *)0;
+ //
+ // code[i++] = CodeAddr[OP_EQ];
+ // code[i++] = (void *)12;
+ // code[i++] = (void *)11;
+ // code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[OP_EQI];
+ //code[i++] = (void *)11; // ここで 11(OFFSET_R)を壊してしまうと他で影響あり
+ code[i++] = (void *)12;
+ code[i++] = (void *)11;
+ code[i++] = (void *)0;
+
+ code[i++] = CodeAddr[OP_JMPEQ0];
+ code[i++] = (void *)12;
+ // code[i++] = (void *)8;
+ code[i++] = (void *)4;
+
+ // code[i++] = CodeAddr[MKVAL];
+ // code[i++] = (void *)12;
+ // code[i++] = (void *)0;
+ // code[i++] = (void *)1;
+ //
+ // code[i++] = CodeAddr[PUSH];
+ // code[i++] = (void *)0;
+ // code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[PUSHI];
+ code[i++] = (void *)0;
+ code[i++] = (void *)INT2FIX(1);
+
+ code[i++] = CodeAddr[RET_FREE_L];
+
+
+
+
+ // code[i++] = CodeAddr[MKVAL];
+ // code[i++] = (void *)14;
+ // code[i++] = (void *)0;
+ // code[i++] = (void *)1;
+ //
+ // code[i++] = CodeAddr[OP_EQ];
+ // code[i++] = (void *)12;
+ // code[i++] = (void *)11;
+ // code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[OP_EQI];
+ code[i++] = (void *)12;
+ code[i++] = (void *)11;
+ code[i++] = (void *)1;
+
+ code[i++] = CodeAddr[OP_JMPEQ0];
+ code[i++] = (void *)12;
+ // code[i++] = (void *)8;
+ code[i++] = (void *)4;
+
+ // code[i++] = CodeAddr[MKVAL];
+ // code[i++] = (void *)12;
+ // code[i++] = (void *)0;
+ // code[i++] = (void *)1;
+ //
+ // code[i++] = CodeAddr[PUSH];
+ // code[i++] = (void *)0;
+ // code[i++] = (void *)12;
+
+ code[i++] = CodeAddr[PUSHI];
+ code[i++] = (void *)0;
+ code[i++] = (void *)INT2FIX(1);
+
+
+ code[i++] = CodeAddr[RET_FREE_L];
+
+
+
+ // Fib(Add(n2,r))~b, Fib(n2)~c
+ // -------------------------------
+ // Fib(n2)~c
+ code[i++] = CodeAddr[MKNAME];
+ code[i++] = (void *)16;
+
+
+ code[i++] = CodeAddr[OP_SUBI];
+ code[i++] = (void *)12;
+ code[i++] = (void *)11;
+ code[i++] = (void *)2;
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)13;
+ code[i++] = (void *)20;
+ code[i++] = (void *)1;
+ code[i++] = (void *)16;
+
+ code[i++] = CodeAddr[PUSH];
+ code[i++] = (void *)13;
+ code[i++] = (void *)12;
+
+
+ // -------------------------------
+ // Fib(Add(n2,r))~b
+ code[i++] = CodeAddr[OP_SUBI];
+ code[i++] = (void *)13;
+ code[i++] = (void *)11;
+ code[i++] = (void *)1;
+
+
+ code[i++] = CodeAddr[MKAGENT];
+ code[i++] = (void *)14;
+ code[i++] = (void *)10;
+ code[i++] = (void *)2;
+ code[i++] = (void *)16;
+ code[i++] = (void *)0;
+
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_META_L(0);
+ code[i++] = (void *)14;
+
+ code[i++] = CodeAddr[LOAD];
+ code[i++] = (void *)VM_OFFSET_ANNOTATE_R;
+ code[i++] = (void *)13;
+
+ code[i++] = CodeAddr[LOOP];
+
+ code_size = i;
+ PutsCodeN(&code[2], i-2);
+ // exit(1);
+#endif
+
+
+
+ //puts_ast(ruleL); printf("><");
+ //puts_ast(ruleR); puts("");
+
+ // Record the rule code for idR >< idL
+ RuleTable_record(idL, idR, code_size, code);
+
+ if (idL != idR) {
+ // Delete the rule code for idR >< idL
+ // because we need only the rule idL >< idR.
+ RuleTable_delete(idR, idL);
+
+ }
+}
+
+
+void *getRuleCode(VALUE heap_syml, VALUE heap_symr, int *result) {
+ int syml = AGENT(heap_syml)->basic.id;
+ int symr = AGENT(heap_symr)->basic.id;
+
+ //RuleList *add;
+
+ if( RuleTable[syml] == NULL ) { /* もしハッシュテーブルが空ならば */
+ *result=0;
+ return NULL;
+ }
+
+ /* 線形探査が必要 */
+ RuleList *at = RuleTable[syml]; /* 先頭をセット */
+ while( at != NULL ) {
+ if( at->sym == symr) { /* すでにあれば... */
+
+ if (at->available == 0) {
+ *result=0;
+ return NULL;
+
+ } else {
+ *result=1;
+ return at->code;
+ }
+ }
+ at = at->next; /* 次のチェーンを辿る */
+ }
+ /* key がなかった → 先頭に追加 */
+ *result=0;
+ return NULL;
+
+}
+
+
+static inline
+void getRuleCodeInt(VALUE heap_syml, void ***code) {
+ int syml = AGENT(heap_syml)->basic.id;
+
+ //RuleList *add;
+
+ if( RuleTable[syml] == NULL ) { /* もしハッシュテーブルが空ならば */
+ return;
+ }
+
+ /* 線形探査が必要 */
+ RuleList *at = RuleTable[syml]; /* 先頭をセット */
+ while( at != NULL ) {
+ if( at->sym == ID_INT) { /* すでにあれば... */
+
+ if (at->available == 0) {
+ return;
+ } else {
+ *code = at->code;
+ return;
+ }
+ }
+ at = at->next; /* 次のチェーンを辿る */
+ }
+ /* key がなかった → 先頭に追加 */
+ return;
+}
+
+
+#ifdef COUNT_CNCT
+int Count_cnct = 0;
+int Count_cnct_true = 0;
+int Count_cnct_indirect_op = 0;
+#endif
+
+
+//void *ExecCode(int arg, VirtualMachine *vm, void** code) {
+void *ExecCode(int mode, VirtualMachine *restrict vm, void *restrict *code) {
+
+ //http://magazine.rubyist.net/?0008-YarvManiacs
+ static const void *table[] = {
+ &&E_PUSH, &&E_PUSHI, &&E_MKNAME, &&E_MKGNAME, &&E_MKAGENT,
+ &&E_REUSEAGENT, &&E_MYPUSH,
+ &&E_RET, &&E_RET_FREE_LR, &&E_RET_FREE_L, &&E_RET_FREE_R,
+ &&E_LOOP, &&E_LOOP_RREC, &&E_LOOP_RREC1, &&E_LOOP_RREC2,
+ &&E_LOADI, &&E_LOAD, &&E_LOADP,
+ &&E_ADD, &&E_SUB, &&E_SUBI, &&E_MUL, &&E_DIV, &&E_MOD,
+ &&E_LT, &&E_LE, &&E_EQ, &&E_EQI, &&E_NE,
+ &&E_JMPEQ0, &&E_JMPCNCT_CONS, &&E_JMPCNCT, &&E_JMP,
+ &&E_UNM, &&E_RAND,
+ &&E_CNCTGN, &&E_SUBSTGN,
+ &&E_NOP,
+ };
+
+ // table 作成用(通常(コード実行時)は arg=1 で呼び出す)
+ if (mode == 0) {
+ return table;
+ }
+
+ //freeAgent(vm->L); freeAgent(vm->R);
+ //freeAgent(vm->agentReg[VM_OFFSET_META_L(MAX_PORT-1)]);
+ //freeAgent(vm->agentReg[VM_OFFSET_META_R(MAX_PORT-1)]);
+
+ int arity, i, pc=0;
+ VALUE a1;
+
+ goto *code[0];
+
+
+ E_MKNAME:
+ // puts("mkname");
+ vm->agentReg[(unsigned long)code[pc+1]] = makeName(vm);
+ pc +=2;
+ goto *code[pc];
+
+ E_MKGNAME:
+ // puts("mkgname");
+
+ //a1 = makeGlobalName(vm, (char *)code[pc+1]);
+
+ a1 = NameTable_get_heap((char *)code[pc+1]);
+ if (a1 == (VALUE)NULL) {
+ i = IdTable_new_gnameid();
+ a1 = makeName(vm);
+ BASIC(a1)->id = i; // GlobalName の ID をセット
+ NameTable_set_heap_id((char *)code[pc+1], a1, i);
+ }
+
+ vm->agentReg[(unsigned long)code[pc+2]] = a1;
+ pc +=3;
+ goto *code[pc];
+
+
+ E_MKAGENT:
+ // puts("mkagent");
+ arity = (unsigned long)code[pc+3];
+ a1 = makeAgent(vm, (unsigned long)code[pc+2]);
+ vm->agentReg[(unsigned long)code[pc+1]] = a1;
+ {
+ volatile VALUE *a1port = AGENT(a1)->port;
+
+ pc +=4;
+
+ for(i=0; i<arity; i++) {
+ // AGENT(a1)->port[i] = vm->agentReg[(unsigned long)code[pc]];
+ a1port[i] = vm->agentReg[(unsigned long)code[pc++]];
+ }
+
+ }
+ goto *code[pc];
+
+ E_REUSEAGENT: // reuseagent target id arity
+ // puts("reuseagent");
+ a1 = vm->agentReg[(unsigned long)code[pc+1]];
+ AGENT(a1)->basic.id = (unsigned long)code[pc+2];
+ {
+ volatile VALUE *a1port = AGENT(a1)->port;
+ arity = (unsigned long)code[pc+3];
+ pc +=4;
+ for(i=0; i<arity; i++) {
+ // AGENT(a1)->port[i] = vm->agentReg[(unsigned long)code[pc]];
+ a1port[i] = vm->agentReg[(unsigned long)code[pc]];
+ pc++;
+ }
+ }
+ goto *code[pc];
+
+
+
+ /*
+ ===TODO===
+ 2021/9/18
+ a2->t であるところに a1->a2 が与えられても a2->t, a1->a2 のままにしてある。
+ a2 がここで解放できればメモリ利用が助かるのでは?
+ 仮に助からないとしても、グローバル環境で与えられたネットの場合には
+ 単純に eval_equation へ持ち込んだ方が、indirection を生成しなくて済むのでは?
+
+ ==>
+ DONE 21 September 2021
+ 誤差程度しか変わらない。
+
+ */
+#ifndef THREAD
+#define PUSH(vm, a1, a2) \
+ if ((!IS_FIXNUM(a1)) && (IS_NAMEID(BASIC(a1)->id)) && \
+ (NAME(a1)->port == (VALUE)NULL)) { \
+ NAME(a1)->port = a2; \
+ } else if ((!IS_FIXNUM(a2)) && (IS_NAMEID(BASIC(a2)->id)) && \
+ (NAME(a2)->port == (VALUE)NULL)) { \
+ NAME(a2)->port = a1; \
+ } else { \
+ VM_PushEQStack(vm, a1, a2); \
+ }
+#else
+#define PUSH(vm, a1, a2) \
+ if ((!IS_FIXNUM(a1)) && (IS_NAMEID(BASIC(a1)->id)) && \
+ (NAME(a1)->port == (VALUE)NULL)) { \
+ if (!(__sync_bool_compare_and_swap(&(NAME(a1)->port), NULL, a2))) { \
+ if (MaxThreadNum - ActiveThreadNum > 0) { \
+ PushEQStack(NAME(a1)->port,a2); \
+ freeName(a1); \
+ } else { \
+ VM_PushEQStack(vm, NAME(a1)->port, a2); \
+ freeName(a1); \
+ } \
+ } \
+ } else if ((!IS_FIXNUM(a2)) && (IS_NAMEID(BASIC(a2)->id)) && \
+ (NAME(a2)->port == (VALUE)NULL)) { \
+ if (!(__sync_bool_compare_and_swap(&(NAME(a2)->port), NULL, a1))) { \
+ if (MaxThreadNum - ActiveThreadNum > 0) { \
+ PushEQStack(a1,NAME(a2)->port); \
+ freeName(a2); \
+ } else { \
+ VM_PushEQStack(vm, a1,NAME(a2)->port); \
+ freeName(a2); \
+ } \
+ } \
+ } else { \
+ if (MaxThreadNum - ActiveThreadNum > 0) { \
+ PushEQStack(a1,a2); \
+ } else { \
+ VM_PushEQStack(vm, a1,a2); \
+ } \
+ }
+#endif
+
+
+
+ E_PUSH:
+ // puts("push");
+ PUSH(vm, vm->agentReg[(unsigned long)code[pc+1]], vm->agentReg[(unsigned long)code[pc+2]]);
+ pc +=3;
+ goto *code[pc];
+
+
+ E_PUSHI:
+ // puts("pushi reg int");
+ PUSH(vm, vm->agentReg[(unsigned long)code[pc+1]], (unsigned long)code[pc+2]);
+ pc +=3;
+ goto *code[pc];
+
+
+
+#ifndef THREAD
+#define MYPUSH(vm, a1, a2) \
+ if ((!IS_FIXNUM(a1)) && (IS_NAMEID(BASIC(a1)->id)) && \
+ (NAME(a1)->port == (VALUE)NULL)) { \
+ NAME(a1)->port = a2; \
+ } else if ((!IS_FIXNUM(a2)) && (BASIC(a2)->id == ID_NAME) && \
+ (NAME(a2)->port == (VALUE)NULL)) { \
+ NAME(a2)->port = a1; \
+ } else { \
+ VM_PushEQStack(vm, a1,a2); \
+ }
+#else
+#define MYPUSH(vm, a1, a2) \
+ if ((!IS_FIXNUM(a1)) && (IS_NAMEID(BASIC(a1)->id)) && \
+ (NAME(a1)->port == (VALUE)NULL)) { \
+ if (!(__sync_bool_compare_and_swap(&(NAME(a1)->port), NULL, a2))) { \
+ VM_PushEQStack(vm, a1,a2); \
+ } \
+ } else if ((!IS_FIXNUM(a2)) && (IS_NAMEID(BASIC(a2)->id)) && \
+ (NAME(a2)->port == (VALUE)NULL)) { \
+ if (!(__sync_bool_compare_and_swap(&(NAME(a2)->port), NULL, a1))) { \
+ VM_PushEQStack(vm, a1,a2); \
+ } \
+ } else { \
+ VM_PushEQStack(vm, a1,a2); \
+ }
+#endif
+
+
+
+
+ E_MYPUSH:
+ // puts("mypush");
+ // VM_PushEQStack(vm, vm->agentReg[(unsigned long)code[pc+1]], vm->agentReg[(unsigned long)code[pc+2]]);
+ MYPUSH(vm, vm->agentReg[(unsigned long)code[pc+1]], vm->agentReg[(unsigned long)code[pc+2]]);
+ pc +=3;
+ goto *code[pc];
+
+
+
+ E_LOADI:
+ // puts("loadi reg num");
+ //a1 = makeVal_int(vm, (unsigned long)code[pc+3]);
+ a1 = INT2FIX((long)code[pc+2]);
+ vm->agentReg[(unsigned long)code[pc+1]] = a1;
+ pc +=3;
+ goto *code[pc];
+
+
+
+
+ E_RET:
+ // puts("ret");
+ return NULL;
+
+ E_RET_FREE_LR:
+ // puts("ret");
+ freeAgent(vm->agentReg[VM_OFFSET_ANNOTATE_L]);
+ freeAgent(vm->agentReg[VM_OFFSET_ANNOTATE_R]);
+ //
+
+ // freeAgent(vm->L);
+ // freeAgent(vm->R);
+ return NULL;
+
+ E_RET_FREE_L:
+ // puts("ret");
+ freeAgent(vm->agentReg[VM_OFFSET_ANNOTATE_L]);
+ // freeAgent(vm->L);
+ return NULL;
+
+ E_RET_FREE_R:
+ // puts("ret");
+ freeAgent(vm->agentReg[VM_OFFSET_ANNOTATE_R]);
+ // freeAgent(vm->R);
+ return NULL;
+
+
+ E_LOOP:
+ // puts("loop");
+ pc = 0;
+ goto *code[0];
+
+
+ E_LOOP_RREC:
+ // puts("looprrec reg ar");
+ freeAgent(vm->agentReg[VM_OFFSET_ANNOTATE_R]);
+
+ a1 = vm->agentReg[(unsigned long)code[pc+1]];
+ for (int i=0; i<(unsigned long)code[pc+2]; i++) {
+ vm->agentReg[VM_OFFSET_META_R(i)] = AGENT(a1)->port[i];
+ }
+
+ vm->agentReg[VM_OFFSET_ANNOTATE_R] = a1;
+
+ pc = 0;
+ goto *code[0];
+
+
+ E_LOOP_RREC1:
+ // puts("looprrec reg ar");
+ freeAgent(vm->agentReg[VM_OFFSET_ANNOTATE_R]);
+
+ a1 = vm->agentReg[(unsigned long)code[pc+1]];
+
+ vm->agentReg[VM_OFFSET_META_R(0)] = AGENT(a1)->port[0];
+
+ vm->agentReg[VM_OFFSET_ANNOTATE_R] = a1;
+
+ pc = 0;
+ goto *code[0];
+
+
+ E_LOOP_RREC2:
+ // puts("looprrec reg ar");
+ freeAgent(vm->agentReg[VM_OFFSET_ANNOTATE_R]);
+
+ a1 = vm->agentReg[(unsigned long)code[pc+1]];
+
+ vm->agentReg[VM_OFFSET_META_R(0)] = AGENT(a1)->port[0];
+ vm->agentReg[VM_OFFSET_META_R(1)] = AGENT(a1)->port[1];
+
+ vm->agentReg[VM_OFFSET_ANNOTATE_R] = a1;
+
+ pc = 0;
+ goto *code[0];
+
+
+
+
+
+ E_LOAD:
+ // puts("load reg reg");
+ //a1 = makeVal_int(vm, (unsigned long)code[pc+3]);
+ vm->agentReg[(unsigned long)code[pc+1]] =
+ vm->agentReg[(unsigned long)code[pc+2]];
+ pc +=3;
+ goto *code[pc];
+
+ E_LOADP:
+ // puts("loadp reg reg port");
+ vm->agentReg[(unsigned long)code[pc+1]] =
+ AGENT(vm->agentReg[(unsigned long)code[pc+2]])->port[vm->agentReg[(unsigned long)code[pc+3]]];
+ pc +=4;
+ goto *code[pc];
+
+
+ E_ADD:
+ // puts("ADD reg reg reg");
+ vm->agentReg[(unsigned long)code[pc+1]] =
+ INT2FIX(FIX2INT(vm->agentReg[(unsigned long)code[pc+2]])+FIX2INT(vm->agentReg[(unsigned long)code[pc+3]]));
+ pc +=4;
+ goto *code[pc];
+
+ E_SUB:
+ // puts("SUB reg reg reg");
+ vm->agentReg[(unsigned long)code[pc+1]] =
+ INT2FIX(FIX2INT(vm->agentReg[(unsigned long)code[pc+2]])-
+ FIX2INT(vm->agentReg[(unsigned long)code[pc+3]]));
+ pc +=4;
+ goto *code[pc];
+
+ E_SUBI:
+ //puts("SUBI reg reg int");exit(1);
+ vm->agentReg[(unsigned long)code[pc+1]] =
+ INT2FIX(FIX2INT(vm->agentReg[(unsigned long)code[pc+2]])-
+ (unsigned long)code[pc+3]);
+ pc +=4;
+ goto *code[pc];
+
+
+ E_MUL:
+ // puts("SUB reg reg reg");
+ vm->agentReg[(unsigned long)code[pc+1]] =
+ INT2FIX(FIX2INT(vm->agentReg[(unsigned long)code[pc+2]])*
+ FIX2INT(vm->agentReg[(unsigned long)code[pc+3]]));
+ pc +=4;
+ goto *code[pc];
+
+ E_DIV:
+ // puts("SUB reg reg reg");
+ vm->agentReg[(unsigned long)code[pc+1]] =
+ INT2FIX(FIX2INT(vm->agentReg[(unsigned long)code[pc+2]])/
+ FIX2INT(vm->agentReg[(unsigned long)code[pc+3]]));
+ pc +=4;
+ goto *code[pc];
+
+ E_MOD:
+ // puts("SUB reg reg reg");
+ vm->agentReg[(unsigned long)code[pc+1]] =
+ INT2FIX(FIX2INT(vm->agentReg[(unsigned long)code[pc+2]])%
+ FIX2INT(vm->agentReg[(unsigned long)code[pc+3]]));
+ pc +=4;
+ goto *code[pc];
+
+ E_LT:
+ // puts("SUB reg reg reg");
+ if (FIX2INT(vm->agentReg[(unsigned long)code[pc+2]]) <
+ FIX2INT(vm->agentReg[(unsigned long)code[pc+3]])) {
+ vm->agentReg[(unsigned long)code[pc+1]] = INT2FIX(1);
+ } else {
+ vm->agentReg[(unsigned long)code[pc+1]] = INT2FIX(0);
+ }
+ pc +=4;
+ goto *code[pc];
+
+ E_LE:
+ // puts("SUB reg reg reg");
+ if (FIX2INT(vm->agentReg[(unsigned long)code[pc+2]]) <=
+ FIX2INT(vm->agentReg[(unsigned long)code[pc+3]])) {
+ vm->agentReg[(unsigned long)code[pc+1]] = INT2FIX(1);
+ } else {
+ vm->agentReg[(unsigned long)code[pc+1]] = INT2FIX(0);
+ }
+ pc +=4;
+ goto *code[pc];
+
+ E_EQ:
+ // puts("SUB reg reg reg");
+ if (vm->agentReg[(unsigned long)code[pc+2]] ==
+ vm->agentReg[(unsigned long)code[pc+3]]) {
+ vm->agentReg[(unsigned long)code[pc+1]] = INT2FIX(1);
+ } else {
+ vm->agentReg[(unsigned long)code[pc+1]] = INT2FIX(0);
+ }
+ pc +=4;
+ goto *code[pc];
+
+
+ E_EQI:
+ // puts("SUB reg reg int");
+ if (FIX2INT(vm->agentReg[(unsigned long)code[pc+2]]) ==
+ (unsigned long)code[pc+3]) {
+ vm->agentReg[(unsigned long)code[pc+1]] = INT2FIX(1);
+ } else {
+ vm->agentReg[(unsigned long)code[pc+1]] = INT2FIX(0);
+ }
+
+ pc +=4;
+ goto *code[pc];
+
+
+
+ E_NE:
+ // puts("SUB reg reg reg");
+ if (vm->agentReg[(unsigned long)code[pc+2]] !=
+ vm->agentReg[(unsigned long)code[pc+3]]) {
+ vm->agentReg[(unsigned long)code[pc+1]] = INT2FIX(1);
+ } else {
+ vm->agentReg[(unsigned long)code[pc+1]] = INT2FIX(0);
+ }
+ pc +=4;
+ goto *code[pc];
+
+ E_JMPEQ0:
+ // puts("JMPEQ0 reg pc");
+ // pc is a relative address, not absolute one!
+ if (!FIX2INT(vm->agentReg[(unsigned long)code[pc+1]])) {
+ pc += (unsigned long)code[pc+2];
+ }
+ pc +=3;
+ goto *code[pc];
+
+
+ E_JMPCNCT_CONS:
+ // puts("JMPCNCT_CONS reg pc");
+#ifdef COUNT_CNCT
+ Count_cnct++;
+#endif
+
+ a1 = vm->agentReg[(unsigned long)code[pc+1]];
+ if (IS_FIXNUM(a1)) {
+ pc +=3;
+ goto *code[pc];
+ }
+
+ while (IS_NAMEID(BASIC(a1)->id)) {
+
+ if (NAME(a1)->port == (VALUE)NULL) {
+ pc +=3;
+ goto *code[pc];
+ }
+
+#ifdef COUNT_CNCT
+ Count_cnct_indirect_op++;
+#endif
+ VALUE a2 = NAME(a1)->port;
+ freeName(a1);
+ a1 = a2;
+ vm->agentReg[(unsigned long)code[pc+1]] = a2;
+ }
+
+ if (BASIC(a1)->id == ID_CONS) {
+#ifdef COUNT_CNCT
+ Count_cnct_true++;
+#endif
+
+ pc += (unsigned long)code[pc+2];
+ pc +=3;
+ goto *code[pc];
+ }
+
+ pc +=3;
+ goto *code[pc];
+
+
+ E_JMPCNCT:
+ // puts("JMPCNCT reg id pc");
+#ifdef COUNT_CNCT
+ Count_cnct++;
+#endif
+
+ a1 = vm->agentReg[(unsigned long)code[pc+1]];
+ if (IS_FIXNUM(a1)) {
+ pc +=4;
+ goto *code[pc];
+ }
+
+ while (IS_NAMEID(BASIC(a1)->id)) {
+
+ if (NAME(a1)->port == (VALUE)NULL) {
+ pc +=4;
+ goto *code[pc];
+ }
+
+#ifdef COUNT_CNCT
+ Count_cnct_indirect_op++;
+#endif
+ VALUE a2 = NAME(a1)->port;
+ freeName(a1);
+ a1 = a2;
+ vm->agentReg[(unsigned long)code[pc+1]] = a2;
+ }
+
+ if (BASIC(a1)->id == (unsigned long)code[pc+2]) {
+#ifdef COUNT_CNCT
+ Count_cnct_true++;
+#endif
+ pc += (unsigned long)code[pc+3];
+ pc +=4;
+ goto *code[pc];
+ }
+
+ pc +=4;
+ goto *code[pc];
+
+
+
+ E_JMP:
+ // puts("JMP pc");
+ pc += vm->agentReg[(unsigned long)code[pc+1]];
+ pc +=2;
+ goto *code[pc];
+
+
+
+ E_UNM:
+ // puts("UNM reg reg");
+ vm->agentReg[(unsigned long)code[pc+1]] =
+ INT2FIX(-1 * FIX2INT(vm->agentReg[(unsigned long)code[pc+2]]));
+ pc +=3;
+ goto *code[pc];
+
+ E_RAND:
+ // puts("RAND reg reg");
+ vm->agentReg[(unsigned long)code[pc+1]] =
+ INT2FIX(rand()%FIX2INT(vm->agentReg[(unsigned long)code[pc+2]]));
+ pc +=3;
+ goto *code[pc];
+
+
+ E_CNCTGN:
+ // puts("CNCTGN reg reg");
+ // "x"~s, "x"->t ==> push(s,t), free("x") where "x" is a global name.
+ {
+ VALUE x = vm->agentReg[(unsigned long)code[pc+1]];
+ a1 = NAME(x)->port;
+ freeName(x);
+ PUSH(vm, vm->agentReg[(unsigned long)code[pc+2]], a1);
+ }
+ pc +=3;
+ goto *code[pc];
+
+
+
+ E_SUBSTGN:
+ // puts("SUBSTGN reg reg");
+ // "x"~s, t->u("x") ==> t->u(s), free("x") where "x" is a global name.
+ {
+ VALUE x = vm->agentReg[(unsigned long)code[pc+1]];
+ global_replace_keynode_in_another_term(x,vm->agentReg[(unsigned long)code[pc+2]]);
+ freeName(x);
+ }
+ pc +=3;
+ goto *code[pc];
+
+
+
+
+ // extended codes should be ended here.
+
+
+ E_NOP:
+ pc++;
+ goto *code[pc];
+
+
+
+}
+
+
+
+
+
+void errprintf(int tid) {
+ printf("%2d:", tid);
+}
+
+void errputs(char *s, int tid) {
+ /*
+ errprintf(tid);
+ puts(s);
+ */
+}
+
+
+/******************************************
+ Mark and Sweep
+******************************************/
+#ifndef THREAD
+
+/* 31bit目が 1 ならば、Garbage Collection の Mark&Sweep にて、
+ Mark されたことを意味する*/
+#define FLAG_MARKED 0x01 << 30
+#define IS_FLAG_MARKED(a) ((a) & FLAG_MARKED)
+#define SET_FLAG_MARKED(a) ((a) = ((a) | FLAG_MARKED))
+#define TOGGLE_FLAG_MARKED(a) ((a) = ((a) ^ FLAG_MARKED))
+
+
+void markHeapRec(VALUE ptr) {
+ loop:
+ if ((ptr == (VALUE)NULL) || (IS_FIXNUM(ptr))) {
+ return;
+ } else if (IS_NAMEID(BASIC(ptr)->id)) {
+ if (ptr == ShowNameHeap) return;
+
+ SET_FLAG_MARKED(BASIC(ptr)->id);
+ if (NAME(ptr)->port != (VALUE)NULL) {
+ ptr = NAME(ptr)->port;
+ goto loop;
+ }
+ } else {
+ if (BASIC(ptr)->id == ID_CONS) {
+ if (IS_FIXNUM(AGENT(ptr)->port[0])) {
+ SET_FLAG_MARKED(BASIC(ptr)->id);
+ ptr = AGENT(ptr)->port[1];
+ goto loop;
+ }
+ }
+
+ int arity = IdTable_get_arity(BASIC(ptr)->id);
+ SET_FLAG_MARKED(BASIC(ptr)->id);
+ if (arity == 1) {
+ ptr = AGENT(ptr)->port[0];
+ goto loop;
+ } else { // it contains the case that i==0.
+ int i;
+ for(i=0; i<arity; i++) {
+ markHeapRec(AGENT(ptr)->port[i]);
+ }
+ }
+ }
+}
+
+
+void mark_name_port0(VALUE ptr) {
+ if (ptr != (VALUE)NULL) {
+
+ SET_FLAG_MARKED(BASIC(ptr)->id);
+ if (NAME(ptr)->port != (VALUE)NULL) {
+ ShowNameHeap=ptr;
+ markHeapRec(NAME(ptr)->port);
+ ShowNameHeap=(VALUE)NULL;
+ }
+ }
+}
+
+
+void mark_allHash() {
+ int i;
+ NameList *at;
+
+ for (i=0; i<NAME_HASHSIZE; i++) {
+ at = NameHashTable[i];
+ while (at != NULL) {
+ if (at->heap != (VALUE)NULL) {
+ if (IS_NAMEID(BASIC(at->heap)->id)) {
+ mark_name_port0(at->heap);
+ }
+ }
+ at = at->next;
+ }
+ }
+}
+
+void sweepAgentHeap(Heap *hp) {
+ int i;
+ for (i=0; i < hp->size; i++) {
+ if (!IS_FLAG_MARKED( ((Agent *)hp->heap)[i].basic.id)) {
+ SET_FLAG_AVAIL( ((Agent *)hp->heap)[i].basic.id);
+ } else {
+ TOGGLE_FLAG_MARKED( ((Agent *)hp->heap)[i].basic.id);
+ }
+ }
+}
+void sweepNameHeap(Heap *hp) {
+ int i;
+ for (i=0; i < hp->size; i++) {
+ if (!IS_FLAG_MARKED( ((Name *)hp->heap)[i].basic.id)) {
+ SET_FLAG_AVAIL( ((Name *)hp->heap)[i].basic.id);
+ } else {
+ TOGGLE_FLAG_MARKED( ((Name *)hp->heap)[i].basic.id);
+ }
+ }
+}
+
+
+
+void mark_and_sweep() {
+ //puts("mark_and_sweep is called."); sleep(10);
+
+ mark_allHash();
+ sweepAgentHeap(&(VM.agentHeap));
+ sweepNameHeap(&VM.nameHeap);
+ VM.nextPtr_eqStack = -1;
+}
+
+#endif
+
+
+
+/***********************************
+ exec coequation
+**********************************/
+//#define DEBUG
+
+
+//#define CAS_USLEEP 4
+#define CAS_USLEEP 100
+
+
+// static inline にしないほうが速いようだ
+static inline
+void eval_equation(VirtualMachine *restrict vm, VALUE a1, VALUE a2) {
+
+loop:
+ // if (BASIC(a2)->id >= START_ID_OF_AGENT) {
+
+ // a2 が fixnum
+ if (IS_FIXNUM(a2)) {
+loop_a2IsFixnum:
+ if (IS_FIXNUM(a1)) {
+ printf("Runtime ERROR: "); puts_term(a1); printf("~"); puts_term(a2);
+ printf("\nInteger %d >< %d can not be used as an active pair\n",
+ FIX2INT(a1), FIX2INT(a2));
+#ifndef THREAD
+ mark_and_sweep();
+ return;
+#else
+ printf("Retrieve is not supported in the multi-threaded version.\n");
+ exit(-1);
+#endif
+ }
+
+ // a1 が agent
+ if (IS_AGENTID(BASIC(a1)->id)) {
+
+ void **code = NULL;
+
+ getRuleCodeInt(a1, &code);
+
+ if (code == NULL) {
+
+ // built-in
+ switch (BASIC(a1)->id) {
+ case ID_ADD:
+ {
+ BASIC(a1)->id = ID_ADD2;
+ VALUE a1port1 = AGENT(a1)->port[1];
+ AGENT(a1)->port[1] = a2;
+ a2 = a1port1;
+ goto loop;
+ }
+ case ID_ADD2:
+ {
+ int m = FIX2INT(AGENT(a1)->port[1]);
+ int n = FIX2INT(a2);
+ a2 = INT2FIX(m+n);
+ VALUE a1port0 = AGENT(a1)->port[0];
+ freeAgent(a1);
+ a1 = a1port0;
+ goto loop;
+ }
+ }
+
+
+ printf("Runtime Error: There is no interaction rule for the following pair:\n ");
+ puts_term(a1);
+ printf("~");
+ puts_term(a2);
+ puts("");
+
+ if (yyin != stdin) exit(-1);
+
+#ifndef THREAD
+ mark_and_sweep();
+ return;
+#else
+ printf("Retrieve is not supported in the multi-threaded version.\n");
+ exit(-1);
+#endif
+ }
+
+ int i;
+ unsigned long arity;
+ arity = (unsigned long)code[0];
+
+ switch(arity) {
+ case 0:
+ break;
+
+ case 1:
+ vm->agentReg[VM_OFFSET_META_L(0)] = AGENT(a1)->port[0];
+ break;
+
+ case 2:
+ vm->agentReg[VM_OFFSET_META_L(0)] = AGENT(a1)->port[0];
+ vm->agentReg[VM_OFFSET_META_L(1)] = AGENT(a1)->port[1];
+ break;
+
+ case 3:
+ vm->agentReg[VM_OFFSET_META_L(0)] = AGENT(a1)->port[0];
+ vm->agentReg[VM_OFFSET_META_L(1)] = AGENT(a1)->port[1];
+ vm->agentReg[VM_OFFSET_META_L(2)] = AGENT(a1)->port[2];
+ break;
+
+ default:
+ for (i=0; i<arity; i++) {
+ vm->agentReg[VM_OFFSET_META_L(i)] = AGENT(a1)->port[i];
+ }
+ }
+
+ vm->agentReg[VM_OFFSET_ANNOTATE_L] = a1;
+ vm->agentReg[VM_OFFSET_ANNOTATE_R] = a2;
+
+#ifdef COUNT_INTERACTION
+ vm->NumberOfInteraction++;
+#endif
+ ExecCode(1, vm, &code[2]);
+ return;
+
+ } else {
+ // a1 は name、a2 は fixint
+ if (NAME(a1)->port != (VALUE)NULL) {
+ VALUE a1p0;
+ a1p0=NAME(a1)->port;
+ freeName(a1);
+ a1=a1p0;
+ goto loop_a2IsFixnum;
+ } else {
+#ifndef THREAD
+ NAME(a1)->port=a2;
+#else
+ if (!(__sync_bool_compare_and_swap(&(NAME(a1)->port), NULL, a2))) {
+ // usleep(CAS_USLEEP);
+ // goto loop;
+ VALUE a1p0;
+ a1p0=NAME(a1)->port;
+ freeName(a1);
+ a1=a1p0;
+ goto loop_a2IsFixnum;
+
+ }
+#endif
+ }
+
+ }
+ return;
+ }
+
+
+
+ // a2 が agent
+ if (IS_AGENTID(BASIC(a2)->id)) {
+loop_a2IsAgent:
+
+ // a1 が fixnum
+ if (IS_FIXNUM(a1)) {
+ // fixnum >< agent
+
+ void **code = NULL;
+
+ getRuleCodeInt(a2, &code);
+
+ if (code == NULL) {
+
+
+ // built-in
+ VALUE tmp = a1;
+ a1 = a2;
+ a2 = tmp;
+ switch (BASIC(a1)->id) {
+
+ case ID_ADD:
+ {
+ BASIC(a1)->id = ID_ADD2;
+ VALUE a1port1 = AGENT(a1)->port[1];
+ AGENT(a1)->port[1] = a2;
+ a2 = a1port1;
+ goto loop;
+ }
+ case ID_ADD2:
+ {
+ int m = FIX2INT(AGENT(a1)->port[1]);
+ int n = FIX2INT(a2);
+ a2 = INT2FIX(m+n);
+ VALUE a1port0 = AGENT(a1)->port[0];
+ freeAgent(a1);
+ a1 = a1port0;
+ goto loop;
+ }
+
+ }
+
+
+
+
+ printf("Runtime Error: There is no interaction rule for the following pair:\n ");
+ puts_term(a1);
+ printf("~");
+ puts_term(a2);
+ puts("");
+
+ if (yyin != stdin) exit(-1);
+
+#ifndef THREAD
+ mark_and_sweep();
+ return;
+#else
+ printf("Retrieve is not supported in the multi-threaded version.\n");
+ exit(-1);
+#endif
+ }
+
+ int i;
+ unsigned long arity;
+ arity = (unsigned long)code[0];
+
+ switch(arity) {
+ case 0:
+ break;
+
+ case 1:
+ vm->agentReg[VM_OFFSET_META_R(0)] = AGENT(a2)->port[0];
+ break;
+
+ case 2:
+ vm->agentReg[VM_OFFSET_META_R(0)] = AGENT(a2)->port[0];
+ vm->agentReg[VM_OFFSET_META_R(1)] = AGENT(a2)->port[1];
+ break;
+
+ case 3:
+ vm->agentReg[VM_OFFSET_META_R(0)] = AGENT(a2)->port[0];
+ vm->agentReg[VM_OFFSET_META_R(1)] = AGENT(a2)->port[1];
+ vm->agentReg[VM_OFFSET_META_R(2)] = AGENT(a2)->port[2];
+ break;
+
+ default:
+ for (i=0; i<arity; i++) {
+ vm->agentReg[VM_OFFSET_META_R(i)] = AGENT(a2)->port[i];
+ }
+ }
+
+ vm->agentReg[VM_OFFSET_ANNOTATE_L] = a2;
+ vm->agentReg[VM_OFFSET_ANNOTATE_R] = a1;
+
+#ifdef COUNT_INTERACTION
+ vm->NumberOfInteraction++;
+#endif
+ ExecCode(1, vm, &code[2]);
+ return;
+ }
+
+ // a1 が agent
+ if (IS_AGENTID(BASIC(a1)->id)) {
+ /* for the case of Agent - Agent */
+
+#ifdef DEBUG
+ puts("");
+ puts("--------------------------------------");
+ puts("execActive");
+ puts("--------------------------------------");
+ puts_term(a1);puts("");
+ printf("><");puts("");
+ puts_term(a2);puts("");
+ puts("--------------------------------------");
+ puts("");
+#endif
+
+
+ if (BASIC(a1)->id < BASIC(a2)->id) {
+ VALUE tmp;
+ tmp=a1;
+ a1=a2;
+ a2=tmp;
+ }
+
+ int result;
+ void **code;
+
+ code = getRuleCode(a1, a2, &result);
+
+ if (result == 0) {
+
+
+ if (BASIC(a2)->id <= ID_CONS) {
+
+ // built-in
+ switch (BASIC(a1)->id) {
+
+ case ID_TUPLE0:
+ if (BASIC(a2)->id == ID_TUPLE0) {
+ // [] ~ [] --> nothing
+ freeAgent(a1);
+ freeAgent(a2);
+ return;
+ }
+
+ break; // end ID_TUPLE0
+
+
+ case ID_TUPLE2:
+ if (BASIC(a2)->id == ID_TUPLE2) {
+ // (x1,x2) ~ (y1,y2) --> x1~y1, x2~y2
+ VALUE a1p1 = AGENT(a1)->port[1];
+ VALUE a2p1 = AGENT(a2)->port[1];
+ PUSH(vm, a1p1, a2p1);
+
+ freeAgent(a1);
+ freeAgent(a2);
+ a1 = AGENT(a1)->port[0];
+ a2 = AGENT(a2)->port[0];
+ goto loop;
+ }
+
+ break; // end ID_TUPLE2
+
+ case ID_TUPLE3:
+ if (BASIC(a2)->id == ID_TUPLE3) {
+ // (x1,x2,x3) ~ (y1,y2,y3) --> x1~y1, x2~y2, x3~y3
+ PUSH(vm, AGENT(a1)->port[2], AGENT(a2)->port[2]);
+ PUSH(vm, AGENT(a1)->port[1], AGENT(a2)->port[1]);
+
+ freeAgent(a1);
+ freeAgent(a2);
+ a1 = AGENT(a1)->port[0];
+ a2 = AGENT(a2)->port[0];
+ goto loop;
+ }
+
+ break; // end ID_TUPLE2
+
+
+ case ID_TUPLE4:
+ if (BASIC(a2)->id == ID_TUPLE4) {
+ // (x1,x2,x3) ~ (y1,y2,y3) --> x1~y1, x2~y2, x3~y3
+ PUSH(vm, AGENT(a1)->port[3], AGENT(a2)->port[3]);
+ PUSH(vm, AGENT(a1)->port[2], AGENT(a2)->port[2]);
+ PUSH(vm, AGENT(a1)->port[1], AGENT(a2)->port[1]);
+
+ freeAgent(a1);
+ freeAgent(a2);
+ a1 = AGENT(a1)->port[0];
+ a2 = AGENT(a2)->port[0];
+ goto loop;
+ }
+
+ break; // end ID_TUPLE2
+
+
+ case ID_TUPLE5:
+ if (BASIC(a2)->id == ID_TUPLE5) {
+ // (x1,x2,x3) ~ (y1,y2,y3) --> x1~y1, x2~y2, x3~y3
+ PUSH(vm, AGENT(a1)->port[4], AGENT(a2)->port[4]);
+ PUSH(vm, AGENT(a1)->port[3], AGENT(a2)->port[3]);
+ PUSH(vm, AGENT(a1)->port[2], AGENT(a2)->port[2]);
+ PUSH(vm, AGENT(a1)->port[1], AGENT(a2)->port[1]);
+
+ freeAgent(a1);
+ freeAgent(a2);
+ a1 = AGENT(a1)->port[0];
+ a2 = AGENT(a2)->port[0];
+ goto loop;
+ }
+
+ break; // end ID_TUPLE2
+
+
+ case ID_NIL:
+ if (BASIC(a2)->id == ID_NIL) {
+ // [] ~ [] --> nothing
+ freeAgent(a1);
+ freeAgent(a2);
+ return;
+ }
+
+ break; // end ID_NIL
+
+
+ case ID_CONS:
+ if (BASIC(a2)->id == ID_CONS) {
+ // a:b ~ c:d --> a~c, b~d
+ VALUE a1p1 = AGENT(a1)->port[1];
+ VALUE a2p1 = AGENT(a2)->port[1];
+ PUSH(vm, a1p1, a2p1);
+
+ freeAgent(a1);
+ freeAgent(a2);
+ a1 = AGENT(a1)->port[0];
+ a2 = AGENT(a2)->port[0];
+ goto loop;
+ }
+
+ break; // end ID_CONS
+
+
+
+ // built-in funcAgent for lists and tuples
+ case ID_APPEND:
+ switch (BASIC(a2)->id) {
+ case ID_NIL:
+ {
+ // App(r,a) >< [] => r~a;
+ VALUE a1p0 = AGENT(a1)->port[0];
+ VALUE a1p1 = AGENT(a1)->port[1];
+ freeAgent(a1);
+ freeAgent(a2);
+ a1=a1p0;
+ a2=a1p1;
+ goto loop;
+ }
+
+ case ID_CONS:
+ {
+ // App(r,a) >< [x|xs] => r~(*R)[x|w], (*L)App(w,a)~xs;
+ VALUE a1p0 = AGENT(a1)->port[0];
+ VALUE a2p1 = AGENT(a2)->port[1];
+ VALUE w = makeName(vm);
+
+ AGENT(a2)->port[1] = w;
+ PUSH(vm, a1p0, a2);
+ //VM_PushEQStack(vm, a1p1, a2);
+
+ AGENT(a1)->port[0] = w;
+ a2 = a2p1;
+ goto loop;
+ }
+ }
+
+ break; // end ID_APPEND
+
+
+
+ }
+ }
+
+
+
+ printf("Runtime Error: There is no interaction rule for the following pair:\n ");
+ puts_term(a1);
+ printf("~");
+ puts_term(a2);
+ puts("");
+
+ if (yyin != stdin) exit(-1);
+
+#ifndef THREAD
+ mark_and_sweep();
+ return;
+#else
+ printf("Retrieve is not supported in the multi-threaded version.\n");
+ exit(-1);
+#endif
+ }
+ // normal op
+
+
+ // PutsCode(at);
+ // return;
+
+
+ int i;
+ unsigned long arity;
+ arity = (unsigned long)code[0];
+
+ switch(arity) {
+ case 0:
+ break;
+
+ case 1:
+ vm->agentReg[VM_OFFSET_META_L(0)] = AGENT(a1)->port[0];
+ break;
+
+ case 2:
+ vm->agentReg[VM_OFFSET_META_L(0)] = AGENT(a1)->port[0];
+ vm->agentReg[VM_OFFSET_META_L(1)] = AGENT(a1)->port[1];
+ break;
+
+ case 3:
+ vm->agentReg[VM_OFFSET_META_L(0)] = AGENT(a1)->port[0];
+ vm->agentReg[VM_OFFSET_META_L(1)] = AGENT(a1)->port[1];
+ vm->agentReg[VM_OFFSET_META_L(2)] = AGENT(a1)->port[2];
+ break;
+
+ default:
+ for (i=0; i<arity; i++) {
+ vm->agentReg[VM_OFFSET_META_L(i)] = AGENT(a1)->port[i];
+ }
+ }
+
+
+ arity = (unsigned long)code[1];
+ switch(arity) {
+ case 0:
+ break;
+
+ case 1:
+ vm->agentReg[VM_OFFSET_META_R(0)] = AGENT(a2)->port[0];
+ break;
+
+ case 2:
+ vm->agentReg[VM_OFFSET_META_R(0)] = AGENT(a2)->port[0];
+ vm->agentReg[VM_OFFSET_META_R(1)] = AGENT(a2)->port[1];
+ break;
+
+ case 3:
+ vm->agentReg[VM_OFFSET_META_R(0)] = AGENT(a2)->port[0];
+ vm->agentReg[VM_OFFSET_META_R(1)] = AGENT(a2)->port[1];
+ vm->agentReg[VM_OFFSET_META_R(2)] = AGENT(a2)->port[2];
+ break;
+
+ default:
+ for (i=0; i<arity; i++) {
+ vm->agentReg[VM_OFFSET_META_R(i)] = AGENT(a2)->port[i];
+ }
+ }
+
+
+ vm->agentReg[VM_OFFSET_ANNOTATE_L] = a1;
+ vm->agentReg[VM_OFFSET_ANNOTATE_R] = a2;
+
+ //freeAgent(a1);
+ //freeAgent(a2);
+
+ // vm->L = a1;
+ // vm->R = a2;
+
+#ifdef COUNT_INTERACTION
+ vm->NumberOfInteraction++;
+#endif
+ ExecCode(1, vm, &code[2]);
+
+
+
+ return;
+ } else {
+
+ // a1 が name
+ // a2 is agent
+ if (NAME(a1)->port != (VALUE)NULL) {
+
+ VALUE a1p0;
+ a1p0=NAME(a1)->port;
+ freeName(a1);
+ a1=a1p0;
+ goto loop_a2IsAgent;
+ } else {
+#ifndef THREAD
+ NAME(a1)->port=a2;
+#else
+ if (!(__sync_bool_compare_and_swap(&(NAME(a1)->port), NULL, a2))) {
+ VALUE a1p0;
+ a1p0=NAME(a1)->port;
+ freeName(a1);
+ a1=a1p0;
+ goto loop_a2IsAgent;
+
+ //usleep(CAS_USLEEP);
+ // // goto loop_a2IsAgent;
+ // goto loop;
+ }
+#endif
+
+ }
+ }
+ } else {
+ // a2 が name: a1 はわからない
+ if (NAME(a2)->port != (VALUE)NULL) {
+ VALUE a2p0;
+ a2p0=NAME(a2)->port;
+ freeName(a2);
+ a2=a2p0;
+ goto loop;
+ } else {
+#ifndef THREAD
+ NAME(a2)->port=a1;
+#else
+ if (!(__sync_bool_compare_and_swap(&(NAME(a2)->port), NULL, a1))) {
+ VALUE a2p0;
+ a2p0=NAME(a2)->port;
+ freeName(a2);
+ a2=a2p0;
+ goto loop;
+
+
+ // usleep(CAS_USLEEP);;
+ // goto loop;
+ }
+#endif
+ }
+ }
+}
+
+
+
+
+
+void Init_VM(VirtualMachine *vm,
+ unsigned int agentBufferSize, unsigned int eqStackSize) {
+ VM_InitBuffer(vm, agentBufferSize);
+ VM_EQStackInit(vm, eqStackSize);
+}
+
+
+
+#ifndef THREAD
+
+
+#define WHNF_UNUSED_STACK_SIZE 100
+typedef struct {
+ // EQStack
+ EQ *eqs;
+ int eqs_index;
+ int size;
+ int enabled; // 0: not Enabled, 1: Enabled.
+} WHNF_Info;
+WHNF_Info WHNFinfo;
+
+void Init_WHNFinfo() {
+ WHNFinfo.eqs_index = 0;
+ WHNFinfo.size = WHNF_UNUSED_STACK_SIZE;
+ WHNFinfo.enabled = 0; // not Enabled
+
+ WHNFinfo.eqs = malloc(sizeof(EQ) * WHNF_UNUSED_STACK_SIZE);
+ if (WHNFinfo.eqs == NULL) {
+ printf("WHNFinfo.eqs: Malloc error\n");
+ exit(-1);
+ }
+}
+
+void WHNFInfo_push_equation(VALUE t1, VALUE t2) {
+ WHNFinfo.eqs[WHNFinfo.eqs_index].l = t1;
+ WHNFinfo.eqs[WHNFinfo.eqs_index].r = t2;
+ WHNFinfo.eqs_index++;
+ if (WHNFinfo.eqs_index >= WHNF_UNUSED_STACK_SIZE) {
+ printf("ERROR: WHNFinfo.eqs stack becomes full.\n");
+ exit(-1);
+ }
+}
+
+
+void WHNF_execution_loop() {
+ VALUE t1, t2;
+ while (PopEQStack(&VM, &t1, &t2)) {
+
+ if ((NameTable_ckech_if_term_has_gname(t1) == 1) ||
+ (NameTable_ckech_if_term_has_gname(t2) == 1)) {
+
+ eval_equation(&VM, t1, t2);
+
+ } else {
+ WHNFInfo_push_equation(t1, t2);
+ }
+ }
+
+}
+
+
+void select_kind_of_push(Ast *ast, int p1, int p2) {
+ char *sym = ast->left->sym;
+ VALUE aheap = NameTable_get_heap(sym);
+
+ if (aheap != (VALUE)NULL) {
+ // aheap already exists as a global
+
+ // aheap is connected with something such as aheap->t
+ // ==> p2 should be conncected with t, so CNCTGN(p1,p2)
+ if (NAME(aheap)->port != (VALUE)NULL) {
+ EnvAddCodeCNCTGN((void *)(unsigned long)p1,
+ (void *)(unsigned long)p2);
+ } else {
+ // aheap occurs somewhere, so it should be replaced by SUBSTGN(p1,p2)
+ EnvAddCodeSUBSTGN((void *)(unsigned long)p1,
+ (void *)(unsigned long)p2);
+ }
+ } else {
+ EnvAddCodePUSH((void *)(unsigned long)p1, (void *)(unsigned long)p2);
+ }
+
+
+}
+
+
+int exec(Ast *at) {
+ // Ast at: (AST_BODY stmlist aplist)
+
+ unsigned long long t, time;
+
+ void* code[MAX_CODE_SIZE];
+
+
+ start_timer(&t);
+
+ CmEnv_clear_all();
+
+ // for `where' expression
+ if (!CompileStmListFromAst(at->left)) return 0;
+
+ // aplist
+ at = at->right;
+
+ // for aplists
+ // puts(""); puts_ast(at); puts("");
+ RewriteEQListOnAST(at);
+ // puts(""); puts_ast(at); puts("");
+ // exit(1);
+
+
+ // Syntax error check
+ {
+ Ast *tmp_at=at;
+ while (tmp_at != NULL) {
+ if ((check_invalid_occurrence(tmp_at->left->left))
+ && (check_invalid_occurrence(tmp_at->left->right))) {
+ // both ara invalid
+ if (yyin != stdin) exit(-1);
+ return 0;
+ }
+
+ tmp_at = ast_getTail(tmp_at);
+ }
+ }
+
+
+ while (at != NULL) {
+ int p1,p2;
+ Ast *left, *right;
+
+ left = at->left->left;
+ right = at->left->right;
+ p1 = CompileTermFromAst(left, -1);
+ p2 = CompileTermFromAst(right, -1);
+
+
+ /*
+ EnvAddCodePUSH((void *)(unsigned long)p1, (void *)(unsigned long)p2);
+ at = ast_getTail(at);
+ */
+
+ if (left->id == AST_NAME) {
+ select_kind_of_push(left, p1, p2);
+
+ } else if (right->id == AST_NAME) {
+ select_kind_of_push(right, p2, p1);
+
+ } else {
+ EnvAddCodePUSH((void *)(unsigned long)p1, (void *)(unsigned long)p2);
+ }
+
+ at = ast_getTail(at);
+
+
+
+ }
+ EnvAddCode(CodeAddr[RET]);
+
+ // checking whether names occur more than twice
+ if (!CmEnv_check_name_reference_times()) {
+ if (yyin != stdin) exit(-1);
+ return 0;
+ }
+
+ // Generate codes from CmEnv, where '0' means index of the `code',
+ // so here codes are stored from code[0].
+ CmEnv_generate_code_with_nameinfo(code,0);
+
+
+ //PutsCode(code); exit(1);
+
+#ifdef COUNT_MKAGENT
+ NumberOfMkAgent=0;
+#endif
+
+
+ // WHNF: Unused equations are stacked to be execution targets again.
+ if (WHNFinfo.enabled) {
+ for (int i=0; i < WHNFinfo.eqs_index ; i++) {
+ MYPUSH(&VM, WHNFinfo.eqs[i].l, WHNFinfo.eqs[i].r);
+ }
+ WHNFinfo.eqs_index = 0;
+ }
+
+
+ ExecCode(1, &VM, code);
+
+
+#ifdef COUNT_INTERACTION
+ VM_ClearInteractionNum(&VM);
+#endif
+
+
+
+ // EXECUTION LOOP
+
+ if (!WHNFinfo.enabled) {
+ // no-stategy execution
+
+ VALUE t1, t2;
+ while (PopEQStack(&VM, &t1, &t2)) {
+ eval_equation(&VM, t1, t2);
+ }
+
+ } else {
+ // WHNF stragety
+ WHNF_execution_loop();
+ }
+
+
+ time=stop_timer(&t);
+#ifdef COUNT_INTERACTION
+ printf("(%d interactions, %.2f sec)\n", VM_GetInteractionNum(&VM),
+ (double)(time)/1000000);
+#else
+ printf("(%.2f sec)\n",
+ (double)(time)/1000000);
+#endif
+
+#ifdef COUNT_MKAGENT
+ printf("(%d mkAgent calls)\n", NumberOfMkAgent);
+#endif
+
+
+#ifdef CELL_USE_VERBOSE
+ printf("(%lu agents and %lu names cells are used.)\n",
+ VM.agentHeap.size - getNumOfAvailAgentHeap(&VM.agentHeap),
+ VM.nameHeap.size - getNumOfAvailNameHeap(&VM.nameHeap));
+#endif
+
+#ifdef COUNT_CNCT
+ printf("JMP_CNCT:%d true:%d ratio:%.2f%%\n",
+ Count_cnct, Count_cnct_true, Count_cnct_true*100.0/Count_cnct);
+ printf(" ind_op:%d ratio(ind/JMP_CNCT):%.2f%%\n",
+ Count_cnct_indirect_op, Count_cnct_indirect_op*100.0/Count_cnct);
+#endif
+
+ return 1;
+}
+
+#else
+
+int CpuNum=1; // CPU 数の設定用(sysconf(_SC_NPROSSEORS_CONF)) を使って求める)
+
+static pthread_cond_t ActiveThread_all_sleep = PTHREAD_COND_INITIALIZER;
+static pthread_t *Threads;
+static VirtualMachine **VMs;
+
+void *tpool_thread(void *arg) {
+
+ VirtualMachine *vm;
+
+ vm = (VirtualMachine *)arg;
+
+#ifdef CPU_ZERO
+ cpu_set_t mask;
+ CPU_ZERO(&mask);
+ CPU_SET((vm->id)%CpuNum, &mask);
+ if(sched_setaffinity(0, sizeof(mask), &mask)==-1) {
+ printf("WARNING:");
+ printf("CPUNUM=%d, id=%d, cpuid=%d\n", CpuNum, vm->id, (vm->id)%CpuNum);
+ }
+ //printf("CPUNUM=%d, id=%d, cpuid=%d\n", CpuNum, vm->id, (vm->id)%CpuNum);
+#endif
+
+ while (1) {
+
+ VALUE t1, t2;
+ while (!PopEQStack(vm, &t1, &t2)) {
+ pthread_mutex_lock(&Sleep_lock);
+ ActiveThreadNum = ActiveThreadNum - 1;
+
+ if (ActiveThreadNum == 0) {
+ pthread_mutex_lock(&AllSleep_lock);
+ pthread_cond_signal(&ActiveThread_all_sleep);
+ pthread_mutex_unlock(&AllSleep_lock);
+ }
+
+ // printf("[Thread %d is slept.]\n", vm->id);
+ pthread_cond_wait(&EQStack_not_empty, &Sleep_lock);
+ ActiveThreadNum = ActiveThreadNum + 1;
+ pthread_mutex_unlock(&Sleep_lock);
+ // printf("[Thread %d is waked up.]\n", vm->id);
+
+
+ }
+
+
+ eval_equation(vm, t1, t2);
+
+
+ }
+
+ return (void *)NULL;
+}
+
+void tpool_init(unsigned int agentBufferSize, unsigned int eqstack_size) {
+ int i, status;
+ // static int id[100];
+
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
+
+
+ CpuNum = sysconf(_SC_NPROCESSORS_CONF);
+
+ pthread_setconcurrency(CpuNum);
+
+
+ Threads = (pthread_t *)malloc(sizeof(pthread_t)*MaxThreadNum);
+ if (Threads == NULL) {
+ printf("the thread pool could not be created.");
+ exit(-1);
+ }
+ ActiveThreadNum = MaxThreadNum;
+
+ VMs = malloc(sizeof(VirtualMachine*)*MaxThreadNum);
+ if (VMs == NULL) {
+ printf("the thread pool could not be created.");
+ exit(-1);
+ }
+
+
+ for (i=0; i<MaxThreadNum; i++) {
+ VMs[i] = malloc(sizeof(VirtualMachine));
+ VMs[i]->id = i;
+ Init_VM(VMs[i], agentBufferSize, eqstack_size);
+ status = pthread_create( &Threads[i],
+ &attr,
+ tpool_thread,
+ (void *)VMs[i]);
+ if (status!=0) {
+ printf("ERROR: Thread%d could not be created.", i);
+ exit(-1);
+ }
+ }
+}
+
+void tpool_destroy() {
+ int i;
+ for (i=0; i<MaxThreadNum; i++) {
+ pthread_join( Threads[i],
+ NULL);
+ }
+ free(Threads);
+
+
+}
+
+
+int exec(Ast *at) {
+ // Ast at: (AST_BODY stmlist aplist)
+
+ unsigned long long t, time;
+ int i;
+
+#ifdef COUNT_INTERACTION
+ for (i=0; i<MaxThreadNum; i++) {
+ VM_ClearInteractionNum(VMs[i]);
+ }
+#endif
+
+ void* code[MAX_CODE_SIZE];
+ int eqsnum = 0;
+
+ start_timer(&t);
+ CmEnv_clear_all();
+
+ // for `where' expression
+ if (!CompileStmListFromAst(at->left)) return 0;
+
+ // aplist
+ at = at->right;
+
+ RewriteEQListOnAST(at);
+
+ // Syntax error check
+ {
+ Ast *tmp_at=at;
+ while (tmp_at != NULL) {
+ if ((check_invalid_occurrence(tmp_at->left->left))
+ && (check_invalid_occurrence(tmp_at->left->right))) {
+ // both ara invalid
+ if (yyin != stdin) exit(-1);
+ return 0;
+ }
+
+ tmp_at = ast_getTail(tmp_at);
+ }
+ }
+
+
+ while (at!=NULL) {
+ int p1,p2;
+ p1 = CompileTermFromAst(at->left->left, -1);
+ p2 = CompileTermFromAst(at->left->right, -1);
+ EnvAddCodeMYPUSH((void *)(unsigned long)p1, (void *)(unsigned long)p2);
+ eqsnum++; //分散用
+ at = ast_getTail(at);
+ }
+ EnvAddCode(CodeAddr[RET]);
+
+ // checking whether names occur more than twice
+ if (!CmEnv_check_name_reference_times()) {
+ return 0;
+ }
+ // '0' means that generated codes are stored in code[0,...].
+ CmEnv_generate_code_with_nameinfo(code,0);
+
+ //PutsCode(code); exit(1);
+
+ ExecCode(1, VMs[0], code);
+
+ //分散用
+ {
+ int each_eqsnum = eqsnum / MaxThreadNum;
+ if (each_eqsnum == 0) each_eqsnum = 1;
+ for (i=1; i<MaxThreadNum; i++) {
+ VALUE t1, t2;
+ int j;
+ for (j=0; j<each_eqsnum; j++) {
+ if (!VM_PopEQStack(VMs[0], &t1, &t2)) goto endloop;
+ VM_PushEQStack(VMs[i], t1, t2);
+ }
+ }
+ }
+ endloop:
+
+
+ pthread_mutex_lock(&Sleep_lock);
+ pthread_cond_broadcast(&EQStack_not_empty);
+ pthread_mutex_unlock(&Sleep_lock);
+
+ usleep(100000);
+
+
+ if (ActiveThreadNum != 0) {
+ pthread_mutex_lock(&AllSleep_lock);
+ pthread_cond_wait(&ActiveThread_all_sleep, &AllSleep_lock);
+ pthread_mutex_unlock(&AllSleep_lock);
+ }
+
+ time=stop_timer(&t);
+
+#ifdef COUNT_INTERACTION
+ unsigned long total=0;
+ for (i=0; i<MaxThreadNum; i++) {
+ total += VM_GetInteractionNum(VMs[i]);
+ }
+ printf("(%lu interactions by %d threads, %.2f sec)\n",
+ total,
+ MaxThreadNum,
+ (double)(time)/1000000.0);
+
+ /*
+ printf("[");
+ for (i=0; i<MaxThreadNum-1; i++) {
+ printf("%.1f%%, ", VM_GetInteractionNum(VMs[i])/(double)total*100.0);
+ }
+ printf("%.1f%%] (CPUNUM=%d)\n", VM_GetInteractionNum(VMs[i])/(double)total*100.0, CpuNum);
+ */
+
+#else
+ printf("(%.2f sec by %d threads)\n",
+ (double)(time)/1000000.0,
+ MaxThreadNum);
+#endif
+
+
+ return 0;
+}
+#endif
+
+
+
+int destroy() {
+
+ return 0;
+}
+
+int yywrap() {
+ return 1;
+}
+
+
+int main(int argc, char *argv[])
+{
+ int retrieve_flag = 1; // 1:エラー時にインタプリタへ復帰, 0:終了
+
+
+#ifdef MY_YYLINENO
+ initInfoLineno();
+#endif
+
+ // Pritty printing for local variables
+#ifdef PRETTY_VAR
+ Pretty_init();
+#endif
+
+ {
+ int i, param;
+ char *fname = NULL;
+
+#ifndef MALLOC
+ unsigned int max_AgentBuffer=100000;
+ unsigned int min_AgentBuffer=20000;
+#endif
+ unsigned int max_EQStack=10000;
+
+
+#ifndef THREAD
+ Init_WHNFinfo();
+#endif
+
+
+ for (i=1; i<argc; i++) {
+ if (*argv[i] == '-') {
+ switch (*(argv[i] +1)) {
+ case 'v':
+ printf("Inpla version %s\n", VERSION);
+ exit(-1);
+ break;
+ case '-':
+ case 'h':
+ case '?':
+ puts("Usage: inpla [options]\n");
+ puts("Options:");
+ printf(" -f <filename> Set input file name (Defalut: STDIN)\n");
+
+#ifndef MALLOC
+ printf(" -c <number> Set the size of term cells (Defalut: %8u)\n",
+ max_AgentBuffer);
+#endif
+
+ printf(" -x <number> Set the size of the EQ stack (Default: %8u)\n",
+ max_EQStack);
+
+
+ // Extended Options for threads or non-threads
+#ifdef THREAD
+ printf(" -t <number> Set the number of threads (Default: %8d)\n",
+ MaxThreadNum);
+
+#else
+ printf(" -w Enable Weak Head Normal Form strategy (Default: false)\n"
+ );
+
+
+#endif
+
+
+ printf(" -h Print this help message\n\n");
+ exit(-1);
+ break;
+
+
+ case 'f' :
+ i++;
+ if (i < argc) {
+ fname = argv[i];
+ retrieve_flag = 0;
+ } else {
+ printf("ERROR: The option switch '-f' needs a string that specifies an input file name.");
+ exit(-1);
+ }
+ break;
+
+
+
+#ifndef MALLOC
+ case 'c' :
+ i++;
+ if (i < argc) {
+ param = atoi(argv[i]);
+ if (param == 0) {
+ printf("ERROR: '%s' is illegal parameter for -c\n", argv[i]);
+ exit(-1);
+ }
+ } else {
+ printf("ERROR: The option switch '-c' needs a number as an argument.");
+ exit(-1);
+ }
+ max_AgentBuffer=param;
+ break;
+#endif
+
+ case 'x' :
+ i++;
+ if (i < argc) {
+ param = atoi(argv[i]);
+ if (param == 0) {
+ printf("ERROR: '%s' is illegal parameter for -x\n", argv[i]);
+ exit(-1);
+ }
+ } else {
+ printf("ERROR: The option switch '-x' needs a number as an argument.");
+ exit(-1);
+ }
+ max_EQStack=param;
+ break;
+
+
+#ifdef THREAD
+ case 't' :
+ i++;
+ if (i < argc) {
+ param = atoi(argv[i]);
+ if (param == 0) {
+ printf("ERROR: '%s' is illegal parameter for -t\n", argv[i]);
+ exit(-1);
+ }
+ } else {
+ printf("ERROR: The option switch '-t' needs a number as an argument.");
+ exit(-1);
+ }
+
+ MaxThreadNum=param;
+ break;
+#else
+ case 'w' :
+ WHNFinfo.enabled = 1;
+ break;
+#endif
+
+
+ default:
+ printf("ERROR: Unrecognized option %s\n", argv[i]);
+ printf("Please use -h option for getting more information.\n\n");
+ exit(-1);
+ }
+ }
+ }
+
+
+ // Dealing with fname
+ if (fname == NULL) {
+ yyin = stdin;
+
+ } else {
+ if (!(yyin = fopen(fname, "r"))) {
+ printf("Error: The file '%s' can not be opened.\n", fname);
+ exit(-1);
+ }
+ }
+
+
+#ifndef THREAD
+ if (WHNFinfo.enabled) {
+ printf("Inpla %s (WHNF) : Interaction nets as a programming language",
+ VERSION);
+ printf(" [%s]\n", BUILT_DATE);
+ } else {
+ printf("Inpla %s : Interaction nets as a programming language",
+ VERSION);
+ printf(" [built: %s]\n", BUILT_DATE);
+ }
+#else
+ printf("Inpla %s : Interaction nets as a programming language",
+ VERSION);
+ printf(" [built: %s]\n", BUILT_DATE);
+#endif
+
+
+
+ max_AgentBuffer = min_AgentBuffer + max_AgentBuffer/MaxThreadNum;
+ printf("max_AgentBuffer:%d\n", max_AgentBuffer);
+
+ IdTable_init();
+ NameTable_init();
+ RuleTable_init();
+
+#ifdef THREAD
+ GlobalEQStack_Init(max_EQStack);
+#endif
+
+ ast_heapInit();
+
+ CmEnv_Init(VM_LOCALVAR_SIZE);
+
+
+ // builtin agents
+
+ // IdTable_set_name(ID_PAIR0, SYM_PAIR0);
+
+
+#ifndef THREAD
+ Init_VM(&VM, max_AgentBuffer, max_EQStack);
+#else
+ tpool_init(max_AgentBuffer, max_EQStack);
+#endif
+
+ /*
+ printf("Name size=%d\n", sizeof(Name));
+ printf("Basic size=%d\n", sizeof(Basic));
+ printf("VALUE size=%d\n", sizeof(VALUE));
+ printf("IDTYPE size=%d\n", sizeof(IDTYPE));
+ */
+
+ }
+
+
+
+ // the main loop of parsing and execution
+ while(1) {
+
+
+ // When errors occur during parsing
+ if (yyparse()!=0) {
+
+ if (!retrieve_flag) {
+ exit(0);
+ }
+
+ if (yyin != stdin) {
+ fclose(yyin);
+ while (yyin!=stdin) {
+ popFP();
+ }
+#ifdef MY_YYLINENO
+ InfoLineno_AllDestroy();
+#endif
+ }
+
+ }
+ }
+
+ exit(0);
+}
+
+
+#include "lex.yy.c"
diff --git a/src/linenoise/.gitignore b/src/linenoise/.gitignore
new file mode 100644
index 0000000..7ab7825
--- /dev/null
+++ b/src/linenoise/.gitignore
@@ -0,0 +1,3 @@
+linenoise_example
+*.dSYM
+history.txt
diff --git a/src/linenoise/linenoise.c b/src/linenoise/linenoise.c
new file mode 100644
index 0000000..cfe51e7
--- /dev/null
+++ b/src/linenoise/linenoise.c
@@ -0,0 +1,1225 @@
+/* linenoise.c -- guerrilla line editing library against the idea that a
+ * line editing lib needs to be 20,000 lines of C code.
+ *
+ * You can find the latest source code at:
+ *
+ * http://github.com/antirez/linenoise
+ *
+ * Does a number of crazy assumptions that happen to be true in 99.9999% of
+ * the 2010 UNIX computers around.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * References:
+ * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+ * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
+ *
+ * Todo list:
+ * - Filter bogus Ctrl+<char> combinations.
+ * - Win32 support
+ *
+ * Bloat:
+ * - History search like Ctrl+r in readline?
+ *
+ * List of escape sequences used by this program, we do everything just
+ * with three sequences. In order to be so cheap we may have some
+ * flickering effect with some slow terminal, but the lesser sequences
+ * the more compatible.
+ *
+ * EL (Erase Line)
+ * Sequence: ESC [ n K
+ * Effect: if n is 0 or missing, clear from cursor to end of line
+ * Effect: if n is 1, clear from beginning of line to cursor
+ * Effect: if n is 2, clear entire line
+ *
+ * CUF (CUrsor Forward)
+ * Sequence: ESC [ n C
+ * Effect: moves cursor forward n chars
+ *
+ * CUB (CUrsor Backward)
+ * Sequence: ESC [ n D
+ * Effect: moves cursor backward n chars
+ *
+ * The following is used to get the terminal width if getting
+ * the width with the TIOCGWINSZ ioctl fails
+ *
+ * DSR (Device Status Report)
+ * Sequence: ESC [ 6 n
+ * Effect: reports the current cusor position as ESC [ n ; m R
+ * where n is the row and m is the column
+ *
+ * When multi line mode is enabled, we also use an additional escape
+ * sequence. However multi line editing is disabled by default.
+ *
+ * CUU (Cursor Up)
+ * Sequence: ESC [ n A
+ * Effect: moves cursor up of n chars.
+ *
+ * CUD (Cursor Down)
+ * Sequence: ESC [ n B
+ * Effect: moves cursor down of n chars.
+ *
+ * When linenoiseClearScreen() is called, two additional escape sequences
+ * are used in order to clear the screen and position the cursor at home
+ * position.
+ *
+ * CUP (Cursor position)
+ * Sequence: ESC [ H
+ * Effect: moves the cursor to upper left corner
+ *
+ * ED (Erase display)
+ * Sequence: ESC [ 2 J
+ * Effect: clear the whole screen
+ *
+ */
+
+#include <termios.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include "linenoise.h"
+
+#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
+#define LINENOISE_MAX_LINE 4096
+static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
+static linenoiseCompletionCallback *completionCallback = NULL;
+static linenoiseHintsCallback *hintsCallback = NULL;
+static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
+
+static struct termios orig_termios; /* In order to restore at exit.*/
+static int maskmode = 0; /* Show "***" instead of input. For passwords. */
+static int rawmode = 0; /* For atexit() function to check if restore is needed*/
+static int mlmode = 0; /* Multi line mode. Default is single line. */
+static int atexit_registered = 0; /* Register atexit just 1 time. */
+static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
+static int history_len = 0;
+static char **history = NULL;
+
+/* The linenoiseState structure represents the state during line editing.
+ * We pass this state to functions implementing specific editing
+ * functionalities. */
+struct linenoiseState {
+ int ifd; /* Terminal stdin file descriptor. */
+ int ofd; /* Terminal stdout file descriptor. */
+ char *buf; /* Edited line buffer. */
+ size_t buflen; /* Edited line buffer size. */
+ const char *prompt; /* Prompt to display. */
+ size_t plen; /* Prompt length. */
+ size_t pos; /* Current cursor position. */
+ size_t oldpos; /* Previous refresh cursor position. */
+ size_t len; /* Current edited line length. */
+ size_t cols; /* Number of columns in terminal. */
+ size_t maxrows; /* Maximum num of rows used so far (multiline mode) */
+ int history_index; /* The history index we are currently editing. */
+};
+
+enum KEY_ACTION{
+ KEY_NULL = 0, /* NULL */
+ CTRL_A = 1, /* Ctrl+a */
+ CTRL_B = 2, /* Ctrl-b */
+ CTRL_C = 3, /* Ctrl-c */
+ CTRL_D = 4, /* Ctrl-d */
+ CTRL_E = 5, /* Ctrl-e */
+ CTRL_F = 6, /* Ctrl-f */
+ CTRL_H = 8, /* Ctrl-h */
+ TAB = 9, /* Tab */
+ CTRL_K = 11, /* Ctrl+k */
+ CTRL_L = 12, /* Ctrl+l */
+ ENTER = 13, /* Enter */
+ CTRL_N = 14, /* Ctrl-n */
+ CTRL_P = 16, /* Ctrl-p */
+ CTRL_T = 20, /* Ctrl-t */
+ CTRL_U = 21, /* Ctrl+u */
+ CTRL_W = 23, /* Ctrl+w */
+ ESC = 27, /* Escape */
+ BACKSPACE = 127 /* Backspace */
+};
+
+static void linenoiseAtExit(void);
+int linenoiseHistoryAdd(const char *line);
+static void refreshLine(struct linenoiseState *l);
+
+/* Debugging macro. */
+#if 0
+FILE *lndebug_fp = NULL;
+#define lndebug(...) \
+ do { \
+ if (lndebug_fp == NULL) { \
+ lndebug_fp = fopen("/tmp/lndebug.txt","a"); \
+ fprintf(lndebug_fp, \
+ "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \
+ (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \
+ (int)l->maxrows,old_rows); \
+ } \
+ fprintf(lndebug_fp, ", " __VA_ARGS__); \
+ fflush(lndebug_fp); \
+ } while (0)
+#else
+#define lndebug(fmt, ...)
+#endif
+
+/* ======================= Low level terminal handling ====================== */
+
+/* Enable "mask mode". When it is enabled, instead of the input that
+ * the user is typing, the terminal will just display a corresponding
+ * number of asterisks, like "****". This is useful for passwords and other
+ * secrets that should not be displayed. */
+void linenoiseMaskModeEnable(void) {
+ maskmode = 1;
+}
+
+/* Disable mask mode. */
+void linenoiseMaskModeDisable(void) {
+ maskmode = 0;
+}
+
+/* Set if to use or not the multi line mode. */
+void linenoiseSetMultiLine(int ml) {
+ mlmode = ml;
+}
+
+/* Return true if the terminal name is in the list of terminals we know are
+ * not able to understand basic escape sequences. */
+static int isUnsupportedTerm(void) {
+ char *term = getenv("TERM");
+ int j;
+
+ if (term == NULL) return 0;
+ for (j = 0; unsupported_term[j]; j++)
+ if (!strcasecmp(term,unsupported_term[j])) return 1;
+ return 0;
+}
+
+/* Raw mode: 1960 magic shit. */
+static int enableRawMode(int fd) {
+ struct termios raw;
+
+ if (!isatty(STDIN_FILENO)) goto fatal;
+ if (!atexit_registered) {
+ atexit(linenoiseAtExit);
+ atexit_registered = 1;
+ }
+ if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
+
+ raw = orig_termios; /* modify the original mode */
+ /* input modes: no break, no CR to NL, no parity check, no strip char,
+ * no start/stop output control. */
+ raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+ /* output modes - disable post processing */
+ raw.c_oflag &= ~(OPOST);
+ /* control modes - set 8 bit chars */
+ raw.c_cflag |= (CS8);
+ /* local modes - choing off, canonical off, no extended functions,
+ * no signal chars (^Z,^C) */
+ raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+ /* control chars - set return condition: min number of bytes and timer.
+ * We want read to return every single byte, without timeout. */
+ raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
+
+ /* put terminal in raw mode after flushing */
+ if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
+ rawmode = 1;
+ return 0;
+
+fatal:
+ errno = ENOTTY;
+ return -1;
+}
+
+static void disableRawMode(int fd) {
+ /* Don't even check the return value as it's too late. */
+ if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)
+ rawmode = 0;
+}
+
+/* Use the ESC [6n escape sequence to query the horizontal cursor position
+ * and return it. On error -1 is returned, on success the position of the
+ * cursor. */
+static int getCursorPosition(int ifd, int ofd) {
+ char buf[32];
+ int cols, rows;
+ unsigned int i = 0;
+
+ /* Report cursor location */
+ if (write(ofd, "\x1b[6n", 4) != 4) return -1;
+
+ /* Read the response: ESC [ rows ; cols R */
+ while (i < sizeof(buf)-1) {
+ if (read(ifd,buf+i,1) != 1) break;
+ if (buf[i] == 'R') break;
+ i++;
+ }
+ buf[i] = '\0';
+
+ /* Parse it. */
+ if (buf[0] != ESC || buf[1] != '[') return -1;
+ if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
+ return cols;
+}
+
+/* Try to get the number of columns in the current terminal, or assume 80
+ * if it fails. */
+static int getColumns(int ifd, int ofd) {
+ struct winsize ws;
+
+ if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
+ /* ioctl() failed. Try to query the terminal itself. */
+ int start, cols;
+
+ /* Get the initial position so we can restore it later. */
+ start = getCursorPosition(ifd,ofd);
+ if (start == -1) goto failed;
+
+ /* Go to right margin and get position. */
+ if (write(ofd,"\x1b[999C",6) != 6) goto failed;
+ cols = getCursorPosition(ifd,ofd);
+ if (cols == -1) goto failed;
+
+ /* Restore position. */
+ if (cols > start) {
+ char seq[32];
+ snprintf(seq,32,"\x1b[%dD",cols-start);
+ if (write(ofd,seq,strlen(seq)) == -1) {
+ /* Can't recover... */
+ }
+ }
+ return cols;
+ } else {
+ return ws.ws_col;
+ }
+
+failed:
+ return 80;
+}
+
+/* Clear the screen. Used to handle ctrl+l */
+void linenoiseClearScreen(void) {
+ if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
+ /* nothing to do, just to avoid warning. */
+ }
+}
+
+/* Beep, used for completion when there is nothing to complete or when all
+ * the choices were already shown. */
+static void linenoiseBeep(void) {
+ fprintf(stderr, "\x7");
+ fflush(stderr);
+}
+
+/* ============================== Completion ================================ */
+
+/* Free a list of completion option populated by linenoiseAddCompletion(). */
+static void freeCompletions(linenoiseCompletions *lc) {
+ size_t i;
+ for (i = 0; i < lc->len; i++)
+ free(lc->cvec[i]);
+ if (lc->cvec != NULL)
+ free(lc->cvec);
+}
+
+/* This is an helper function for linenoiseEdit() and is called when the
+ * user types the <tab> key in order to complete the string currently in the
+ * input.
+ *
+ * The state of the editing is encapsulated into the pointed linenoiseState
+ * structure as described in the structure definition. */
+static int completeLine(struct linenoiseState *ls) {
+ linenoiseCompletions lc = { 0, NULL };
+ int nread, nwritten;
+ char c = 0;
+
+ completionCallback(ls->buf,&lc);
+ if (lc.len == 0) {
+ linenoiseBeep();
+ } else {
+ size_t stop = 0, i = 0;
+
+ while(!stop) {
+ /* Show completion or original buffer */
+ if (i < lc.len) {
+ struct linenoiseState saved = *ls;
+
+ ls->len = ls->pos = strlen(lc.cvec[i]);
+ ls->buf = lc.cvec[i];
+ refreshLine(ls);
+ ls->len = saved.len;
+ ls->pos = saved.pos;
+ ls->buf = saved.buf;
+ } else {
+ refreshLine(ls);
+ }
+
+ nread = read(ls->ifd,&c,1);
+ if (nread <= 0) {
+ freeCompletions(&lc);
+ return -1;
+ }
+
+ switch(c) {
+ case 9: /* tab */
+ i = (i+1) % (lc.len+1);
+ if (i == lc.len) linenoiseBeep();
+ break;
+ case 27: /* escape */
+ /* Re-show original buffer */
+ if (i < lc.len) refreshLine(ls);
+ stop = 1;
+ break;
+ default:
+ /* Update buffer and return */
+ if (i < lc.len) {
+ nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]);
+ ls->len = ls->pos = nwritten;
+ }
+ stop = 1;
+ break;
+ }
+ }
+ }
+
+ freeCompletions(&lc);
+ return c; /* Return last read character */
+}
+
+/* Register a callback function to be called for tab-completion. */
+void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
+ completionCallback = fn;
+}
+
+/* Register a hits function to be called to show hits to the user at the
+ * right of the prompt. */
+void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) {
+ hintsCallback = fn;
+}
+
+/* Register a function to free the hints returned by the hints callback
+ * registered with linenoiseSetHintsCallback(). */
+void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) {
+ freeHintsCallback = fn;
+}
+
+/* This function is used by the callback function registered by the user
+ * in order to add completion options given the input string when the
+ * user typed <tab>. See the example.c source code for a very easy to
+ * understand example. */
+void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
+ size_t len = strlen(str);
+ char *copy, **cvec;
+
+ copy = malloc(len+1);
+ if (copy == NULL) return;
+ memcpy(copy,str,len+1);
+ cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
+ if (cvec == NULL) {
+ free(copy);
+ return;
+ }
+ lc->cvec = cvec;
+ lc->cvec[lc->len++] = copy;
+}
+
+/* =========================== Line editing ================================= */
+
+/* We define a very simple "append buffer" structure, that is an heap
+ * allocated string where we can append to. This is useful in order to
+ * write all the escape sequences in a buffer and flush them to the standard
+ * output in a single call, to avoid flickering effects. */
+struct abuf {
+ char *b;
+ int len;
+};
+
+static void abInit(struct abuf *ab) {
+ ab->b = NULL;
+ ab->len = 0;
+}
+
+static void abAppend(struct abuf *ab, const char *s, int len) {
+ char *new = realloc(ab->b,ab->len+len);
+
+ if (new == NULL) return;
+ memcpy(new+ab->len,s,len);
+ ab->b = new;
+ ab->len += len;
+}
+
+static void abFree(struct abuf *ab) {
+ free(ab->b);
+}
+
+/* Helper of refreshSingleLine() and refreshMultiLine() to show hints
+ * to the right of the prompt. */
+void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
+ char seq[64];
+ if (hintsCallback && plen+l->len < l->cols) {
+ int color = -1, bold = 0;
+ char *hint = hintsCallback(l->buf,&color,&bold);
+ if (hint) {
+ int hintlen = strlen(hint);
+ int hintmaxlen = l->cols-(plen+l->len);
+ if (hintlen > hintmaxlen) hintlen = hintmaxlen;
+ if (bold == 1 && color == -1) color = 37;
+ if (color != -1 || bold != 0)
+ snprintf(seq,64,"\033[%d;%d;49m",bold,color);
+ else
+ seq[0] = '\0';
+ abAppend(ab,seq,strlen(seq));
+ abAppend(ab,hint,hintlen);
+ if (color != -1 || bold != 0)
+ abAppend(ab,"\033[0m",4);
+ /* Call the function to free the hint returned. */
+ if (freeHintsCallback) freeHintsCallback(hint);
+ }
+ }
+}
+
+/* Single line low level line refresh.
+ *
+ * Rewrite the currently edited line accordingly to the buffer content,
+ * cursor position, and number of columns of the terminal. */
+static void refreshSingleLine(struct linenoiseState *l) {
+ char seq[64];
+ size_t plen = strlen(l->prompt);
+ int fd = l->ofd;
+ char *buf = l->buf;
+ size_t len = l->len;
+ size_t pos = l->pos;
+ struct abuf ab;
+
+ while((plen+pos) >= l->cols) {
+ buf++;
+ len--;
+ pos--;
+ }
+ while (plen+len > l->cols) {
+ len--;
+ }
+
+ abInit(&ab);
+ /* Cursor to left edge */
+ snprintf(seq,64,"\r");
+ abAppend(&ab,seq,strlen(seq));
+ /* Write the prompt and the current buffer content */
+ abAppend(&ab,l->prompt,strlen(l->prompt));
+ if (maskmode == 1) {
+ while (len--) abAppend(&ab,"*",1);
+ } else {
+ abAppend(&ab,buf,len);
+ }
+ /* Show hits if any. */
+ refreshShowHints(&ab,l,plen);
+ /* Erase to right */
+ snprintf(seq,64,"\x1b[0K");
+ abAppend(&ab,seq,strlen(seq));
+ /* Move cursor to original position. */
+ snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen));
+ abAppend(&ab,seq,strlen(seq));
+ if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
+ abFree(&ab);
+}
+
+/* Multi line low level line refresh.
+ *
+ * Rewrite the currently edited line accordingly to the buffer content,
+ * cursor position, and number of columns of the terminal. */
+static void refreshMultiLine(struct linenoiseState *l) {
+ char seq[64];
+ int plen = strlen(l->prompt);
+ int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */
+ int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */
+ int rpos2; /* rpos after refresh. */
+ int col; /* colum position, zero-based. */
+ int old_rows = l->maxrows;
+ int fd = l->ofd, j;
+ struct abuf ab;
+
+ /* Update maxrows if needed. */
+ if (rows > (int)l->maxrows) l->maxrows = rows;
+
+ /* First step: clear all the lines used before. To do so start by
+ * going to the last row. */
+ abInit(&ab);
+ if (old_rows-rpos > 0) {
+ lndebug("go down %d", old_rows-rpos);
+ snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
+ abAppend(&ab,seq,strlen(seq));
+ }
+
+ /* Now for every row clear it, go up. */
+ for (j = 0; j < old_rows-1; j++) {
+ lndebug("clear+up");
+ snprintf(seq,64,"\r\x1b[0K\x1b[1A");
+ abAppend(&ab,seq,strlen(seq));
+ }
+
+ /* Clean the top line. */
+ lndebug("clear");
+ snprintf(seq,64,"\r\x1b[0K");
+ abAppend(&ab,seq,strlen(seq));
+
+ /* Write the prompt and the current buffer content */
+ abAppend(&ab,l->prompt,strlen(l->prompt));
+ if (maskmode == 1) {
+ unsigned int i;
+ for (i = 0; i < l->len; i++) abAppend(&ab,"*",1);
+ } else {
+ abAppend(&ab,l->buf,l->len);
+ }
+
+ /* Show hits if any. */
+ refreshShowHints(&ab,l,plen);
+
+ /* If we are at the very end of the screen with our prompt, we need to
+ * emit a newline and move the prompt to the first column. */
+ if (l->pos &&
+ l->pos == l->len &&
+ (l->pos+plen) % l->cols == 0)
+ {
+ lndebug("<newline>");
+ abAppend(&ab,"\n",1);
+ snprintf(seq,64,"\r");
+ abAppend(&ab,seq,strlen(seq));
+ rows++;
+ if (rows > (int)l->maxrows) l->maxrows = rows;
+ }
+
+ /* Move cursor to right position. */
+ rpos2 = (plen+l->pos+l->cols)/l->cols; /* current cursor relative row. */
+ lndebug("rpos2 %d", rpos2);
+
+ /* Go up till we reach the expected positon. */
+ if (rows-rpos2 > 0) {
+ lndebug("go-up %d", rows-rpos2);
+ snprintf(seq,64,"\x1b[%dA", rows-rpos2);
+ abAppend(&ab,seq,strlen(seq));
+ }
+
+ /* Set column. */
+ col = (plen+(int)l->pos) % (int)l->cols;
+ lndebug("set col %d", 1+col);
+ if (col)
+ snprintf(seq,64,"\r\x1b[%dC", col);
+ else
+ snprintf(seq,64,"\r");
+ abAppend(&ab,seq,strlen(seq));
+
+ lndebug("\n");
+ l->oldpos = l->pos;
+
+ if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
+ abFree(&ab);
+}
+
+/* Calls the two low level functions refreshSingleLine() or
+ * refreshMultiLine() according to the selected mode. */
+static void refreshLine(struct linenoiseState *l) {
+ if (mlmode)
+ refreshMultiLine(l);
+ else
+ refreshSingleLine(l);
+}
+
+/* Insert the character 'c' at cursor current position.
+ *
+ * On error writing to the terminal -1 is returned, otherwise 0. */
+int linenoiseEditInsert(struct linenoiseState *l, char c) {
+ if (l->len < l->buflen) {
+ if (l->len == l->pos) {
+ l->buf[l->pos] = c;
+ l->pos++;
+ l->len++;
+ l->buf[l->len] = '\0';
+ if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {
+ /* Avoid a full update of the line in the
+ * trivial case. */
+ char d = (maskmode==1) ? '*' : c;
+ if (write(l->ofd,&d,1) == -1) return -1;
+ } else {
+ refreshLine(l);
+ }
+ } else {
+ memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos);
+ l->buf[l->pos] = c;
+ l->len++;
+ l->pos++;
+ l->buf[l->len] = '\0';
+ refreshLine(l);
+ }
+ }
+ return 0;
+}
+
+/* Move cursor on the left. */
+void linenoiseEditMoveLeft(struct linenoiseState *l) {
+ if (l->pos > 0) {
+ l->pos--;
+ refreshLine(l);
+ }
+}
+
+/* Move cursor on the right. */
+void linenoiseEditMoveRight(struct linenoiseState *l) {
+ if (l->pos != l->len) {
+ l->pos++;
+ refreshLine(l);
+ }
+}
+
+/* Move cursor to the start of the line. */
+void linenoiseEditMoveHome(struct linenoiseState *l) {
+ if (l->pos != 0) {
+ l->pos = 0;
+ refreshLine(l);
+ }
+}
+
+/* Move cursor to the end of the line. */
+void linenoiseEditMoveEnd(struct linenoiseState *l) {
+ if (l->pos != l->len) {
+ l->pos = l->len;
+ refreshLine(l);
+ }
+}
+
+/* Substitute the currently edited line with the next or previous history
+ * entry as specified by 'dir'. */
+#define LINENOISE_HISTORY_NEXT 0
+#define LINENOISE_HISTORY_PREV 1
+void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) {
+ if (history_len > 1) {
+ /* Update the current history entry before to
+ * overwrite it with the next one. */
+ free(history[history_len - 1 - l->history_index]);
+ history[history_len - 1 - l->history_index] = strdup(l->buf);
+ /* Show the new entry */
+ l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1;
+ if (l->history_index < 0) {
+ l->history_index = 0;
+ return;
+ } else if (l->history_index >= history_len) {
+ l->history_index = history_len-1;
+ return;
+ }
+ strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen);
+ l->buf[l->buflen-1] = '\0';
+ l->len = l->pos = strlen(l->buf);
+ refreshLine(l);
+ }
+}
+
+/* Delete the character at the right of the cursor without altering the cursor
+ * position. Basically this is what happens with the "Delete" keyboard key. */
+void linenoiseEditDelete(struct linenoiseState *l) {
+ if (l->len > 0 && l->pos < l->len) {
+ memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1);
+ l->len--;
+ l->buf[l->len] = '\0';
+ refreshLine(l);
+ }
+}
+
+/* Backspace implementation. */
+void linenoiseEditBackspace(struct linenoiseState *l) {
+ if (l->pos > 0 && l->len > 0) {
+ memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos);
+ l->pos--;
+ l->len--;
+ l->buf[l->len] = '\0';
+ refreshLine(l);
+ }
+}
+
+/* Delete the previosu word, maintaining the cursor at the start of the
+ * current word. */
+void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
+ size_t old_pos = l->pos;
+ size_t diff;
+
+ while (l->pos > 0 && l->buf[l->pos-1] == ' ')
+ l->pos--;
+ while (l->pos > 0 && l->buf[l->pos-1] != ' ')
+ l->pos--;
+ diff = old_pos - l->pos;
+ memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);
+ l->len -= diff;
+ refreshLine(l);
+}
+
+/* This function is the core of the line editing capability of linenoise.
+ * It expects 'fd' to be already in "raw mode" so that every key pressed
+ * will be returned ASAP to read().
+ *
+ * The resulting string is put into 'buf' when the user type enter, or
+ * when ctrl+d is typed.
+ *
+ * The function returns the length of the current buffer. */
+static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
+{
+ struct linenoiseState l;
+
+ /* Populate the linenoise state that we pass to functions implementing
+ * specific editing functionalities. */
+ l.ifd = stdin_fd;
+ l.ofd = stdout_fd;
+ l.buf = buf;
+ l.buflen = buflen;
+ l.prompt = prompt;
+ l.plen = strlen(prompt);
+ l.oldpos = l.pos = 0;
+ l.len = 0;
+ l.cols = getColumns(stdin_fd, stdout_fd);
+ l.maxrows = 0;
+ l.history_index = 0;
+
+ /* Buffer starts empty. */
+ l.buf[0] = '\0';
+ l.buflen--; /* Make sure there is always space for the nulterm */
+
+ /* The latest history entry is always our current buffer, that
+ * initially is just an empty string. */
+ linenoiseHistoryAdd("");
+
+ if (write(l.ofd,prompt,l.plen) == -1) return -1;
+ while(1) {
+ char c;
+ int nread;
+ char seq[3];
+
+ nread = read(l.ifd,&c,1);
+ if (nread <= 0) return l.len;
+
+ /* Only autocomplete when the callback is set. It returns < 0 when
+ * there was an error reading from fd. Otherwise it will return the
+ * character that should be handled next. */
+ if (c == 9 && completionCallback != NULL) {
+ c = completeLine(&l);
+ /* Return on errors */
+ if (c < 0) return l.len;
+ /* Read next character when 0 */
+ if (c == 0) continue;
+ }
+
+ switch(c) {
+ case ENTER: /* enter */
+ history_len--;
+ free(history[history_len]);
+ if (mlmode) linenoiseEditMoveEnd(&l);
+ if (hintsCallback) {
+ /* Force a refresh without hints to leave the previous
+ * line as the user typed it after a newline. */
+ linenoiseHintsCallback *hc = hintsCallback;
+ hintsCallback = NULL;
+ refreshLine(&l);
+ hintsCallback = hc;
+ }
+ return (int)l.len;
+ case CTRL_C: /* ctrl-c */
+ errno = EAGAIN;
+ return -1;
+ case BACKSPACE: /* backspace */
+ case 8: /* ctrl-h */
+ linenoiseEditBackspace(&l);
+ break;
+ case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the
+ line is empty, act as end-of-file. */
+ if (l.len > 0) {
+ linenoiseEditDelete(&l);
+ } else {
+ history_len--;
+ free(history[history_len]);
+ return -1;
+ }
+ break;
+ case CTRL_T: /* ctrl-t, swaps current character with previous. */
+ if (l.pos > 0 && l.pos < l.len) {
+ int aux = buf[l.pos-1];
+ buf[l.pos-1] = buf[l.pos];
+ buf[l.pos] = aux;
+ if (l.pos != l.len-1) l.pos++;
+ refreshLine(&l);
+ }
+ break;
+ case CTRL_B: /* ctrl-b */
+ linenoiseEditMoveLeft(&l);
+ break;
+ case CTRL_F: /* ctrl-f */
+ linenoiseEditMoveRight(&l);
+ break;
+ case CTRL_P: /* ctrl-p */
+ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
+ break;
+ case CTRL_N: /* ctrl-n */
+ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
+ break;
+ case ESC: /* escape sequence */
+ /* Read the next two bytes representing the escape sequence.
+ * Use two calls to handle slow terminals returning the two
+ * chars at different times. */
+ if (read(l.ifd,seq,1) == -1) break;
+ if (read(l.ifd,seq+1,1) == -1) break;
+
+ /* ESC [ sequences. */
+ if (seq[0] == '[') {
+ if (seq[1] >= '0' && seq[1] <= '9') {
+ /* Extended escape, read additional byte. */
+ if (read(l.ifd,seq+2,1) == -1) break;
+ if (seq[2] == '~') {
+ switch(seq[1]) {
+ case '3': /* Delete key. */
+ linenoiseEditDelete(&l);
+ break;
+ }
+ }
+ } else {
+ switch(seq[1]) {
+ case 'A': /* Up */
+ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
+ break;
+ case 'B': /* Down */
+ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
+ break;
+ case 'C': /* Right */
+ linenoiseEditMoveRight(&l);
+ break;
+ case 'D': /* Left */
+ linenoiseEditMoveLeft(&l);
+ break;
+ case 'H': /* Home */
+ linenoiseEditMoveHome(&l);
+ break;
+ case 'F': /* End*/
+ linenoiseEditMoveEnd(&l);
+ break;
+ }
+ }
+ }
+
+ /* ESC O sequences. */
+ else if (seq[0] == 'O') {
+ switch(seq[1]) {
+ case 'H': /* Home */
+ linenoiseEditMoveHome(&l);
+ break;
+ case 'F': /* End*/
+ linenoiseEditMoveEnd(&l);
+ break;
+ }
+ }
+ break;
+ default:
+ if (linenoiseEditInsert(&l,c)) return -1;
+ break;
+ case CTRL_U: /* Ctrl+u, delete the whole line. */
+ buf[0] = '\0';
+ l.pos = l.len = 0;
+ refreshLine(&l);
+ break;
+ case CTRL_K: /* Ctrl+k, delete from current to end of line. */
+ buf[l.pos] = '\0';
+ l.len = l.pos;
+ refreshLine(&l);
+ break;
+ case CTRL_A: /* Ctrl+a, go to the start of the line */
+ linenoiseEditMoveHome(&l);
+ break;
+ case CTRL_E: /* ctrl+e, go to the end of the line */
+ linenoiseEditMoveEnd(&l);
+ break;
+ case CTRL_L: /* ctrl+l, clear screen */
+ linenoiseClearScreen();
+ refreshLine(&l);
+ break;
+ case CTRL_W: /* ctrl+w, delete previous word */
+ linenoiseEditDeletePrevWord(&l);
+ break;
+ }
+ }
+ return l.len;
+}
+
+/* This special mode is used by linenoise in order to print scan codes
+ * on screen for debugging / development purposes. It is implemented
+ * by the linenoise_example program using the --keycodes option. */
+void linenoisePrintKeyCodes(void) {
+ char quit[4];
+
+ printf("Linenoise key codes debugging mode.\n"
+ "Press keys to see scan codes. Type 'quit' at any time to exit.\n");
+ if (enableRawMode(STDIN_FILENO) == -1) return;
+ memset(quit,' ',4);
+ while(1) {
+ char c;
+ int nread;
+
+ nread = read(STDIN_FILENO,&c,1);
+ if (nread <= 0) continue;
+ memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */
+ quit[sizeof(quit)-1] = c; /* Insert current char on the right. */
+ if (memcmp(quit,"quit",sizeof(quit)) == 0) break;
+
+ printf("'%c' %02x (%d) (type quit to exit)\n",
+ isprint(c) ? c : '?', (int)c, (int)c);
+ printf("\r"); /* Go left edge manually, we are in raw mode. */
+ fflush(stdout);
+ }
+ disableRawMode(STDIN_FILENO);
+}
+
+/* This function calls the line editing function linenoiseEdit() using
+ * the STDIN file descriptor set in raw mode. */
+static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
+ int count;
+
+ if (buflen == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (enableRawMode(STDIN_FILENO) == -1) return -1;
+ count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
+ disableRawMode(STDIN_FILENO);
+ printf("\n");
+ return count;
+}
+
+/* This function is called when linenoise() is called with the standard
+ * input file descriptor not attached to a TTY. So for example when the
+ * program using linenoise is called in pipe or with a file redirected
+ * to its standard input. In this case, we want to be able to return the
+ * line regardless of its length (by default we are limited to 4k). */
+static char *linenoiseNoTTY(void) {
+ char *line = NULL;
+ size_t len = 0, maxlen = 0;
+
+ while(1) {
+ if (len == maxlen) {
+ if (maxlen == 0) maxlen = 16;
+ maxlen *= 2;
+ char *oldval = line;
+ line = realloc(line,maxlen);
+ if (line == NULL) {
+ if (oldval) free(oldval);
+ return NULL;
+ }
+ }
+ int c = fgetc(stdin);
+ if (c == EOF || c == '\n') {
+ if (c == EOF && len == 0) {
+ free(line);
+ return NULL;
+ } else {
+ line[len] = '\0';
+ return line;
+ }
+ } else {
+ line[len] = c;
+ len++;
+ }
+ }
+}
+
+/* The high level function that is the main API of the linenoise library.
+ * This function checks if the terminal has basic capabilities, just checking
+ * for a blacklist of stupid terminals, and later either calls the line
+ * editing function or uses dummy fgets() so that you will be able to type
+ * something even in the most desperate of the conditions. */
+char *linenoise(const char *prompt) {
+ char buf[LINENOISE_MAX_LINE];
+ int count;
+
+ if (!isatty(STDIN_FILENO)) {
+ /* Not a tty: read from file / pipe. In this mode we don't want any
+ * limit to the line size, so we call a function to handle that. */
+ return linenoiseNoTTY();
+ } else if (isUnsupportedTerm()) {
+ size_t len;
+
+ printf("%s",prompt);
+ fflush(stdout);
+ if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL;
+ len = strlen(buf);
+ while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) {
+ len--;
+ buf[len] = '\0';
+ }
+ return strdup(buf);
+ } else {
+ count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
+ if (count == -1) return NULL;
+ return strdup(buf);
+ }
+}
+
+/* This is just a wrapper the user may want to call in order to make sure
+ * the linenoise returned buffer is freed with the same allocator it was
+ * created with. Useful when the main program is using an alternative
+ * allocator. */
+void linenoiseFree(void *ptr) {
+ free(ptr);
+}
+
+/* ================================ History ================================= */
+
+/* Free the history, but does not reset it. Only used when we have to
+ * exit() to avoid memory leaks are reported by valgrind & co. */
+static void freeHistory(void) {
+ if (history) {
+ int j;
+
+ for (j = 0; j < history_len; j++)
+ free(history[j]);
+ free(history);
+ }
+}
+
+/* At exit we'll try to fix the terminal to the initial conditions. */
+static void linenoiseAtExit(void) {
+ disableRawMode(STDIN_FILENO);
+ freeHistory();
+}
+
+/* This is the API call to add a new entry in the linenoise history.
+ * It uses a fixed array of char pointers that are shifted (memmoved)
+ * when the history max length is reached in order to remove the older
+ * entry and make room for the new one, so it is not exactly suitable for huge
+ * histories, but will work well for a few hundred of entries.
+ *
+ * Using a circular buffer is smarter, but a bit more complex to handle. */
+int linenoiseHistoryAdd(const char *line) {
+ char *linecopy;
+
+ if (history_max_len == 0) return 0;
+
+ /* Initialization on first call. */
+ if (history == NULL) {
+ history = malloc(sizeof(char*)*history_max_len);
+ if (history == NULL) return 0;
+ memset(history,0,(sizeof(char*)*history_max_len));
+ }
+
+ /* Don't add duplicated lines. */
+ if (history_len && !strcmp(history[history_len-1], line)) return 0;
+
+ /* Add an heap allocated copy of the line in the history.
+ * If we reached the max length, remove the older line. */
+ linecopy = strdup(line);
+ if (!linecopy) return 0;
+ if (history_len == history_max_len) {
+ free(history[0]);
+ memmove(history,history+1,sizeof(char*)*(history_max_len-1));
+ history_len--;
+ }
+ history[history_len] = linecopy;
+ history_len++;
+ return 1;
+}
+
+/* Set the maximum length for the history. This function can be called even
+ * if there is already some history, the function will make sure to retain
+ * just the latest 'len' elements if the new history length value is smaller
+ * than the amount of items already inside the history. */
+int linenoiseHistorySetMaxLen(int len) {
+ char **new;
+
+ if (len < 1) return 0;
+ if (history) {
+ int tocopy = history_len;
+
+ new = malloc(sizeof(char*)*len);
+ if (new == NULL) return 0;
+
+ /* If we can't copy everything, free the elements we'll not use. */
+ if (len < tocopy) {
+ int j;
+
+ for (j = 0; j < tocopy-len; j++) free(history[j]);
+ tocopy = len;
+ }
+ memset(new,0,sizeof(char*)*len);
+ memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy);
+ free(history);
+ history = new;
+ }
+ history_max_len = len;
+ if (history_len > history_max_len)
+ history_len = history_max_len;
+ return 1;
+}
+
+/* Save the history in the specified file. On success 0 is returned
+ * otherwise -1 is returned. */
+int linenoiseHistorySave(const char *filename) {
+ mode_t old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
+ FILE *fp;
+ int j;
+
+ fp = fopen(filename,"w");
+ umask(old_umask);
+ if (fp == NULL) return -1;
+ chmod(filename,S_IRUSR|S_IWUSR);
+ for (j = 0; j < history_len; j++)
+ fprintf(fp,"%s\n",history[j]);
+ fclose(fp);
+ return 0;
+}
+
+/* Load the history from the specified file. If the file does not exist
+ * zero is returned and no operation is performed.
+ *
+ * If the file exists and the operation succeeded 0 is returned, otherwise
+ * on error -1 is returned. */
+int linenoiseHistoryLoad(const char *filename) {
+ FILE *fp = fopen(filename,"r");
+ char buf[LINENOISE_MAX_LINE];
+
+ if (fp == NULL) return -1;
+
+ while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
+ char *p;
+
+ p = strchr(buf,'\r');
+ if (!p) p = strchr(buf,'\n');
+ if (p) *p = '\0';
+ linenoiseHistoryAdd(buf);
+ }
+ fclose(fp);
+ return 0;
+}
diff --git a/src/linenoise/linenoise.h b/src/linenoise/linenoise.h
new file mode 100644
index 0000000..6dfee73
--- /dev/null
+++ b/src/linenoise/linenoise.h
@@ -0,0 +1,75 @@
+/* linenoise.h -- VERSION 1.0
+ *
+ * Guerrilla line editing library against the idea that a line editing lib
+ * needs to be 20,000 lines of C code.
+ *
+ * See linenoise.c for more information.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LINENOISE_H
+#define __LINENOISE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct linenoiseCompletions {
+ size_t len;
+ char **cvec;
+} linenoiseCompletions;
+
+typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
+typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
+typedef void(linenoiseFreeHintsCallback)(void *);
+void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
+void linenoiseSetHintsCallback(linenoiseHintsCallback *);
+void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
+void linenoiseAddCompletion(linenoiseCompletions *, const char *);
+
+char *linenoise(const char *prompt);
+void linenoiseFree(void *ptr);
+int linenoiseHistoryAdd(const char *line);
+int linenoiseHistorySetMaxLen(int len);
+int linenoiseHistorySave(const char *filename);
+int linenoiseHistoryLoad(const char *filename);
+void linenoiseClearScreen(void);
+void linenoiseSetMultiLine(int ml);
+void linenoisePrintKeyCodes(void);
+void linenoiseMaskModeEnable(void);
+void linenoiseMaskModeDisable(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LINENOISE_H */
diff --git a/src/mytype.h b/src/mytype.h
new file mode 100644
index 0000000..7e55a20
--- /dev/null
+++ b/src/mytype.h
@@ -0,0 +1,49 @@
+#ifndef _TYPE_
+#define _TYPE_
+
+typedef unsigned int IDTYPE;
+typedef unsigned long VALUE;
+
+
+typedef struct {
+ IDTYPE id;
+} Basic;
+
+
+#define MAX_PORT 5
+
+#ifndef THREAD
+typedef struct {
+ Basic basic;
+ VALUE port;
+} Name;
+
+typedef struct {
+ Basic basic;
+ VALUE port[MAX_PORT];
+} Agent;
+
+#else
+typedef struct {
+ Basic basic;
+ volatile VALUE port;
+} Name;
+
+typedef struct {
+ Basic basic;
+ volatile VALUE port[MAX_PORT];
+} Agent;
+#endif
+
+
+#define FIXNUM_FLAG 0x01
+#define INT2FIX(i) ((VALUE)(((long)(i) << 1) | FIXNUM_FLAG))
+#define FIX2INT(i) ((int)(i) >> 1)
+#define IS_FIXNUM(i) ((VALUE)(i) & FIXNUM_FLAG)
+
+
+#define AGENT(a) ((Agent *)(a))
+#define BASIC(a) ((Basic *)(a))
+#define NAME(a) ((Name *)(a))
+
+#endif
diff --git a/src/name_table.c b/src/name_table.c
new file mode 100644
index 0000000..5c6f9f6
--- /dev/null
+++ b/src/name_table.c
@@ -0,0 +1,423 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "name_table.h"
+
+NameList *NameList_new() {
+ NameList *alist;
+ alist = malloc(sizeof(NameList));
+ if (alist == NULL) {
+ printf("Malloc error\n");
+ exit(-1);
+ }
+ return alist;
+}
+
+
+// It should be called at first, and never called after that.
+void NameTable_init() {
+ int i;
+ for (i=0; i<NAME_HASHSIZE; i++) {
+ NameHashTable[i] = NULL;
+ }
+}
+
+int getHash(char *key)
+{
+ int len;
+ int ret;
+
+ // 0文字目、最後の文字、真中の文字の数値を加算し
+ len = strlen(key);
+ ret = key[0];
+ ret += key[len-1];
+ ret += key[(len-1)/2];
+
+ // ハッシュテーブルのサイズ(山の数)で modulo する
+ return ret % NAME_HASHSIZE;
+}
+
+
+
+
+
+void NameTable_set_heap_id(char *key, VALUE heap, IDTYPE id) {
+ int hash;
+ NameList *add;
+ hash = getHash(key);
+
+ if (NameHashTable[hash] == NULL) { // もしハッシュテーブルが空ならば
+ add = NameList_new(); // データノードを作成
+
+ add->name = key;
+ add->id = id;
+ IdTable_set_name(id, key);
+ add->heap = heap;
+ add->next = NULL;
+
+ NameHashTable[hash] = add; /* 単にセット */
+ }
+
+
+ /* 線形探査 */
+ NameList *at = NameHashTable[hash]; /* 先頭をセット */
+ while (at != NULL) {
+ if(strcmp( at->name, key ) == 0) { /* すでにあれば... */
+ at->id = id;
+ IdTable_set_name(at->id, key);
+ at->heap = heap;
+ return;
+
+ }
+ at = at->next; /* 次のチェーンを辿る */
+ }
+
+
+ /* key がなかったら、 先頭に追加 */
+ add = NameList_new();
+
+ add->name = key;
+ add->id = id;
+ IdTable_set_name(add->id, key);
+ add->heap = heap;
+
+ add->next = NameHashTable[hash]; // 以前の先頭を自分の次にする
+ NameHashTable[hash] = add; // add を先頭とする
+
+ return;
+}
+
+
+
+
+// NameHashTable から key のエントリーを削除
+void NameTable_erase(char *key) {
+ int hash;
+ //int heap;
+ //NameList *add;
+
+ if (key == NULL) return;
+
+ hash = getHash(key);
+
+ if (NameHashTable[hash] == NULL) { // ハッシュテーブルが空ならば何もしない
+ return;
+ }
+
+ /* 線形探査 */
+ NameList *at = NameHashTable[hash]; /* 先頭をセット */
+ while (at != NULL) {
+ if (strcmp(at->name, key) == 0) { /* すでにあれば... */
+ at->heap = (VALUE)NULL;
+ at->id = -1; // 登録削除したら ID を -1 にする
+ // これを削ると、10%の速度低下。なぜ?
+
+ return;
+
+ }
+ at = at->next; /* 次のチェーンを辿る */
+ }
+
+ return;
+}
+
+
+
+VALUE NameTable_get_heap(char *key) {
+ int hash;
+ //int heap;
+ //NameList *add;
+ hash = getHash(key);
+
+ if (NameHashTable[hash] == NULL) {
+ // ハッシュテーブルが空
+ return (VALUE)NULL;
+ }
+
+ // 線形探査
+ NameList *at = NameHashTable[hash]; // 先頭をセット
+ while (at != NULL) {
+ if (strcmp( at->name, key ) == 0) { // すでにあれば
+
+ if (at->heap != (VALUE)NULL) {
+ // NULLP でなければ、既に存在している変数
+ return at->heap;
+
+ } else {
+ return (VALUE)NULL;
+
+ }
+ }
+ at = at->next; // 次のチェーンを辿る
+ }
+
+ // key がなかった
+ return (VALUE)NULL;
+
+}
+
+
+IDTYPE NameTable_get_set_id(char *key) {
+ int hash;
+ NameList *add;
+
+
+ hash = getHash(key);
+
+ if (NameHashTable[hash] == NULL) {
+ // ハッシュテーブルが空
+ add = NameList_new(); // データノードを作成
+ add->name = key;
+ add->id = IdTable_new_agentid();
+ IdTable_set_name(add->id, add->name);
+ add->heap = (VALUE)NULL;
+ add->next = NULL;
+ NameHashTable[hash] = add; // 単にセット
+ return (add->id);
+
+ }
+
+ // 線形探査
+ NameList *at = NameHashTable[hash]; // 先頭をセット
+ while (at != NULL) {
+ if (strcmp(at->name, key) == 0) { // すでにあれば
+ return (at->id);
+
+ }
+ at = at->next; // 次のチェーンを辿る
+ }
+
+ // key がなかったら→ 先頭に追加
+ add = NameList_new();
+ add->name = key;
+ add->id = IdTable_new_agentid();
+ IdTable_set_name(add->id, add->name);
+ add->heap = (VALUE)NULL;
+ add->next = NameHashTable[hash]; // 以前の先頭を自分の次にする
+ NameHashTable[hash] = add; // 先頭に追加
+
+ return (add->id);
+}
+
+
+
+// Whether the given 'term' has a name node 'keynode'.
+int term_has_keynode(VALUE keynode, VALUE term) {
+ int i;
+
+ if ((term == (VALUE)NULL) || (IS_FIXNUM(term))) return 0;
+
+ //puts_term(term);
+ //puts("");
+
+ if (IS_NAMEID(BASIC(term)->id)) {
+
+ if (term == keynode) {
+ return 1;
+ } else {
+ if (NAME(term)->port == (VALUE)NULL) {
+ return 0;
+ } else {
+ return term_has_keynode(keynode, NAME(term)->port);
+ }
+ }
+
+ } else {
+ // general term
+ int arity;
+ arity = IdTable_get_arity(AGENT(term)->basic.id);
+ for (i=0; i < arity; i++) {
+ if (term_has_keynode(keynode, AGENT(term)->port[i]) ) {
+ return 1;
+ }
+ }
+ return 0;
+ }
+}
+
+
+int keynode_exists_in_another_term(VALUE keynode, VALUE *connected_from) {
+ // It returns how many occurs in terms connected from global names.
+ // Also, the one of the terms is stored in the 'connected_from'.
+ int i, result=0;
+ NameList *at;
+
+ for (i=0; i<NAME_HASHSIZE; i++) {
+ at = NameHashTable[i];
+ while (at != NULL) {
+ if (at->heap != (VALUE)NULL) {
+ if (at->heap != keynode) {
+ if (term_has_keynode(keynode, at->heap)) {
+ result++;
+ if (connected_from != NULL) {
+ *connected_from = at->heap;
+ }
+ /*
+ PutIndirection=1;
+ puts_name(at->heap);
+ puts("");
+ PutIndirection=0;
+ */
+ }
+ }
+ }
+ at = at->next;
+ }
+ }
+ return result;
+}
+
+
+
+
+VALUE replace_keynode(VALUE keynode, VALUE term, VALUE heap) {
+
+ if ((heap == (VALUE)NULL) || (IS_FIXNUM(heap))) {
+ return heap;
+ }
+
+ if (IS_GNAMEID(BASIC(heap)->id)) {
+ if (keynode == heap) {
+ return term;
+ }
+ }
+
+ if (IS_NAMEID(BASIC(heap)->id)) {
+ if (NAME(heap)->port == (VALUE)NULL) {
+ return heap;
+ } else {
+ NAME(heap)->port = replace_keynode(keynode, term, NAME(heap)->port);
+ return heap;
+ }
+ }
+
+ // general heap
+ int i, arity;
+ arity = IdTable_get_arity(AGENT(heap)->basic.id);
+ for (i=0; i < arity; i++) {
+ AGENT(heap)->port[i] = replace_keynode(keynode, term, AGENT(heap)->port[i]);
+ }
+ return heap;
+}
+
+
+
+void global_replace_keynode_in_another_term(VALUE keynode, VALUE term) {
+ // Replace keynode in Global environment with term.
+ int i;
+ NameList *at;
+
+ for (i=0; i<NAME_HASHSIZE; i++) {
+ at = NameHashTable[i];
+ while (at != NULL) {
+ if (at->heap != (VALUE)NULL) {
+ if (at->heap != keynode) {
+
+ if (term_has_keynode(keynode, at->heap)) {
+
+ VALUE replaced = replace_keynode(keynode, term, at->heap);
+ at->heap = replaced;
+
+ return;
+ }
+ }
+ }
+ at = at->next;
+ }
+ }
+}
+
+
+
+
+void NameTable_puts_all() {
+ int i;
+ NameList *at;
+ int count=0;
+
+ for (i=0; i<NAME_HASHSIZE; i++) {
+ at = NameHashTable[i];
+ while (at != NULL) {
+ if (at->heap != (VALUE)NULL) {
+ if (IS_NAMEID(BASIC(at->heap)->id)) {
+ printf("%s ", IdTable_get_name(BASIC(at->heap)->id));
+ count++;
+ }
+ }
+ at = at->next;
+ }
+ }
+ if (count == 0) {
+ printf("<NO-INTERFACE>\n");
+ return;
+ }
+
+ printf("\n\nConnections:\n");
+
+ for (i=0; i<NAME_HASHSIZE; i++) {
+ at = NameHashTable[i];
+ while (at != NULL) {
+ if (at->heap != (VALUE)NULL) {
+ if (IS_NAMEID(BASIC(at->heap)->id)) {
+ printf("%s ->", IdTable_get_name(BASIC(at->heap)->id));
+ puts_name_port0(at->heap);
+ printf("\n");
+ }
+ }
+ at = at->next;
+ }
+ }
+ puts("");
+}
+
+
+void NameTable_free_all() {
+ int i;
+ NameList *at;
+
+ for (i=0; i<NAME_HASHSIZE; i++) {
+ at = NameHashTable[i];
+ while (at != NULL) {
+ if (at->heap != (VALUE)NULL) {
+ if (IS_NAMEID(BASIC(at->heap)->id)) {
+ flush_name_port0(at->heap);
+ }
+ }
+ at = at->next;
+ }
+ }
+}
+
+
+int NameTable_ckech_if_term_has_gname(VALUE term) {
+ int i;
+ NameList *at;
+ VALUE ptr;
+
+ for (i=0; i<NAME_HASHSIZE; i++) {
+ at = NameHashTable[i];
+ while (at != NULL) {
+ if (at->heap != (VALUE)NULL) {
+ ptr = at->heap;
+ while ((ptr != (VALUE)NULL) &&
+ (! IS_FIXNUM(ptr)) &&
+ (IS_NAMEID(BASIC(ptr)->id))) {
+
+
+ if (term_has_keynode(ptr, term)) {
+ return 1;
+ }
+
+ ptr = NAME(ptr)->port;
+
+ }
+
+ }
+ at = at->next;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/src/name_table.h b/src/name_table.h
new file mode 100644
index 0000000..c7f885d
--- /dev/null
+++ b/src/name_table.h
@@ -0,0 +1,50 @@
+#ifndef _NAME_TABLE_
+#define _NAME_TABLE_
+
+#include "mytype.h"
+#include "id_table.h"
+
+
+/**************************************
+ NAME TABLE
+**************************************/
+
+typedef struct NameList {
+ char *name; // KEY
+ IDTYPE id;
+
+ // `heap' stores a heap only of a global name,
+ // that is, is kept having NULL for other nodes, such as agents.
+ VALUE heap;
+
+ struct NameList *next;
+} NameList;
+
+#define NAME_HASHSIZE 127
+static NameList *NameHashTable[NAME_HASHSIZE]; /* ハッシュテーブル本体 */
+
+// It should be called at first, and never called after that.
+void NameTable_init();
+
+
+void NameTable_set_heap_id(char *key, VALUE heap, IDTYPE id);
+
+
+// Erace key entry from NameHashTable
+void NameTable_erase(char *key);
+
+
+VALUE NameTable_get_heap(char *key);
+IDTYPE NameTable_get_set_id(char *key);
+
+void NameTable_puts_all();
+void NameTable_free_all();
+
+int NameTable_ckech_if_term_has_gname(VALUE term);
+
+int term_has_keynode(VALUE keynode, VALUE term);
+int keynode_exists_in_another_term(VALUE keynode, VALUE *connected_from);
+void global_replace_keynode_in_another_term(VALUE keynode, VALUE term);
+
+
+#endif
diff --git a/src/timer.h b/src/timer.h
new file mode 100644
index 0000000..904bd6a
--- /dev/null
+++ b/src/timer.h
@@ -0,0 +1,31 @@
+//https://github.com/zuqqhi2/numerical_simulation/blob/master/multithread/laytrace/timer.h
+
+#ifndef _H_TIMER
+#define _H_TIMER
+
+#include <stdio.h>
+#include <sys/time.h>
+
+static inline
+unsigned long long gettimeval(void) {
+ struct timeval tv;
+ struct timezone tz;
+ gettimeofday(&tv, &tz);
+ return ((unsigned long long)tv.tv_sec)*1000000+tv.tv_usec;
+}
+
+static inline
+void start_timer(unsigned long long *startt) {
+ *startt = gettimeval();
+ return;
+}
+
+static inline
+unsigned long long stop_timer(unsigned long long *startt) {
+ unsigned long long stopt = gettimeval();
+ return (stopt>=*startt)?(stopt-*startt):(stopt);
+}
+
+#define print_timer(te) {printf("time of %s:%f[sec]\n", #te, (te*1.0e-3)/1000);}
+
+#endif