diff options
| author | Shinya Sato <shinnya.sato@gmail.com> | 2021-09-24 16:42:54 +0900 |
|---|---|---|
| committer | Shinya Sato <shinnya.sato@gmail.com> | 2021-09-24 16:42:54 +0900 |
| commit | 6b3075d90d945d5e7e8fd4d28284ffd99dbeb82e (patch) | |
| tree | 4d9e58166e36452bc3a19172d9cfb7a245f996b0 /src/inpla.y | |
| parent | dd62122ee43d2c388fb96518eaa527976fddfc38 (diff) | |
| download | inpla-6b3075d90d945d5e7e8fd4d28284ffd99dbeb82e.tar.gz inpla-6b3075d90d945d5e7e8fd4d28284ffd99dbeb82e.zip | |
v0.4.1
Diffstat (limited to '')
| -rw-r--r-- | src/inpla.y | 7606 |
1 files changed, 7606 insertions, 0 deletions
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" |
