protoverse

A metaverse protocol
git clone git://jb55.com/protoverse
Log | Files | Refs | README | LICENSE

commit 82618ad625d4d97f4ac7eaa61acd67e3aa4a9eb5
parent 030ce65562738498d7768f3f252450272a4147fc
Author: William Casarin <jb55@jb55.com>
Date:   Fri,  3 Jul 2020 08:11:14 -0700

initial describe code

This will be used for building natural language descriptions of
spaces, rooms and objects.

Diffstat:
MMakefile | 2+-
Mcursor.c | 11+++++++++++
Mcursor.h | 3+++
Adescribe.c | 196+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adescribe.h | 10++++++++++
Mparse.c | 8++++----
Mparse.h | 1+
Mprotoverse.c | 66++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msatoshis-citadel.space | 13++++++++-----
9 files changed, 284 insertions(+), 26 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,7 +1,7 @@ CFLAGS = -Wno-error=unused-function -O1 -g -std=c89 -Wall -Wextra -Werror -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Wdeclaration-after-statement -OBJS = io.o parse.o cursor.o +OBJS = io.o parse.o cursor.o describe.o protoverse: protoverse.c $(OBJS) $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ diff --git a/cursor.c b/cursor.c @@ -94,3 +94,14 @@ void *index_cursor(struct cursor *cursor, u16 index, int elem_size) return (void*)p; } + + +int push_sized_str(struct cursor *cursor, const char *str, int len) +{ + return push_data(cursor, (u8*)str, len); +} + +int push_str(struct cursor *cursor, const char *str) +{ + return push_data(cursor, (u8*)str, strlen(str)); +} diff --git a/cursor.h b/cursor.h @@ -21,4 +21,7 @@ int pull_data(struct cursor *cursor, unsigned char *data, int len); int pull_byte(struct cursor *cursor, unsigned char *c); int push_byte(struct cursor *cursor, unsigned char c); +int push_str(struct cursor *cursor, const char *str); +int push_sized_str(struct cursor *cursor, const char *str, int len); + #endif diff --git a/describe.c b/describe.c @@ -0,0 +1,196 @@ + +#include "describe.h" +#include <assert.h> +#include <stdio.h> + +#define ADJ_PUSHED 1 +#define ADJ_NOT_PUSHED 2 + +/* various functions used to describe the scene */ + +struct describe { + struct cell *cell; + struct parser *parsed; + struct cursor *strs; +}; + +static int push_adjective(struct cursor *strs, struct attribute *attr) +{ + int ok; + + switch (attr->type) { + case A_CONDITION: + ok = push_str(strs, " "); + if (!ok) return 0; + ok = push_sized_str(strs, attr->data.str.ptr, + attr->data.str.len); + if (!ok) return 0; + return ADJ_PUSHED; + default: + break; + } + + return ADJ_NOT_PUSHED; +} + +static int is_adjective(struct attribute *attr) +{ + return attr->type == A_CONDITION; +} + +static int count_adjectives(struct describe *desc) +{ + struct attribute *attr; + int count; + int i; + + for (i = 0, count = 0; i < desc->cell->n_attributes; i++) { + attr = get_attr(desc->parsed->attributes, + desc->cell->attributes[i]); + assert(attr); + + if (is_adjective(attr)) + count++; + } + + return count; +} + +static int push_adjectives(struct describe *desc) +{ + struct attribute *attr; + int i, ok, adjs, adj_count; + + adj_count = count_adjectives(desc); + + for (i = 0, adjs = 0; i < desc->cell->n_attributes; i++) { + attr = get_attr(desc->parsed->attributes, + desc->cell->attributes[i]); + assert(attr); + + if (!is_adjective(attr)) + continue; + + if (adjs > 0) { + if (adjs == adj_count-1) + push_str(desc->strs, " and"); + else if (adjs != adj_count-1) + push_str(desc->strs, ","); + + } + + ok = push_adjective(desc->strs, attr); + if (ok == ADJ_PUSHED) + adjs++; + } + + return 1; +} + +static int push_made_of(struct describe *desc) +{ + struct attribute *attr; + int i, ok; + + for (i = 0; i < desc->cell->n_attributes; i++) { + attr = get_attr(desc->parsed->attributes, + desc->cell->attributes[i]); + assert(attr); + + if (attr->type == A_MATERIAL) { + ok = push_str(desc->strs, " made of "); + if (!ok) return 0; + + ok = push_sized_str(desc->strs, + attr->data.str.ptr, + attr->data.str.len); + if (!ok) return 0; + return 1; + } + } + + return 2; +} + +static int push_named(struct describe *desc) +{ + const char *name; + int name_len; + int ok; + + cell_name(desc->parsed->attributes, desc->cell, &name, &name_len); + + if (name_len == 0) + return 1; + + ok = push_str(desc->strs, " named "); + if (!ok) return 0; + + ok = push_sized_str(desc->strs, name, name_len); + if (!ok) return 0; + + return 1; +} + +static int describe_room(struct describe *desc) +{ + int ok; + + /* TODO: temp buffers for determining a(n) things */ + ok = push_str(desc->strs, "a(n)"); + if (!ok) return 0; + + ok = push_adjectives(desc); + if (!ok) return 0; + + ok = push_str(desc->strs, " room"); + if (!ok) return 0; + + ok = push_made_of(desc); + if (!ok) return 0; + + ok = push_named(desc); + if (!ok) return 0; + + return 1; +} + +static int describe_group(struct describe *desc) +{ + (void)desc; + return 0; +} + +static int describe_object(struct describe *desc) +{ + (void)desc; + return 0; +} + +static int describe_space(struct describe *desc) +{ + (void)desc; + return 0; +} + +int describe_cell(struct cell *cell, struct parser *parsed, struct cursor *strbuf) +{ + struct describe desc; + + desc.cell = cell; + desc.parsed = parsed; + desc.strs = strbuf; + + switch (cell->type) { + case C_ROOM: + return describe_room(&desc); + case C_GROUP: + return describe_group(&desc); + case C_OBJECT: + return describe_object(&desc); + case C_SPACE: + return describe_space(&desc); + } + + return 1; +} diff --git a/describe.h b/describe.h @@ -0,0 +1,10 @@ + +#ifndef PROTOVERSE_DESCRIBE_H +#define PROTOVERSE_DESCRIBE_H + +#include "parse.h" + +int describe_cell(struct cell *cell, struct parser *parsed, struct cursor *strbuf); + + +#endif diff --git a/parse.c b/parse.c @@ -88,7 +88,7 @@ void make_token_cursor(u8 *start, u8 *end, struct token_cursor *cursor) memset(&cursor->err_data, 0, sizeof(cursor->err_data)); } -static struct attribute *get_attr(struct cursor *attributes, u16 index) +struct attribute *get_attr(struct cursor *attributes, u16 index) { return (struct attribute*)index_cursor(attributes, index, sizeof(struct attribute)); @@ -154,7 +154,7 @@ void print_cell(struct cursor *attributes, struct cell *cell) ? object_type_str(cell->obj_type) : cell_type_str(cell->type)); - print_attributes(attributes, cell); + /* print_attributes(attributes, cell); */ printf("\n"); } @@ -931,11 +931,11 @@ static int parse_attribute(struct token_cursor *tokens, struct attribute *attr) goto close; } - ok = parse_str_attr(&temp, attr, "material", A_MATERIAL, T_SYMBOL); + ok = parse_str_attr(&temp, attr, "material", A_MATERIAL, T_STRING); if (ok) goto close; /* TODO: parse multiple conditions */ - ok = parse_str_attr(&temp, attr, "condition", A_CONDITION, T_SYMBOL); + ok = parse_str_attr(&temp, attr, "condition", A_CONDITION, T_STRING); if (ok) goto close; ok = parse_str_attr(&temp, attr, "location", A_LOCATION, T_SYMBOL); diff --git a/parse.h b/parse.h @@ -133,5 +133,6 @@ const char *cell_type_str(enum cell_type); const char *object_type_str(enum object_type); int cell_name(struct cursor *attributes, struct cell *cell, const char** name, int *len); struct cell *get_cell(struct cursor *cells, u16 index); +struct attribute *get_attr(struct cursor *attributes, u16 index); #endif /* PROTOVERSE_PARSE_H */ diff --git a/protoverse.c b/protoverse.c @@ -1,6 +1,7 @@ #include "io.h" #include "parse.h" +#include "describe.h" #include <assert.h> @@ -46,38 +47,34 @@ static int print_cell_tree(struct parser *parser, u16 root, int depth) return 1; } -int main(int argc, const char *argv[]) { +static int parse_file(struct parser *parser, const char *filename, u16 *root) +{ + /* TODO: increase these limits */ static u8 file_buf[4096]; static u8 token_buf[2048]; - static u8 attrs_buf[4096]; + static u8 attrs_buf[sizeof(struct attribute) * 1024]; static u8 cells_buf[sizeof(struct cell) * 1024]; struct token_cursor tokens; struct cursor attributes; struct cursor cells; - struct parser parser; - size_t count; - const char *space; int ok; - u16 root; - - parser.tokens = &tokens; - parser.attributes = &attributes; - parser.cells = &cells; + parser->tokens = &tokens; + parser->attributes = &attributes; + parser->cells = &cells; make_cursor(cells_buf, cells_buf + sizeof(cells_buf), &cells); make_cursor(attrs_buf, attrs_buf + sizeof(attrs_buf), &attributes); make_token_cursor(token_buf, token_buf + sizeof(token_buf), &tokens); - space = argc == 2 ? argv[1] : "satoshis-citadel.space"; - ok = read_file(space, file_buf, sizeof(file_buf), &count); + ok = read_file(filename, file_buf, sizeof(file_buf), &count); if (!ok) { - printf("failed to load '%s'\n", space); - return 1; + printf("failed to load '%s'\n", filename); + return 0; } @@ -85,18 +82,55 @@ int main(int argc, const char *argv[]) { if (!ok) { printf("failed to tokenize\n"); - return 1; + return 0; } assert(tokens.c.p == token_buf); - ok = parse_cell(&parser, &root); + ok = parse_cell(parser, root); if (!ok) { print_token_error(&tokens); + return 0; } + return 1; +} + +static int describe(struct parser *parser, u16 root_cell) +{ + static char strbuf[2048]; + struct cursor strs; + struct cell *cell; + + strbuf[0] = 0; + + cell = get_cell(parser->cells, root_cell); + + make_cursor((u8*)strbuf, (u8*)strbuf + sizeof(strbuf), &strs); + + describe_cell(cell, parser, &strs); + + printf("\n\ndescription\n-----------\n\n%s\n", strbuf); + + return 1; +} + +int main(int argc, const char *argv[]) +{ + const char *space; + struct parser parser; + u16 root; + int ok; + + space = argc == 2 ? argv[1] : "satoshis-citadel.space"; + + ok = parse_file(&parser, space, &root); + if (!ok) return 1; + print_cell_tree(&parser, root, 0); + describe(&parser, root); + return 0; } diff --git a/satoshis-citadel.space b/satoshis-citadel.space @@ -1,17 +1,20 @@ (room (shape rectangle) - (name "Satoshi's Citadel") + (condition "clean") + (condition "shiny") + (material "solid gold") + (name "Satoshi's Den") (width 10) (depth 10) (height 100) (group (table (id welcome-desk) (name "welcome desk") - (material marble) - (condition clean) - (condition new) + (material "marble") + (condition "clean") + (condition "new") (width 1) (depth 2) (height 1) (location center) (light (name "desk"))) (chair (id welcome-desk-chair) - (name "welcome desk")) + (name "fancy")) (light (location ceiling) (shape circle))))