void buzzdict_set(buzzdict_t dt, const void* key, const void* data) { /* Hash the key */ uint32_t h = dt->hashf(key) % dt->num_buckets; /* Is the bucket empty? */ if(!dt->buckets[h]) { /* Create new entry list */ dt->buckets[h] = buzzdarray_new(1, sizeof(struct buzzdict_entry_s), NULL); /* Add entry */ buzzdict_entry_new(dt, e, key, data); buzzdarray_push(dt->buckets[h], &e); /* Increase size */ ++(dt->size); } else { /* Bucket not empty - is the entry present? */ uint32_t i; for(i = 0; i < buzzdarray_size(dt->buckets[h]); ++i) { const struct buzzdict_entry_s* e = &buzzdarray_get(dt->buckets[h], i, struct buzzdict_entry_s); if(dt->keycmpf(key, e->key) == 0) { /* Yes, destroy the entry */ dt->dstryf(e->key, e->data, dt); buzzdarray_remove(dt->buckets[h], i); --(dt->size); break; } } /* Add new entry */ buzzdict_entry_new(dt, e, key, data); buzzdarray_push(dt->buckets[h], &e); /* Increase size */ ++(dt->size); } }
void buzzmsg_serialize_u32(buzzdarray_t buf, uint32_t data) { uint32_t x = htonl(data); buzzdarray_push(buf, (uint8_t*)(&x)); buzzdarray_push(buf, (uint8_t*)(&x)+1); buzzdarray_push(buf, (uint8_t*)(&x)+2); buzzdarray_push(buf, (uint8_t*)(&x)+3); }
buzzvm_state buzzvm_call(buzzvm_t vm, int isswrm) { /* Get argument number and pop it */ buzzvm_stack_assert(vm, 1); buzzvm_type_assert(vm, 1, BUZZTYPE_INT); int32_t argn = buzzvm_stack_at(vm, 1)->i.value; buzzvm_pop(vm); /* Make sure the stack has enough elements */ buzzvm_stack_assert(vm, argn+1); /* Make sure the closure is where expected */ buzzvm_type_assert(vm, argn+1, BUZZTYPE_CLOSURE); buzzobj_t c = buzzvm_stack_at(vm, argn+1); /* Make sure that that data about C closures is correct */ if((!c->c.value.isnative) && ((c->c.value.ref) >= buzzdarray_size(vm->flist))) { buzzvm_seterror(vm, BUZZVM_ERROR_FLIST, NULL); return vm->state; } /* Create a new local symbol list copying the parent's */ vm->lsyms = buzzvm_lsyms_new(isswrm, buzzdarray_clone(c->c.value.actrec)); buzzdarray_push(vm->lsymts, &(vm->lsyms)); /* Add function arguments to the local symbols */ int32_t i; for(i = argn; i > 0; --i) buzzdarray_push(vm->lsyms->syms, &buzzdarray_get(vm->stack, buzzdarray_size(vm->stack) - i, buzzobj_t)); /* Get rid of the function arguments */ for(i = argn+1; i > 0; --i) buzzdarray_pop(vm->stack); /* Pop unused self table */ buzzdarray_pop(vm->stack); /* Push return address */ buzzvm_pushi((vm), vm->pc); /* Make a new stack for the function */ vm->stack = buzzdarray_new(1, sizeof(buzzobj_t), NULL); buzzdarray_push(vm->stacks, &(vm->stack)); /* Jump to/execute the function */ if(c->c.value.isnative) { vm->oldpc = vm->pc; vm->pc = c->c.value.ref; } else buzzdarray_get(vm->flist, c->c.value.ref, buzzvm_funp)(vm); return vm->state; }
buzzvm_state buzzvm_pushl(buzzvm_t vm, int32_t addr) { buzzobj_t o = buzzheap_newobj(vm, BUZZTYPE_CLOSURE); o->c.value.isnative = 1; o->c.value.ref = addr; if(vm->lsyms) { int i; for(i = 0; i < buzzdarray_size(vm->lsyms->syms); ++i) buzzdarray_push(o->c.value.actrec, &buzzdarray_get(vm->lsyms->syms, i, buzzobj_t)); } else { buzzobj_t nil = buzzheap_newobj(vm, BUZZTYPE_NIL); buzzdarray_push(o->c.value.actrec, &nil); } return buzzvm_push(vm, o); }
buzzvm_state buzzvm_pushc(buzzvm_t vm, int32_t rfrnc, int32_t nat) { buzzobj_t o = buzzheap_newobj(vm, BUZZTYPE_CLOSURE); o->c.value.isnative = nat; o->c.value.ref = rfrnc; buzzobj_t nil = buzzheap_newobj(vm, BUZZTYPE_NIL); buzzdarray_push(o->c.value.actrec, &nil); buzzvm_push(vm, o); return vm->state; }
uint32_t buzzvm_function_register(buzzvm_t vm, buzzvm_funp funp) { /* Look for function pointer to avoid duplicates */ uint32_t fpos = buzzdarray_find(vm->flist, buzzvm_function_cmp, funp); if(fpos == buzzdarray_size(vm->flist)) { /* Add function to the list */ buzzdarray_push(vm->flist, &funp); } return fpos; }
buzzvm_state buzzvm_dup(buzzvm_t vm) { if(buzzdarray_isempty(vm->stack)) { buzzvm_seterror(vm, BUZZVM_ERROR_STACK, "empty stack"); return vm->state; } else { buzzobj_t x = buzzvm_stack_at(vm, 1); buzzdarray_push(vm->stack, &x); } return vm->state; }
buzzlex_t buzzlex_new(const char* fname) { /* The lexer corresponds to a stack of file information */ buzzlex_t x = buzzdarray_new(10, sizeof(struct buzzlex_file_s*), buzzlex_file_destroy); /* Read file */ buzzlex_file_t f = buzzlex_file_new(fname); if(!f) return NULL; buzzdarray_push(x, &f); /* Return the lexer state */ return x; }
void buzzmsg_serialize_string(buzzdarray_t buf, const char* data) { /* Get the length of the string */ uint16_t len = strlen(data); /* Push that into the buffer */ buzzmsg_serialize_u16(buf, len); /* Go through the characters and push them into the buffer */ const char* c = data; while(*c) { buzzdarray_push(buf, (uint8_t*)(c)); ++c; } }
buzzvm_state buzzvm_tput(buzzvm_t vm) { buzzvm_stack_assert(vm, 3); buzzvm_type_assert(vm, 3, BUZZTYPE_TABLE); buzzobj_t v = buzzvm_stack_at(vm, 1); buzzobj_t k = buzzvm_stack_at(vm, 2); buzzobj_t t = buzzvm_stack_at(vm, 3); buzzvm_pop(vm); buzzvm_pop(vm); buzzvm_pop(vm); if(k->o.type != BUZZTYPE_INT && k->o.type != BUZZTYPE_FLOAT && k->o.type != BUZZTYPE_STRING) { buzzvm_seterror(vm, BUZZVM_ERROR_TYPE, "a %s value can't be used as table key", buzztype_desc[k->o.type]); return vm->state; } if(v->o.type == BUZZTYPE_NIL) { /* Nil, erase entry */ buzzdict_remove(t->t.value, &k); } else if(v->o.type == BUZZTYPE_CLOSURE) { /* Method call */ int i; buzzobj_t o = buzzheap_newobj(vm, BUZZTYPE_CLOSURE); o->c.value.isnative = v->c.value.isnative; o->c.value.ref = v->c.value.ref; buzzdarray_push(o->c.value.actrec, &t); for(i = 1; i < buzzdarray_size(v->c.value.actrec); ++i) buzzdarray_push(o->c.value.actrec, &buzzdarray_get(v->c.value.actrec, i, buzzobj_t)); buzzdict_set(t->t.value, &k, &o); } else { buzzdict_set(t->t.value, &k, &v); } return BUZZVM_STATE_READY; }
void buzzswarm_members_join(buzzswarm_members_t m, uint16_t robot, uint16_t swarm) { /* Is an entry for the passed robot already present? */ buzzswarm_elem_t* e = buzzdict_get(m, &robot, buzzswarm_elem_t); if(e) { /* Yes, update it */ (*e)->age = 0; /* Search for the passed id; if found, nothing to do */ uint32_t i; for(i = 0; i < buzzdarray_size((*e)->swarms); ++i) { if(buzzdarray_get((*e)->swarms, i, uint16_t) == swarm) return; } /* If we get here, it's because we got new information - add it */ buzzdarray_push((*e)->swarms, &swarm); } else { /* No, create it */ buzzswarm_elem_t ne = buzzswarm_elem_new(); buzzdarray_push(ne->swarms, &swarm); /* Add it to the structure */ buzzdict_set(m, &robot, &ne); } }
int buzzvm_swarm_exec(buzzvm_t vm) { buzzvm_lnum_assert(vm, 1); /* Get the id */ buzzvm_lload(vm, 0); buzzvm_pushs(vm, buzzvm_string_register(vm, "id")); buzzvm_tget(vm); uint16_t id = buzzvm_stack_at(vm, 1)->i.value; /* Get the swarm entry */ uint8_t* x = buzzdict_get(vm->swarms, &id, uint8_t); if(!x) { vm->state = BUZZVM_STATE_ERROR; vm->error = BUZZVM_ERROR_SWARM; return BUZZVM_STATE_ERROR; } /* Check whether the robot is in the swarm */ if(*x) { /* Get the closure */ buzzvm_lload(vm, 1); buzzvm_type_assert(vm, 1, BUZZTYPE_CLOSURE); buzzobj_t c = buzzvm_stack_at(vm, 1); /* Get rid of the current call structure */ if(buzzvm_ret0(vm) != BUZZVM_STATE_READY) return vm->state; /* Save the current stack depth */ uint32_t stacks = buzzdarray_size(vm->stacks); /* Push the current swarm in the stack */ buzzdarray_push(vm->swarmstack, &id); /* Call the closure */ buzzvm_push(vm, c); int32_t numargs = 0; buzzvm_pushi(vm, numargs); buzzvm_calls(vm); do if(buzzvm_step(vm) != BUZZVM_STATE_READY) return vm->state; while(stacks < buzzdarray_size(vm->stacks)); return vm->state; } else { /* Get rid of the current call structure */ return buzzvm_ret0(vm); } }
buzztok_t buzzlex_nexttok(buzzlex_t lex) { buzzlex_file_t lexf = buzzlex_getfile(lex); do { /* Look for a non-space character */ do { /* Keep reading until you find a non-space character or end of stream */ while(lexf->cur_c < lexf->buf_size && buzzlex_isspace(lexf->buf[lexf->cur_c])) { nextchar(); } /* End of stream? */ if(lexf->cur_c >= lexf->buf_size) { /* Done with current file, go back to previous */ buzzdarray_pop(lex); if(buzzdarray_isempty(lex)) /* No file to go back to, done parsing */ return NULL; lexf = buzzlex_getfile(lex); } else /* Non-space character found */ break; } while(1); /* Non-space character found */ /* If the current character is a '#' ignore the rest of the line */ if(lexf->buf[lexf->cur_c] == '#') { do { nextchar(); } while(lexf->cur_c < lexf->buf_size && lexf->buf[lexf->cur_c] != '\n'); /* End of stream? */ if(lexf->cur_c >= lexf->buf_size) { /* Done with current file, go back to previous */ buzzdarray_pop(lex); if(buzzdarray_isempty(lex)) /* No file to go back to, done parsing */ return NULL; lexf = buzzlex_getfile(lex); } else { /* New line and carry on */ ++lexf->cur_line; lexf->cur_col = 0; ++lexf->cur_c; } } else if(strncmp(lexf->buf + lexf->cur_c, "include", 7) == 0) { /* Manage file inclusion */ lexf->cur_c += 7; lexf->cur_col += 7; /* Skip whitespace */ while(lexf->cur_c < lexf->buf_size && buzzlex_isspace(lexf->buf[lexf->cur_c])) { nextchar(); } /* End of file or not-string opening -> syntax error */ if(lexf->cur_c >= lexf->buf_size || !buzzlex_isquote(lexf->buf[lexf->cur_c])) { fprintf(stderr, "%s:%" PRIu64 ":%" PRIu64 ": Syntax error: expected string after include\n", lexf->fname, lexf->cur_line, lexf->cur_col); return NULL; } /* Read string */ char quote = lexf->buf[lexf->cur_c]; size_t start = lexf->cur_c + 1; nextchar(); while(lexf->cur_c < lexf->buf_size && lexf->buf[lexf->cur_c] != quote && lexf->buf[lexf->cur_c] != '\n') { nextchar(); } /* End of file or newline -> syntax error */ if(lexf->cur_c >= lexf->buf_size || lexf->buf[lexf->cur_c] == '\n') { fprintf(stderr, "%s:%" PRIu64 ":%" PRIu64 ": Syntax error: expected end of string\n", lexf->fname, lexf->cur_line, lexf->cur_col); return NULL; } /* Copy data into a new string */ char* fname = (char*)malloc(lexf->cur_c - start + 1); strncpy(fname, lexf->buf + start, lexf->cur_c - start); fname[lexf->cur_c - start] = '\0'; /* Get to next character in this file */ nextchar(); /* Create new file structure */ buzzlex_file_t f = buzzlex_file_new(fname); if(!f) { fprintf(stderr, "%s:%" PRIu64 ":%" PRIu64 ": Can't read '%s'\n", lexf->fname, lexf->cur_line, lexf->cur_col, fname); free(fname); return NULL; } free(fname); /* Make sure the file hasn't been already included */ if(buzzdarray_find(lex, buzzlex_file_cmp, &f) < buzzdarray_size(lex)) { buzzlex_file_destroy(0, &f, NULL); } else { /* Push file structure */ buzzdarray_push(lex, &f); lexf = buzzlex_getfile(lex); } } else /* The character must be parsed */ break; } while(1); /* If we get here it's because we read potential token character */ uint64_t tokstart = lexf->cur_col - 1; char c = lexf->buf[lexf->cur_c]; nextchar(); /* Consider the 1-char non-alphanumeric cases first */ switch(c) { case '\n': { buzztok_t tok = buzzlex_newtok(BUZZTOK_STATEND, NULL, lexf->cur_line, tokstart, lexf->fname); ++lexf->cur_line; lexf->cur_col = 0; return tok; } casetokchar(';', BUZZTOK_STATEND); casetokchar('{', BUZZTOK_BLOCKOPEN); casetokchar('}', BUZZTOK_BLOCKCLOSE); casetokchar('(', BUZZTOK_PAROPEN); casetokchar(')', BUZZTOK_PARCLOSE); casetokchar('[', BUZZTOK_IDXOPEN); casetokchar(']', BUZZTOK_IDXCLOSE); casetokchar(',', BUZZTOK_LISTSEP); casetokchar('.', BUZZTOK_DOT); } /* If we get here, it's because we found either a constant, an * identifier, a keyword, an assignment, a comparison operator, * an arithmetic operator, or an unexpected character */ if(isdigit(c)) { /* It's a constant */ readval(buzzlex_isnumber); return buzzlex_newtok(BUZZTOK_CONST, val, lexf->cur_line, tokstart, lexf->fname); } else if(isalpha(c)) { /* It's either a keyword or an identifier */ readval(buzzlex_isid); /* Go through the possible keywords */ checkkeyword("var", BUZZTOK_VAR); checkkeyword("if", BUZZTOK_IF); checkkeyword("else", BUZZTOK_ELSE); checkkeyword("function", BUZZTOK_FUN); checkkeyword("return", BUZZTOK_RETURN); checkkeyword("for", BUZZTOK_FOR); checkkeyword("while", BUZZTOK_WHILE); checkkeyword("and", BUZZTOK_ANDOR); checkkeyword("or", BUZZTOK_ANDOR); checkkeyword("not", BUZZTOK_NOT); checkkeyword("nil", BUZZTOK_NIL); /* No keyword found, consider it an id */ return buzzlex_newtok(BUZZTOK_ID, val, lexf->cur_line, tokstart, lexf->fname); } else if(c == '=') { /* Either an assignment or a comparison */ if(lexf->cur_c < lexf->buf_size && lexf->buf[lexf->cur_c] == '=') { /* It's a comparison */ nextchar(); return buzzlex_newtok(BUZZTOK_CMP, strdup("=="), lexf->cur_line, tokstart, lexf->fname); } else { /* It's an assignment */ return buzzlex_newtok(BUZZTOK_ASSIGN, NULL, lexf->cur_line, tokstart, lexf->fname); } } else if(c == '!') { /* Comparison operator? */ if(lexf->cur_c < lexf->buf_size && lexf->buf[lexf->cur_c] == '=') { /* It's a comparison */ nextchar(); return buzzlex_newtok(BUZZTOK_CMP, strdup("!="), lexf->cur_line, tokstart, lexf->fname); } else { /* Syntax error */ fprintf(stderr, "%s:%" PRIu64 ":%" PRIu64 ": Syntax error: expected '=' after '!'\n", lexf->fname, lexf->cur_line, tokstart); return NULL; } } else if((c == '<') || (c == '>')) { /* It's a comparison operator */ size_t start = lexf->cur_c - 1; /* Include the '=' if present */ if(lexf->cur_c < lexf->buf_size && lexf->buf[lexf->cur_c] == '=') { nextchar(); } char* val = (char*)malloc(lexf->cur_c - start + 1); strncpy(val, lexf->buf + start, lexf->cur_c - start); val[lexf->cur_c - start] = 0; return buzzlex_newtok(BUZZTOK_CMP, val, lexf->cur_line, tokstart, lexf->fname); } else if(buzzlex_isarith(c)) { /* Arithmetic operator */ char* val = (char*)malloc(2); strncpy(val, lexf->buf + lexf->cur_c - 1, 1); val[1] = 0; switch(c) { case '+': case '-': { return buzzlex_newtok(BUZZTOK_ADDSUB, val, lexf->cur_line, tokstart, lexf->fname); } case '*': case '/': { return buzzlex_newtok(BUZZTOK_MULDIV, val, lexf->cur_line, tokstart, lexf->fname); } case '%': { return buzzlex_newtok(BUZZTOK_MOD, val, lexf->cur_line, tokstart, lexf->fname); } case '^': { return buzzlex_newtok(BUZZTOK_POW, val, lexf->cur_line, tokstart, lexf->fname); } default: return NULL; } } else if(buzzlex_isquote(c)) { /* String - eat any character until you find the next matching quote */ size_t start = lexf->cur_c; char last1 = 0, last2 = 0; while(lexf->cur_c < lexf->buf_size && /* Not end of stream */ ((lexf->buf[lexf->cur_c] != c) || /* Matching quote not found */ (lexf->buf[lexf->cur_c] == c && /* Matching quote found, but preceded by \ and not \\ */ last1 == '\\' && last2 != '\\'))) { /* Remember the last two characters read */ last2 = last1; last1 = lexf->buf[lexf->cur_c]; /* Keep parsing the string */ if(lexf->buf[lexf->cur_c] != '\n') { nextchar(); } else { fprintf(stderr, "%s:%" PRIu64 ":%" PRIu64 ": Syntax error: string closing quote not found\n", lexf->fname, lexf->cur_line, tokstart); return NULL; } } /* End of stream? Syntax error */ if(lexf->cur_c >= lexf->buf_size) { fprintf(stderr, "%s:%" PRIu64 ":%" PRIu64 ": Syntax error: string closing quote not found\n", lexf->fname, lexf->cur_line, tokstart); return NULL; } /* We have a valid string */ char* val = buzzlex_newstring(lexf->buf + start, lexf->cur_c - start); nextchar(); return buzzlex_newtok(BUZZTOK_STRING, val, lexf->cur_line, tokstart, lexf->fname); } else { /* Unknown character */ fprintf(stderr, "%s:%" PRIu64 ":%" PRIu64 ": Syntax error: unknown character '%c' (octal: %o; hex: %x)\n", lexf->fname, lexf->cur_line, tokstart, c, c, c); return NULL; } }
void buzzmsg_serialize_u16(buzzdarray_t buf, uint16_t data) { uint16_t x = htons(data); buzzdarray_push(buf, (uint8_t*)(&x)); buzzdarray_push(buf, (uint8_t*)(&x)+1); }
void buzzmsg_serialize_u8(buzzdarray_t buf, uint8_t data) { buzzdarray_push(buf, &data); }
buzzvm_state buzzvm_push(buzzvm_t vm, buzzobj_t v) { buzzdarray_push(vm->stack, &v); return vm->state; }
buzzvm_t buzzvm_new(uint16_t robot) { /* Create VM state. calloc() takes care of zeroing everything */ buzzvm_t vm = (buzzvm_t)calloc(1, sizeof(struct buzzvm_s)); /* Create stacks */ vm->stacks = buzzdarray_new(BUZZVM_STACKS_INIT_CAPACITY, sizeof(buzzdarray_t), buzzvm_darray_destroy); vm->stack = buzzdarray_new(BUZZVM_STACK_INIT_CAPACITY, sizeof(buzzobj_t), NULL); buzzdarray_push(vm->stacks, &(vm->stack)); /* Create local variable tables */ vm->lsymts = buzzdarray_new(BUZZVM_LSYMTS_INIT_CAPACITY, sizeof(buzzvm_lsyms_t), buzzvm_lsyms_destroy); vm->lsyms = NULL; /* Create global variable tables */ vm->gsyms = buzzdict_new(BUZZVM_SYMS_INIT_CAPACITY, sizeof(int32_t), sizeof(buzzobj_t), buzzdict_int32keyhash, buzzdict_int32keycmp, NULL); /* Create string list */ vm->strings = buzzstrman_new(); /* Create heap */ vm->heap = buzzheap_new(); /* Create function list */ vm->flist = buzzdarray_new(20, sizeof(buzzvm_funp), NULL); /* Create swarm list */ vm->swarms = buzzdict_new(10, sizeof(uint16_t), sizeof(uint8_t), buzzdict_uint16keyhash, buzzdict_uint16keycmp, NULL); /* Create swarm stack */ vm->swarmstack = buzzdarray_new(10, sizeof(uint16_t), NULL); /* Create swarm member structure */ vm->swarmmembers = buzzswarm_members_new(); vm->swarmbroadcast = SWARM_BROADCAST_PERIOD; /* Create message queues */ vm->inmsgs = buzzinmsg_queue_new(); vm->outmsgs = buzzoutmsg_queue_new(robot); /* Create virtual stigmergy */ vm->vstigs = buzzdict_new(10, sizeof(uint16_t), sizeof(buzzvstig_t), buzzdict_uint16keyhash, buzzdict_uint16keycmp, buzzvm_vstig_destroy); /* Create virtual stigmergy */ vm->listeners = buzzdict_new(10, sizeof(uint16_t), sizeof(buzzobj_t), buzzdict_uint16keyhash, buzzdict_uint16keycmp, NULL); /* Take care of the robot id */ vm->robot = robot; /* Initialize empty random number generator (buzzvm_math takes care of creating it) */ vm->rngstate = NULL; vm->rngidx = 0; /* Return new vm */ return vm; }