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:
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))))