diff --git a/Akinator/makefile b/Akinator/makefile new file mode 100644 index 0000000..45b49cf --- /dev/null +++ b/Akinator/makefile @@ -0,0 +1,48 @@ +LDFLAGS := ../ttrack-lib/lib/ttrack-lib.a -lm +CFLAGS := \ + -Wall -Wextra \ + -g \ + -I../ttrack-lib/hdr + +DOCPATH := doc-html +OBJPATH := obj +SRCPATH := src +BINPATH := bin + +BINNAME := akinator +DOXCONF := doxygen + +run: $(BINPATH)/$(BINNAME) + ./$< + +build: $(BINPATH)/$(BINNAME) + +doc: $(DOCPATH) + +clean: + -rm -rf $(OBJPATH)/* + -rm -rf $(BINPATH)/* + -rm -rf $(DOCPATH) + + +_CFILES := $(wildcard $(SRCPATH)/*.c) +_HFILES := $(wildcard $(SRCPATH)/*.h) +_OFILES := $(patsubst $(SRCPATH)/%.c, $(OBJPATH)/%.o, $(_CFILES)) +_DFILES := $(patsubst $(SRCPATH)/%.c, $(OBJPATH)/%.d, $(_CFILES)) + +include $(_DFILES) + +$(DOCPATH): $(_CFILES) $(_HFILES) + doxygen $(DOXCONF) + +$(OBJPATH)/%.o: $(SRCPATH)/%.c + $(CC) -c $< -o $@ $(CFLAGS) + +$(OBJPATH)/%.d: $(SRCPATH)/%.c + $(CC) -MM $< | sed 's/.*:/$(OBJPATH)\/$*.o $(OBJPATH)\/$*.d:/g' > $@ + +$(BINPATH)/$(BINNAME): $(_OFILES) + $(CC) -o $@ $^ $(LDFLAGS) + +.PHONY: all clean doc build + diff --git a/Akinator/src/io.c b/Akinator/src/io.c new file mode 100644 index 0000000..500f2fc --- /dev/null +++ b/Akinator/src/io.c @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include "io.h" + +int const read_word(char buf[], size_t size) +{$_ + ASSERT(buf != NULL); + + size_t const LINEBUF_SIZE = 32; + char linebuf[LINEBUF_SIZE]; + + if(fgets(linebuf, LINEBUF_SIZE, stdin) == NULL) { + RETURN(0); + } + + size_t linebuf_len = strlen(linebuf); + if(linebuf[linebuf_len - 1] == '\n') { // whole line was read + linebuf[linebuf_len - 1] = ' '; + + char* space_pos = strchr(linebuf, ' '); + *space_pos = '\0'; + + size_t len = space_pos - linebuf + 1; + if(len > size) { + RETURN(0); + } + + memcpy(buf, linebuf, len); + RETURN(1); + } + else { // overflow, need to clear stdin + scanf("%*[^\n]"); + getc(stdin); + + RETURN(0); + } +$$ +} +int const read_line(char buf[], size_t size) +{$_ + ASSERT(buf != NULL); + + if(fgets(buf, size, stdin) == NULL) { + RETURN(0); + } + + size_t len = strlen(buf); + if(buf[len - 1] != '\n') { + scanf("%*[^\n]"); + getc(stdin); + + RETURN(0); + } + + buf[len - 1] = '\0'; + + RETURN(1); +$$ +} + +static void string_to_lower(char* string) +{$_ + ASSERT(string != NULL); + + for(; *string != '\0'; ++string) { + *string = (char)tolower((int)*string); + } +$$ +} + + +int const yes_or_no() +{$_ + for(;;) { + printf("Print \'yes\' if you are agree, \'no\' otherwise: "); + fflush(stdout); + + char buf[4]; + if(read_word(buf, 4)) { + string_to_lower(buf); + + if(strcmp(buf, "no") == 0) { + RETURN(0); + } + if(strcmp(buf, "yes") == 0) { + RETURN(1); + } + } + + } +$$ +} diff --git a/Akinator/src/io.h b/Akinator/src/io.h new file mode 100644 index 0000000..ab4fcff --- /dev/null +++ b/Akinator/src/io.h @@ -0,0 +1,10 @@ +#ifndef IO_H +#define IO_H + +#include + +int const read_word(char buf[], size_t size); +int const read_line(char buf[], size_t size); +int const yes_or_no(); + +#endif diff --git a/Akinator/src/main.c b/Akinator/src/main.c new file mode 100644 index 0000000..bb327d1 --- /dev/null +++ b/Akinator/src/main.c @@ -0,0 +1,228 @@ +#include +#include +#include +#include +#include + +#include "node.h" +#include "io.h" + +typedef enum { + TREE_ERR_OK, + TREE_ERR_LOOP, + TREE_ERR_NODE, + TREE_ERR_NULL, + + TREE_NERRORS +} tree_err_t; + +char const* tree_errstr(tree_err_t err) +{$_ + ASSERT(err >= 0 && err < TREE_NERRORS); + + char const* TABLE[TREE_NERRORS] = { + "ok", + "loop", + + }; + + RETURN(TABLE[err]); +$$ +} + +tree_err_t tree_check(node_t const* root) +{$_ + node_err_t node_err = node_check(root); + if(node_err != NODE_ERR_OK) { + switch(node_err) { + case NODE_ERR_LOOP: + RETURN(TREE_ERR_LOOP); + break; + + default: + RETURN(TREE_ERR_NODE); + break; + } + } + + if(root->lch == NULL) { + RETURN(TREE_ERR_OK); + } + + ((node_t*)root)->color = 1; + + tree_err_t lerr = tree_check(root->lch); + if(lerr != TREE_ERR_OK) { + ((node_t*)root)->color = 0; + RETURN(lerr); + } + + tree_err_t rerr = tree_check(root->rch); + if(rerr != TREE_ERR_OK) { + ((node_t*)root)->color = 0; + RETURN(rerr); + } + + ((node_t*)root)->color = 0; + + RETURN(TREE_ERR_OK); +} + +void tree__dump_body(node_t const* root) { + if(root != NULL) { + node_dump(root); + if(((node_t*)root)->color == 1) { + dump("cycle found\n"); + } + else { + ((node_t*)root)->color = 1; + tree__dump_body(root->lch); + tree__dump_body(root->rch); + ((node_t*)root)->color = 0; + } + } + +} + +void tree__dump(node_t const* root, char const* funcname, char const* filename, + size_t nline) +{$_ + tree_err_t err = tree_check(root); + dump("tree dump from %s (%s %i), reason %i (%s) {\n", + funcname, filename, nline, err, tree_errstr(err)); + + DUMP_DEPTH += 1; + tree__dump_body(root); + DUMP_DEPTH -= 1; + + dump("}\n"); +$$ +} + +#define tree_dump(root) \ + tree__dump(root, __func__, __FILE__, __LINE__) + +void tree__assert(node_t const* root, char const* funcname, char const* filename, + size_t nline) +{$_ + if(tree_check(root) != TREE_ERR_OK) { + tree__dump(root, funcname, filename, nline); + ASSERT(0); + } +$$ +} + +#define tree_assert(root) \ + tree__assert(root, __func__, __FILE__, __LINE__) + +void tree__traversal(node_t* node) +{$_ + if(node->lch == NULL) { + printf("Is it %s?\n", node->data); + fflush(stdout); + + int answer = yes_or_no(); + + if(answer == 0) { + node_t* node_answ = node_read_answer(); + node_t* node_question = node_read_question(NULL, NULL); + + node_question->lch = node_question; + node_question->rch = node_answ; + + node_swap(node_question, node); + } + else { + printf("That\'s cool!\n"); + fflush(stdout); + } + } + else { + printf("%s\n", node->data); + fflush(stdout); + + int answer = yes_or_no(); + + if(answer == 0) { + tree__traversal(node->lch); + } + else { + tree__traversal(node->rch); + } + } +$$ +} + +void tree_traversal(node_t* root) +{$_ + tree_assert(root); + tree__traversal(root); + tree_assert(root); +$$ +} + +void tree__free(node_t* root) +{$_ + if(root != NULL) { + tree__free(root->lch); + tree__free(root->rch); + node_free(root); + } +$$ +} + +void tree_free(node_t* root) +{$_ + tree_assert(root); + tree__free(root); +$$ +} + +int const tree__write(node_t const* root) +{$_ + if(root == NULL) { + size_t zero = 0; + RETURN( binbuf_write_value(size_t, zero) == BINBUF_ERR_OK ); + } + else { + size_t len = strlen(root->data); + + if(binbuf_write_value(size_t, len) == BINBUF_ERR_OK && + binbuf_write(root->data, len) == BINBUF_ERR_OK) { + RETURN( tree__write(root->lch) && tree__write(root->rch) ); + } + else { + RETURN(0); + } + } +$$ +} + +int const tree_write(node_t const* root, FILE* stream) +{$_ + tree_assert(root); + stream_assert(stream); + + if(tree__write(root) && binbuf_flushh(stream) == BINBUF_ERR_OK) { + binbuf_free(); + RETURN(1); + } + + RETURN(0); +$$ +} + +int main() { + node_t* root = node_make("dog", NULL, NULL); + while(1) { + printf("Do you want to play?\n"); + int answer = yes_or_no(); + + if(!answer) + break; + + tree_traversal(root); + } + + tree_free(root); +} diff --git a/Akinator/src/node.c b/Akinator/src/node.c new file mode 100644 index 0000000..df27664 --- /dev/null +++ b/Akinator/src/node.c @@ -0,0 +1,159 @@ +#include +#include +#include +#include +#include "node.h" +#include "io.h" + +static int const node__ch_ok(node_t const* lch, node_t const* rch) +{$_ + RETURN(!((lch == NULL) ^ (rch == NULL))); +$$ +} + +char const* node_errstr(node_err_t err) +{$_ + ASSERT(err >= 0 && err < NODE_NERRORS); + + char const* TABLE[NODE_NERRORS] = { + "ok", + "invalid pointers to child nodes", + "invalid data", + "node is null", + "loop" + }; + return TABLE[err]; +$$ +} + +node_err_t const node_check(node_t const* node) +{$_ + if(node == NULL) { RETURN(NODE_ERR_NULL); } + if(node->data == NULL) { RETURN(NODE_ERR_DATA); } + if(!node__ch_ok(node->lch, node->rch)) { RETURN(NODE_ERR_CHILDREN); } + if(node->color != 0) { RETURN(NODE_ERR_LOOP); } + RETURN(NODE_ERR_OK); +$$ +} + +void node__dump(node_t const* node, char const* funcname, char const* filename, + size_t nline) +{$_ + node_err_t err = node_check(node); + dump("node_t [%p] dump from %s (%s %zu), reason %i (%s) {\n", + funcname, filename, nline, node, err, node_errstr(err)); + + if(node != NULL) { + dump("\tdata [%p] = \'%s\'\n", node->data, node->data); + dump("\tlch = %p\n", node->lch); + dump("\trch = %p\n", node->rch); + + dump("\tcolor = %i\n", node->color); + } + dump("}\n"); +$$ +} + +void node__assert(node_t const* node, char const* funcname, char const* filename, + size_t nline) +{$_ + if(node_check(node) != NODE_ERR_OK) { + node__dump(node, funcname, filename, nline); + ASSERT_(!"invalid node", funcname, filename, nline); + } +$$ +} + +node_t* const node_make(char const* cdata, node_t* lch, node_t* rch) +{$_ + ASSERT(cdata != NULL); + ASSERT(node__ch_ok(lch, rch)); + + node_t* node = (node_t*)malloc(sizeof(node_t)); + if(node == NULL) { + RETURN(NULL); + } + + size_t dlen = strlen(cdata) + 1; + char* data = (char*)malloc(sizeof(char) * dlen); + if(data == NULL) { + free(node); + RETURN(NULL); + } + + memcpy(data, cdata, sizeof(char) * dlen); + + node->data = data; + node->lch = lch; + node->rch = rch; + + node->color = 0; + + node_assert(node); + + RETURN(node); +$$ +} +node_t* const node_read_answer() +{$_ + size_t const BUF_SIZE = 1024; + char buf[BUF_SIZE]; + do { + printf("Who is it? "); + fflush(stdout); + } while(!read_word(buf, BUF_SIZE)); + + node_t* node = node_make(buf, NULL, NULL); + + node_assert(node); + + RETURN(node); +$$ +} +node_t* const node_read_question(node_t* lch, node_t* rch) +{$_ + ASSERT(node__ch_ok(lch, rch)); + + size_t const BUF_SIZE = 1024; + char buf[BUF_SIZE]; + + do { + printf("What question? "); + fflush(stdout); + } while(!read_line(buf, BUF_SIZE)); + + node_t* node = node_make(buf, lch, rch); + + node_assert(node); + + RETURN(node); +$$ +} + +#define swap(type, x, y) \ + do { \ + type tmp = x; \ + x = y; \ + y = tmp; \ + } while(0) + +void node_swap(node_t* node1, node_t* node2) +{$_ + node_assert(node1); + node_assert(node2); + + swap(char*, node1->data, node2->data); + swap(node_t*, node1->lch, node2->lch); + swap(node_t*, node1->rch, node2->rch); + + node_assert(node1); + node_assert(node2); +$$ +} +void const node_free(node_t* node) +{$_ + node_assert(node); + free(node->data); + free(node); +$$ +} diff --git a/Akinator/src/node.h b/Akinator/src/node.h new file mode 100644 index 0000000..731967b --- /dev/null +++ b/Akinator/src/node.h @@ -0,0 +1,47 @@ +#ifndef NODE_H +#define NODE_H + +typedef struct node_s { + char* data; + struct node_s* lch; + struct node_s* rch; +#ifndef NDEBUG + int color; // dfs cycles check +#endif +} node_t; + +typedef enum { + NODE_ERR_OK, + NODE_ERR_CHILDREN, + NODE_ERR_DATA, + NODE_ERR_NULL, + NODE_ERR_LOOP, + + NODE_NERRORS +} node_err_t; + +char const* node_errstr(node_err_t err); + +node_err_t const node_check(node_t const* node); +void node__dump(node_t const* node, char const* funcname, char const* filename, + size_t nline); + +#define node_dump(node) \ + node__dump(node, __func__, __FILE__, __LINE__) + +void node__assert(node_t const* node, char const* funcname, char const* filename, + size_t nline); + +#define node_assert(node) \ + node__assert(node, __func__, __FILE__, __LINE__) + +node_t* const node_make(char const* cdata, node_t* lch, node_t* rch); +node_t* const node_read_answer(); +node_t* const node_read_question(node_t* lch, node_t* rch); + +void node_swap(node_t* node1, node_t* node2); + +void const node_free(node_t* node); + + +#endif diff --git a/Processor/disasm.asm b/AsmExamples/disasm.asm similarity index 100% rename from Processor/disasm.asm rename to AsmExamples/disasm.asm diff --git a/Processor/example.asm b/AsmExamples/example.asm similarity index 100% rename from Processor/example.asm rename to AsmExamples/example.asm diff --git a/Processor/example.bin b/AsmExamples/example.bin similarity index 100% rename from Processor/example.bin rename to AsmExamples/example.bin diff --git a/AsmExamples/makefile b/AsmExamples/makefile new file mode 100644 index 0000000..7b3699b --- /dev/null +++ b/AsmExamples/makefile @@ -0,0 +1,9 @@ +run: example.bin + ../Disassembler/bin/disassembler example.bin disasm.asm + ../Emulator/bin/emulator example.bin + +build: example.bin; + +example.bin: example.asm + ../Assembler/bin/assembler example.asm example.bin + diff --git a/Assembler/example.asm b/Assembler/example.asm new file mode 100644 index 0000000..a286741 --- /dev/null +++ b/Assembler/example.asm @@ -0,0 +1,51 @@ +call main +hlt + +sqr: + ; copy value to the stack twice + pop ax + push ax + push ax + + ; find sqr + mul + + ; that is all + ret + +; emtry point +main: + ; initialize counter and store it in bx + in + pop bx + + ; initialize max counter value and store it in cx + in + pop cx + +loop: + ; copy counter to the stack to compute sqr + push bx + call sqr + ; print sqr value + out + + ; copy counter to the stack to increment it + push bx + push 1 + ; increment counter + add + ; store counter in bx + pop bx + + ; test if counter less of equal to 10 + push bx + push cx + ; halt otherwise + jl exit + + ; keep counting squares + jmp loop + +exit: + ret diff --git a/Assembler/example.bin b/Assembler/example.bin new file mode 100644 index 0000000..16e1730 Binary files /dev/null and b/Assembler/example.bin differ diff --git a/Processor/Assembler/makefile b/Assembler/makefile similarity index 88% rename from Processor/Assembler/makefile rename to Assembler/makefile index c8c8072..8a2b564 100644 --- a/Processor/Assembler/makefile +++ b/Assembler/makefile @@ -1,15 +1,18 @@ LDFLAGS := \ - ../../ttrack-lib/lib/ttrack-lib.a \ + ../ttrack-lib/lib/ttrack-lib.a \ ../LibCommon/lib/libcommon.a \ -lm CFLAGS := \ -Wall -Wextra \ -g \ - -I../../ttrack-lib/hdr \ + -I../ttrack-lib/hdr \ -I../LibCommon/hdr \ -DSTACKTRACE +LIBS := \ + + DOCPATH := doc-html OBJPATH := obj SRCPATH := src @@ -19,7 +22,7 @@ BINNAME := assembler DOXCONF := doxygen run: $(BINPATH)/$(BINNAME) - + $(BINPATH)/$(BINNAME) example.asm example.bin build: $(BINPATH)/$(BINNAME) diff --git a/Processor/Assembler/src/cmdparsers.c b/Assembler/src/cmdparsers.c similarity index 65% rename from Processor/Assembler/src/cmdparsers.c rename to Assembler/src/cmdparsers.c index f200a40..fc34180 100644 --- a/Processor/Assembler/src/cmdparsers.c +++ b/Assembler/src/cmdparsers.c @@ -59,6 +59,90 @@ int CMD_PARSER_PEDANTIC_LABELS = 0; RETURN(cmd_parser_make_err(CMD_PARSER_ERRT_OK, NULL, 0)); \ } +// push 1 +// push ax +// push [ax+0] + +typedef enum { + CMD_ARG_VAL, + CMD_ARG_REG, + CMD_ARG_MEM, + CMD_ARG_INV +} cmd_arg_type_t; + +typedef struct { + cmd_arg_type_t type; + union { + double value; + struct { + regid_t regid; + offset_t offset; + }; + }; +} cmd_arg_t; + +cmd_arg_t cmd_parse_arg(char* arg) +{$_ + ASSERT(arg != NULL); + + cmd_arg_t res; + res.type = CMD_ARG_INV; + + if(arg[0] == '[') { + + arg[0] = '\0'; + ++arg; + + size_t l = strlen(arg); + if(arg[l - 1] == ']') { + arg[l - 1] = '\0'; + + char* pos = strchr(arg, '+'); + if(pos == NULL) { + RETURN(res); + } + + *pos = '\0'; + ++pos; + + regid_t regid = get_regid(arg); + if(regid == UCHAR_MAX) { + RETURN(res); + } + + offset_t offset; + if(sscanf(pos, "%hu", &offset) != 1) { + RETURN(res); + } + + res.type = CMD_ARG_MEM; + res.regid = regid; + res.offset = offset; + RETURN(res); + } + else { + RETURN(res); + } + } + + regid_t regid = get_regid(arg); + if(regid != UCHAR_MAX) { + res.type = CMD_ARG_REG; + res.regid = regid; + RETURN(res); + } + + double value; + if(sscanf(arg, "%lf", &value) == 1) { + res.type = CMD_ARG_VAL; + res.value = value; + RETURN(res); + } + + RETURN(res); +$$ +} + cmd_parser_err_t const cmd_push_parser(char const* args[], size_t nargs) {$_ ASSERT(args != NULL); @@ -67,27 +151,40 @@ cmd_parser_err_t const cmd_push_parser(char const* args[], size_t nargs) RETURN(cmd_parser_make_err(CMD_PARSER_ERRT_NARGS, NULL, 0)); } - regid_t regid = get_regid(args[0]); - if(regid != UCHAR_MAX) { - opcode_t opc = OPCODE_PUSHR; + cmd_arg_t arg = cmd_parse_arg((char*)args[0]); + opcode_t opc; + + switch(arg.type) { + case CMD_ARG_MEM: + opc = OPCODE_PUSHM; if(binbuf_write_value(opcode_t, opc) != BINBUF_ERR_OK || - binbuf_write_value(regid_t, regid) != BINBUF_ERR_OK) { + binbuf_write_value(regid_t, arg.regid) != BINBUF_ERR_OK || + binbuf_write_value(offset_t, arg.offset) != BINBUF_ERR_OK) { RETURN(cmd_parser_make_err(CMD_PARSER_ERRT_BINBUF, NULL, 0)); } - } - else { - opcode_t opc = OPCODE_PUSHV; - char* pend; - double v = strtod(args[0], &pend); // TODO: range check - if(v == HUGE_VAL || pend != args[0] + strlen(args[0])) { - RETURN(cmd_parser_make_err(CMD_PARSER_ERRT_ARGFMT, - "register or double value excepted", 0)); + break; + + case CMD_ARG_REG: + opc = OPCODE_PUSHR; + if(binbuf_write_value(opcode_t, opc) != BINBUF_ERR_OK || + binbuf_write_value(regid_t, arg.regid) != BINBUF_ERR_OK) { + RETURN(cmd_parser_make_err(CMD_PARSER_ERRT_BINBUF, NULL, 0)); } + break; + + case CMD_ARG_VAL: + opc = OPCODE_PUSHV; if(binbuf_write_value(opcode_t, opc) != BINBUF_ERR_OK || - binbuf_write_value(double, v) != BINBUF_ERR_OK) { + binbuf_write_value(double, arg.value) != BINBUF_ERR_OK) { RETURN(cmd_parser_make_err(CMD_PARSER_ERRT_BINBUF, NULL, 0)); } + break; + + default: + RETURN(cmd_parser_make_err(CMD_PARSER_ERRT_ARGFMT, "invalid argument", 0)); + break; } + RETURN(cmd_parser_make_err(CMD_PARSER_ERRT_OK, NULL, 0)); } @@ -101,17 +198,30 @@ cmd_parser_err_t const cmd_pop_parser(char const* args[], size_t nargs) } } else if(nargs == 1) { - regid_t regid = get_regid(args[0]); - if(regid != UCHAR_MAX) { - opcode_t opc = OPCODE_POPR; + cmd_arg_t arg = cmd_parse_arg((char*)args[0]); + opcode_t opc; + + switch(arg.type) { + case CMD_ARG_MEM: + opc = OPCODE_POPM; if(binbuf_write_value(opcode_t, opc) != BINBUF_ERR_OK || - binbuf_write_value(regid_t, regid) != BINBUF_ERR_OK) { + binbuf_write_value(regid_t, arg.regid) != BINBUF_ERR_OK || + binbuf_write_value(offset_t, arg.offset) != BINBUF_ERR_OK) { RETURN(cmd_parser_make_err(CMD_PARSER_ERRT_BINBUF, NULL, 0)); } - } - else { - RETURN(cmd_parser_make_err(CMD_PARSER_ERRT_ARGFMT, - "double value excepted", 0)); + break; + + case CMD_ARG_REG: + opc = OPCODE_POPR; + if(binbuf_write_value(opcode_t, opc) != BINBUF_ERR_OK || + binbuf_write_value(regid_t, arg.regid) != BINBUF_ERR_OK) { + RETURN(cmd_parser_make_err(CMD_PARSER_ERRT_BINBUF, NULL, 0)); + } + break; + + default: + RETURN(cmd_parser_make_err(CMD_PARSER_ERRT_ARGFMT, "invalid argument", 0)); + break; } } else { @@ -142,6 +252,9 @@ GEN_LABELED_PARSER(cmd_jge_parser, OPCODE_JGE); GEN_LABELED_PARSER(cmd_call_parser, OPCODE_CALL); GEN_LABELED_PARSER(cmd_jmp_parser, OPCODE_JMP); +GEN_TRIVIAL_PARSER(cmd_gpu_clear_parser, OPCODE_GPU_CLEAR); +GEN_TRIVIAL_PARSER(cmd_gpu_point_parser, OPCODE_GPU_POINT); + cmd_parser_t CMD_PARSERS[] = { { "hlt", cmd_hlt_parser }, { "push", cmd_push_parser }, @@ -164,6 +277,8 @@ cmd_parser_t CMD_PARSERS[] = { { "call", cmd_call_parser }, { "ret", cmd_ret_parser }, { "jmp", cmd_jmp_parser }, + { "gpu_clear", cmd_gpu_clear_parser }, + { "gpu_point", cmd_gpu_point_parser }, }; size_t CMD_PARSERS_COUNT = sizeof(CMD_PARSERS) / sizeof(CMD_PARSERS[0]); diff --git a/Processor/Assembler/src/cmdparsers.h b/Assembler/src/cmdparsers.h similarity index 100% rename from Processor/Assembler/src/cmdparsers.h rename to Assembler/src/cmdparsers.h diff --git a/Processor/Assembler/src/main.c b/Assembler/src/main.c similarity index 85% rename from Processor/Assembler/src/main.c rename to Assembler/src/main.c index 5f32c7d..20ae1b9 100644 --- a/Processor/Assembler/src/main.c +++ b/Assembler/src/main.c @@ -3,13 +3,19 @@ #include #include #include +#include +void signal_sigsegv(int _) { + stacktrace_print(stderr); + abort(); +} + #include "parser.h" int main(int argc, char* argv[]) {$_ - (void)argc; + signal(SIGSEGV, signal_sigsegv); if(argc != 3) { fprintf(stderr, "[ERROR] Expected \'assembler \'" @@ -24,7 +30,7 @@ int main(int argc, char* argv[]) exit(EXIT_FAILURE); } - if(!parser_init) { + if(!parser_init()) { exit(EXIT_FAILURE); } diff --git a/Processor/Assembler/src/parser.c b/Assembler/src/parser.c similarity index 100% rename from Processor/Assembler/src/parser.c rename to Assembler/src/parser.c diff --git a/Processor/Assembler/src/parser.h b/Assembler/src/parser.h similarity index 100% rename from Processor/Assembler/src/parser.h rename to Assembler/src/parser.h diff --git a/Processor/Assembler/src/tokenizer.c b/Assembler/src/tokenizer.c similarity index 89% rename from Processor/Assembler/src/tokenizer.c rename to Assembler/src/tokenizer.c index 901632b..fd2dc4e 100644 --- a/Processor/Assembler/src/tokenizer.c +++ b/Assembler/src/tokenizer.c @@ -26,7 +26,7 @@ char const* tokenizer_errstr(tokenizer_err_t errc) typedef struct { tokenizer_err_t err; char* text; - string_t* lines; + strv_t* lines; size_t nlines; size_t curline; } tokenizer_t; @@ -40,13 +40,13 @@ static tokenizer_err_t tokenizer__set_error(tokenizer_err_t err) static void tokenizer__remove_comments() {$_ - for(string_t* line = tokenizer.lines; line < tokenizer.lines + tokenizer.nlines; + for(strv_t* line = tokenizer.lines; line < tokenizer.lines + tokenizer.nlines; ++line) { - char* pos = memchr(line->first, ';', string_length(line)); + char* pos = memchr(strv_begin(line), ';', strv_len(line)); if(pos != NULL) { - line->last = pos; - *line->last = '\0'; + line->plast = pos; + *(char*)line->plast = '\0'; // <- a bit shitty... } } $$ @@ -76,6 +76,10 @@ tokenizer_err_t const tokenizer_init(FILE* file) RETURN(tokenizer__set_error(TOKENIZER_ERR_MEM)); } + for(size_t i = 0; i < tokenizer.nlines - 1; ++i) { + *(char*)(tokenizer.lines[i].plast) = '\0'; + } + tokenizer.curline = 0; tokenizer__remove_comments(); RETURN(TOKENIZER_ERR_OK); @@ -101,10 +105,10 @@ tokenizer_err_t const tokenizer_nextline(size_t max_args, char* args[], size_t* RETURN(tokenizer__set_error(TOKENIZER_ERR_EOF)); } - string_t* line = tokenizer.lines + tokenizer.curline; + strv_t* line = tokenizer.lines + tokenizer.curline; size_t nargs = 0; - char* pos = strtok(line->first, SPACES); + char* pos = strtok((char*)line->pfirst, SPACES); while(pos != NULL && nargs < max_args) { args[nargs++] = pos; diff --git a/Processor/Assembler/src/tokenizer.h b/Assembler/src/tokenizer.h similarity index 100% rename from Processor/Assembler/src/tokenizer.h rename to Assembler/src/tokenizer.h diff --git a/Processor/Disassembler/makefile b/Disassembler/makefile similarity index 93% rename from Processor/Disassembler/makefile rename to Disassembler/makefile index 2d4ca5d..d86d6ab 100644 --- a/Processor/Disassembler/makefile +++ b/Disassembler/makefile @@ -1,12 +1,12 @@ LDFLAGS := \ - ../../ttrack-lib/lib/ttrack-lib.a \ + ../ttrack-lib/lib/ttrack-lib.a \ ../LibCommon/lib/libcommon.a \ -lm CFLAGS := \ -Wall -Wextra \ -g \ - -I../../ttrack-lib/hdr \ + -I../ttrack-lib/hdr \ -I../LibCommon/hdr \ -DSTACKTRACE diff --git a/Processor/Disassembler/src/main.c b/Disassembler/src/disasm.c similarity index 68% rename from Processor/Disassembler/src/main.c rename to Disassembler/src/disasm.c index 1a8e5ca..b9aa043 100644 --- a/Processor/Disassembler/src/main.c +++ b/Disassembler/src/disasm.c @@ -1,9 +1,3 @@ -#ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wignored-qualifiers" -#endif - -#include -#include #include #include #include @@ -11,9 +5,11 @@ #include #include +#include "disasmerr.h" + #define MAX_LINE_LEN 1024 -typedef int const (*cmd_disassembler_f) (char* line); +typedef int const (*cmd_disassembler_f) (opcode_t opcode, size_t pos, char* line); typedef struct { opcode_t opcode; @@ -21,40 +17,56 @@ typedef struct { cmd_disassembler_f disasm; } cmd_disassembler_t; -int const cmd_disasm_trivial(char* line) +static int const cmd_disasm_trivial(opcode_t opcode, size_t pos, char* line) {$_ + (void)opcode; + (void)pos; + + ASSERT(line != NULL); *line = '\0'; RETURN(1); $$ } -int const cmd_disasm_reg(char* line) +static int const cmd_disasm_reg(opcode_t opcode, size_t pos, char* line) {$_ ASSERT(line != NULL); regid_t regid; - if(binbuf_read_value(regid_t, regid) != BINBUF_ERR_OK) { + binbuf_err_t err; + if((err = binbuf_read_value(regid_t, regid)) != BINBUF_ERR_OK) { + disasm_err_binbuf(opcode, pos, err); RETURN(0); } - char const* regname = get_regname(regid); - if(regname == NULL) { + + if(!regid_ok(regid)) { + disasm_err_invregid(opcode, pos, regid); RETURN(0); } + + char const* regname = get_regname(regid); + ASSERT(regname != NULL); + if(snprintf(line, MAX_LINE_LEN, regname) < 0) { + disasm_err_stdio(opcode, pos); RETURN(0); } RETURN(1); } -int const cmd_disasm_val(char* line) +static int const cmd_disasm_val(opcode_t opcode, size_t pos, char* line) {$_ ASSERT(line != NULL); double v; - if(binbuf_read_value(double, v) != BINBUF_ERR_OK) { + + binbuf_err_t err; + if((err = binbuf_read_value(double, v)) != BINBUF_ERR_OK) { + disasm_err_binbuf(opcode, pos, err); RETURN(0); } if(snprintf(line, MAX_LINE_LEN, "%lf", v) < 0) { + disasm_err_stdio(opcode, pos); RETURN(0); } RETURN(1); @@ -62,7 +74,7 @@ int const cmd_disasm_val(char* line) #define LABELNAME_LEN 10 -int const gen_labelname(char* name) +static int const gen_labelname(char* name) {$_ if(snprintf(name, LABELNAME_LEN, "L_%.6zu", labeldic_size()) < 0) { RETURN(0); @@ -70,27 +82,35 @@ int const gen_labelname(char* name) RETURN(1); } -int const cmd_disasm_label(char* line) +static int const cmd_disasm_label(opcode_t opcode, size_t pos, char* line) {$_ offset_t offset; - if(binbuf_read_value(offset_t, offset) != BINBUF_ERR_OK) { + binbuf_err_t err; + if((err = binbuf_read_value(offset_t, offset)) != BINBUF_ERR_OK) { + disasm_err_binbuf(opcode, pos, err); RETURN(0); } char const* labelname = NULL; if((labelname = labeldic_addrname((size_t)offset)) != NULL) { if(snprintf(line, MAX_LINE_LEN, labelname) < 0) { + disasm_err_stdio(opcode, pos); RETURN(0); } } else { char nlabelname[LABELNAME_LEN]; if(!gen_labelname(nlabelname)) { + disasm_err_stdio(opcode, pos); RETURN(0); } - if(labeldic_setaddr(nlabelname, (size_t)offset) != LABELDIC_ERR_OK) { + + labeldic_err_t lerr; + if((lerr = labeldic_setaddr(nlabelname, (size_t)offset)) != LABELDIC_ERR_OK) { + disasm_err_labeldic(opcode, pos, lerr); RETURN(0); } if(snprintf(line, MAX_LINE_LEN, nlabelname, (size_t)offset) < 0) { + disasm_err_stdio(opcode, pos); RETURN(0); } } @@ -124,7 +144,7 @@ cmd_disassembler_t cmd_disasms[OPCODES_COUNT] = { }; size_t const CMD_DISASMS_COUNT = sizeof(cmd_disasms) / sizeof(cmd_disasms[0]); -cmd_disassembler_t* const find_disasm(opcode_t opcode) +static cmd_disassembler_t* const find_disasm(opcode_t opcode) {$_ for(size_t i = 0; i < CMD_DISASMS_COUNT; ++i) { if(cmd_disasms[i].opcode == opcode) { @@ -144,10 +164,12 @@ int const disasm_pass(FILE* stream, int write) { cmd_disassembler_t* disasm = find_disasm(opcode); if(disasm == NULL) { - fprintf(stderr, "[ERROR] Unknown opcode %zu\n", (size_t)opcode); + disasm_err_invopcode(opcode, opcode_pos); + RETURN(0); + } + if(!disasm->disasm(opcode, opcode_pos, buf)) { RETURN(0); } - disasm->disasm(buf); if(write) { char const* name = labeldic_addrname(opcode_pos); @@ -158,6 +180,7 @@ int const disasm_pass(FILE* stream, int write) fprintf(stream, "\t%s %s\n", disasm->name, buf); } } + if(binbuf_error() == BINBUF_ERR_RANGE) { binbuf_clearerr(); RETURN(1); @@ -166,42 +189,3 @@ int const disasm_pass(FILE* stream, int write) } -int main(int argc, char* argv[]) -{$_ - if(argc != 3) { - fprintf(stderr, - "[ERROR] Excepted format \'disassembler \'\n"); - RETURN(EXIT_FAILURE); - } - - FILE* ifile = fopen(argv[1], "rb"); - if(ifile == NULL) { - fprintf(stderr, "[ERROR] File \'%s\' not found\n", argv[1]); - RETURN(EXIT_FAILURE); - } - - if(binbuf_initf(ifile) != BINBUF_ERR_OK) { - fclose(ifile); - fprintf(stderr, "[ERROR] Failed to read input file\n"); - RETURN(EXIT_FAILURE); - } - - fclose(ifile); - - binbuf_reset(); - - FILE* ofile = fopen(argv[2], "w"); - - disasm_pass(NULL, 0); - - binbuf_reset(); - disasm_pass(ofile, 1); - - fclose(ofile); - - labeldic_free(); - - binbuf_clearerr(); - binbuf_free(); -$$ -} diff --git a/Disassembler/src/disasm.h b/Disassembler/src/disasm.h new file mode 100644 index 0000000..def8dfc --- /dev/null +++ b/Disassembler/src/disasm.h @@ -0,0 +1,8 @@ +#ifndef DISASM_H +#define DISASM_H + +#include + +int const disasm_pass(FILE* stream, int write); + +#endif diff --git a/Disassembler/src/disasmerr.c b/Disassembler/src/disasmerr.c new file mode 100644 index 0000000..3ce1954 --- /dev/null +++ b/Disassembler/src/disasmerr.c @@ -0,0 +1,173 @@ +#include +#include "disasmerr.h" + +// ---------- DISASSEMBLER ERROR TYPE ---------- // + +int const disasm_errt_ok(disasm_errt_t errt) +{ + return errt >= 0 && errt < CMD_DISASM_NTYPES; +} +void disasm_errt_assert(disasm_errt_t errt) +{$_ + ASSERT(disasm_errt_ok(errt)); +$$ +} + +char const* disasm_errt_str(disasm_errt_t errt) +{$_ + disasm_errt_assert(errt); + + static char const* TABLE[CMD_DISASM_NTYPES] = { + "ok", + "error in the binary buffer", + "error in the label dictionary", + "invalid opcode", + "invalid offset", + "invalid register id", + "invalid value", + "stdio error" + }; + RETURN(TABLE[errt]); +} + +// ---------- DISASSEMBLER ERROR PROCESSING ----------- // + +static disasm_err_t ERROR = { CMD_DISASM_ERRT_OK }; + +void disasm_err_binbuf(opcode_t opcode, size_t pos, binbuf_err_t err) +{$_ + ERROR.type = CMD_DISASM_ERRT_BINBUF; + ERROR.opcode = opcode; + ERROR.pos = pos; + ERROR.binbuf_err = err; +$$ +} + +void disasm_err_labeldic(opcode_t opcode, size_t pos, labeldic_err_t err) +{$_ + ERROR.type = CMD_DISASM_ERRT_LABELDIC; + ERROR.opcode = opcode; + ERROR.pos = pos; + ERROR.labeldic_err = err; +$$ +} + +void disasm_err_invopcode(opcode_t opcode, size_t pos) +{$_ + ERROR.type = CMD_DISASM_ERRT_INVOPCODE; + ERROR.opcode = opcode; + ERROR.pos = pos; +$$ +} + +void disasm_err_invoffset(opcode_t opcode, size_t pos, offset_t offset) +{$_ + ERROR.type = CMD_DISASM_ERRT_INVOPCODE; + ERROR.opcode = opcode; + ERROR.pos = pos; + ERROR.offset = offset; +$$ +} + +void disasm_err_invregid(opcode_t opcode, size_t pos, regid_t regid) +{$_ + ERROR.type = CMD_DISASM_ERRT_INVOPCODE; + ERROR.opcode = opcode; + ERROR.pos = pos; + ERROR.regid = regid; +$$ +} + +void disasm_err_stdio(opcode_t opcode, size_t pos) +{$_ + ERROR.type = CMD_DISASM_ERRT_STDIO; + ERROR.opcode = opcode; + ERROR.pos = pos; +} + +disasm_err_t const disasm_err_get() +{$_ + RETURN(ERROR); +$$ +} + +void disasm_err_print(disasm_err_t err) +{$_ + disasm_errt_assert(err.type); + switch(err.type) { + case CMD_DISASM_ERRT_OK: + fprintf(stderr, "[DISASSEMBLER] All is ok at %zX (opcode %hhx)\n", + (size_t)err.pos, err.opcode); + break; + + case CMD_DISASM_ERRT_BINBUF: + fprintf(stderr, "[DISASSEMBLER] Error occured in the binary buffer " + "at %zX (opcode %hhx)\n", (size_t)err.pos, err.opcode); + switch(err.binbuf_err) { + case BINBUF_ERR_OK: + fprintf(stderr, "\t[BINBUF] All is ok\n"); + break; + + case BINBUF_ERR_MEM: + fprintf(stderr, "\t[BINBUF] Out of memory\n"); + break; + + default: + fprintf(stderr, "\t[BINBUF] Data corrupted\n"); + break; + } + break; + + case CMD_DISASM_ERRT_LABELDIC: + fprintf(stderr, "[DISASSEMBLER] Error occured in the label dictionary " + "at %zX (opcode %hhx)\n", (size_t)err.pos, err.opcode); + switch(err.labeldic_err) { + case LABELDIC_ERR_OK: + fprintf(stderr, "\t[LABELDIC] All is ok\n"); + break; + + case LABELDIC_ERR_OVERFLOW: + fprintf(stderr, "\t[LABELDIC] Too many labels\n"); + break; + + case LABELDIC_ERR_MEM: + fprintf(stderr, "\t[LABELDIC] Out of memory\n"); + break; + + default: + fprintf(stderr, "\t[LABELDIC] Data corrupted\n"); + + } + break; + + case CMD_DISASM_ERRT_INVOPCODE: + fprintf(stderr, "[DISASSEMBLER] Invalid opcode %hhx at %zX\n", + err.opcode, err.pos); + break; + + case CMD_DISASM_ERRT_INVOFFSET: + fprintf(stderr, "[DISASSEMBLER] Invalid offset %zX at %zX (opcode %hhx)\n", + (size_t)err.offset, (size_t)err.pos, err.opcode); + break; + + case CMD_DISASM_ERRT_INVREGID: + fprintf(stderr, "[DISASSEMBLER] Invalid register id %zX at %zX (opcode %hhx)\n", + (size_t)err.regid, (size_t)err.pos, err.opcode); + break; + + case CMD_DISASM_ERRT_STDIO: + fprintf(stderr, "[DISASSEMBLER] Error in stdio at %zX (opcode %hhx)\n", + (size_t)err.pos, err.opcode); + break; + + default: + break; + } +$$ +} + +void disasm_err_print_this() +{$_ + disasm_err_print(ERROR); +$$ +} diff --git a/Disassembler/src/disasmerr.h b/Disassembler/src/disasmerr.h new file mode 100644 index 0000000..a13b2eb --- /dev/null +++ b/Disassembler/src/disasmerr.h @@ -0,0 +1,55 @@ +#ifndef DISASMERR_H +#define DISASMERR_H +#include +#include +#include +#include +#include + +// ---------- DISASSEMBLER ERROR TYPE ---------- // + +typedef enum { + CMD_DISASM_ERRT_OK, + CMD_DISASM_ERRT_BINBUF, + CMD_DISASM_ERRT_LABELDIC, + CMD_DISASM_ERRT_INVOPCODE, + CMD_DISASM_ERRT_INVOFFSET, + CMD_DISASM_ERRT_INVREGID, + CMD_DISASM_ERRT_INVVALUE, + CMD_DISASM_ERRT_STDIO, + CMD_DISASM_NTYPES +} disasm_errt_t; + +int const disasm_errt_ok(disasm_errt_t errt); +void disasm_errt_assert(disasm_errt_t errt); +char const* disasm_errt_str(disasm_errt_t errt); + +// ---------- DISASSEMBLER ERROR PROCESSING ----------- // + +typedef struct { + disasm_errt_t type; + opcode_t opcode; + size_t pos; + union { + offset_t offset; + regid_t regid; + binbuf_err_t binbuf_err; + labeldic_err_t labeldic_err; + + }; +} disasm_err_t; + +void disasm_err_binbuf(opcode_t opcode, size_t pos, binbuf_err_t err); +void disasm_err_labeldic(opcode_t opcode, size_t pos, labeldic_err_t err); +void disasm_err_invopcode(opcode_t opcode, size_t pos); +void disasm_err_invoffset(opcode_t opcode, size_t pos, offset_t offset); +void disasm_err_invregid(opcode_t opcode, size_t pos, regid_t regid); +void disasm_err_stdio(opcode_t opcode, size_t pos); + +disasm_err_t const disasm_err_get(); + +void disasm_err_print(disasm_err_t err); +void disasm_err_print_this(); + + +#endif diff --git a/Disassembler/src/main.c b/Disassembler/src/main.c new file mode 100644 index 0000000..b671e48 --- /dev/null +++ b/Disassembler/src/main.c @@ -0,0 +1,57 @@ +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wignored-qualifiers" +#endif + +#include +#include +#include +#include +#include + +#include "disasm.h" +#include "disasmerr.h" + +int main(int argc, char* argv[]) +{$_ + if(argc != 3) { + fprintf(stderr, + "[ERROR] Excepted format \'disassembler \'\n"); + RETURN(0); + } + + FILE* ifile = fopen(argv[1], "rb"); + if(ifile == NULL) { + fprintf(stderr, "[ERROR] File \'%s\' not found\n", argv[1]); + RETURN(0); + } + + if(binbuf_initf(ifile) != BINBUF_ERR_OK) { + fclose(ifile); + fprintf(stderr, "[ERROR] Failed to read input file\n"); + RETURN(0); + } + + fclose(ifile); + + binbuf_reset(); + + FILE* ofile = fopen(argv[2], "w"); + + if(!disasm_pass(NULL, 0)) { + disasm_err_print_this(); + goto finish; + } + + binbuf_reset(); + if(!disasm_pass(ofile, 1)) { + disasm_err_print_this(); + goto finish; + } + +finish: // free all resources + fclose(ofile); + labeldic_free(); + binbuf_clearerr(); + binbuf_free(); +$$ +} diff --git a/Processor/Emulator/makefile b/Emulator/makefile similarity index 88% rename from Processor/Emulator/makefile rename to Emulator/makefile index 8355a2d..f6d6918 100644 --- a/Processor/Emulator/makefile +++ b/Emulator/makefile @@ -1,11 +1,15 @@ LDFLAGS := \ - ../../ttrack-lib/lib/ttrack-lib.a \ + ../ttrack-lib/lib/ttrack-lib.a \ ../LibCommon/lib/libcommon.a \ - -lm + -lm \ + -lsfml-window \ + -lsfml-graphics \ + -lsfml-system + CFLAGS := \ -Wall -Wextra \ -g \ - -I../../ttrack-lib/hdr \ + -I../ttrack-lib/hdr \ -I../LibCommon/hdr \ -DSTACKTRACE diff --git a/Processor/Emulator/src/main.c b/Emulator/src/main.c similarity index 90% rename from Processor/Emulator/src/main.c rename to Emulator/src/main.c index 3162660..2587c0f 100644 --- a/Processor/Emulator/src/main.c +++ b/Emulator/src/main.c @@ -28,9 +28,12 @@ #define EPS 1e-7 +#define MEM_SIZE 1024 + double regs[REGCNT]; stack_double_t stack; stack_size_t_t callstack; +double mem[MEM_SIZE]; int const cpu_init(char const* binfile) {$_ @@ -89,6 +92,13 @@ void cpu_free() return; \ } +#define MEM_CHECK() \ + if(regs[id] < 0 || (size_t)regs[id] + pos >= MEM_SIZE) { \ + fprintf(stderr, "segmentation violation\n"); \ + $$ \ + return; \ + } + void cpu_execute() {$_ opcode_t opcode; @@ -170,6 +180,14 @@ void cpu_execute() STACK_CHECK(stack_push(double, &stack, regs[id])); break; + case OPCODE_PUSHM: + BINBUF_CHECK(binbuf_read_value(regid_t, id)); + REGID_CHECK(); + BINBUF_CHECK(binbuf_read_value(offset_t, pos)); + MEM_CHECK(); + STACK_CHECK(stack_push(double, &stack, mem[(size_t)regs[id] + pos])); + break; + case OPCODE_POPV: STACK_CHECK(stack_pop(double, &stack, &op1)); break; @@ -180,6 +198,14 @@ void cpu_execute() STACK_CHECK(stack_pop(double, &stack, regs + id)); break; + case OPCODE_POPM: + BINBUF_CHECK(binbuf_read_value(regid_t, id)); + REGID_CHECK(); + BINBUF_CHECK(binbuf_read_value(offset_t, pos)); + MEM_CHECK(); + STACK_CHECK(stack_pop(double, &stack, mem + (size_t)regs[id] + pos)); + break; + case OPCODE_JMP: BINBUF_CHECK(binbuf_read_value(offset_t, pos)); BINBUF_CHECK(binbuf_seek((size_t)pos)); diff --git a/Processor/LibCommon/hdr/libcommon/labeldic.h b/LibCommon/hdr/libcommon/labeldic.h similarity index 100% rename from Processor/LibCommon/hdr/libcommon/labeldic.h rename to LibCommon/hdr/libcommon/labeldic.h diff --git a/Processor/LibCommon/src/opcodes.h b/LibCommon/hdr/libcommon/opcodes.h similarity index 82% rename from Processor/LibCommon/src/opcodes.h rename to LibCommon/hdr/libcommon/opcodes.h index d79e20d..468b89d 100644 --- a/Processor/LibCommon/src/opcodes.h +++ b/LibCommon/hdr/libcommon/opcodes.h @@ -27,6 +27,11 @@ typedef enum { OPCODE_JLE, // 14 OPCODE_CALL, // 15 OPCODE_RET, // 16 + OPCODE_PUSHM, + OPCODE_POPM, + + OPCODE_GPU_CLEAR, + OPCODE_GPU_POINT, OPCODES_COUNT } opcode_s; @@ -34,6 +39,8 @@ typedef enum { typedef unsigned char opcode_t; typedef unsigned short offset_t; +int const opcode_ok(opcode_t opcode); +void opcode_assert(opcode_t opcode); char const* opcode_str(opcode_t opcode); #endif diff --git a/Processor/LibCommon/hdr/libcommon/reginfo.h b/LibCommon/hdr/libcommon/reginfo.h similarity index 76% rename from Processor/LibCommon/hdr/libcommon/reginfo.h rename to LibCommon/hdr/libcommon/reginfo.h index 13e3d76..52aa7ad 100644 --- a/Processor/LibCommon/hdr/libcommon/reginfo.h +++ b/LibCommon/hdr/libcommon/reginfo.h @@ -7,6 +7,8 @@ typedef unsigned char regid_t; extern char const* regmap[]; +int const regid_ok(regid_t regid); +void regid_assert(regid_t regid); regid_t const get_regid(char const* regname); char const* const get_regname(regid_t regid); diff --git a/Processor/LibCommon/makefile b/LibCommon/makefile similarity index 100% rename from Processor/LibCommon/makefile rename to LibCommon/makefile diff --git a/Processor/LibCommon/src/labeldic.c b/LibCommon/src/labeldic.c similarity index 100% rename from Processor/LibCommon/src/labeldic.c rename to LibCommon/src/labeldic.c diff --git a/Processor/LibCommon/src/labeldic.h b/LibCommon/src/labeldic.h similarity index 100% rename from Processor/LibCommon/src/labeldic.h rename to LibCommon/src/labeldic.h diff --git a/Processor/LibCommon/src/opcodes.c b/LibCommon/src/opcodes.c similarity index 77% rename from Processor/LibCommon/src/opcodes.c rename to LibCommon/src/opcodes.c index 1d16943..cd951c9 100644 --- a/Processor/LibCommon/src/opcodes.c +++ b/LibCommon/src/opcodes.c @@ -1,6 +1,14 @@ #include #include "opcodes.h" +int const opcode_ok(opcode_t opcode) { + return opcode < OPCODES_COUNT; +} +void opcode_assert(opcode_t opcode) +{$_ + ASSERT(opcode_ok(opcode)); +$$ +} char const* opcode_str(opcode_t opcode) {$_ @@ -16,7 +24,7 @@ char const* opcode_str(opcode_t opcode) "лошадь", "раздупли", "грех", - "сероокись", // Carbon Oxide Sulphide + "сероокись", // Carbon Oxide Sulphide = cos "корень", "возложи", "возложи", @@ -56,7 +64,11 @@ char const* opcode_str(opcode_t opcode) "jge", "jle", "call", - "ret" + "ret", + "push", + "push", + "gpu_clear", + "gpu_point" }; #endif diff --git a/Processor/LibCommon/hdr/libcommon/opcodes.h b/LibCommon/src/opcodes.h similarity index 82% rename from Processor/LibCommon/hdr/libcommon/opcodes.h rename to LibCommon/src/opcodes.h index d79e20d..468b89d 100644 --- a/Processor/LibCommon/hdr/libcommon/opcodes.h +++ b/LibCommon/src/opcodes.h @@ -27,6 +27,11 @@ typedef enum { OPCODE_JLE, // 14 OPCODE_CALL, // 15 OPCODE_RET, // 16 + OPCODE_PUSHM, + OPCODE_POPM, + + OPCODE_GPU_CLEAR, + OPCODE_GPU_POINT, OPCODES_COUNT } opcode_s; @@ -34,6 +39,8 @@ typedef enum { typedef unsigned char opcode_t; typedef unsigned short offset_t; +int const opcode_ok(opcode_t opcode); +void opcode_assert(opcode_t opcode); char const* opcode_str(opcode_t opcode); #endif diff --git a/Processor/LibCommon/src/reginfo.c b/LibCommon/src/reginfo.c similarity index 73% rename from Processor/LibCommon/src/reginfo.c rename to LibCommon/src/reginfo.c index 902b0e7..5a6b390 100644 --- a/Processor/LibCommon/src/reginfo.c +++ b/LibCommon/src/reginfo.c @@ -10,6 +10,15 @@ char const* regmap[REGCNT] = { "dx" }; +int const regid_ok(regid_t regid) { + return regid < REGCNT; +} +void regid_assert(regid_t regid) +{$_ + ASSERT(regid_ok(regid)); +$$ +} + regid_t const get_regid(char const* regname) {$_ ASSERT(regname != NULL); @@ -22,8 +31,6 @@ regid_t const get_regid(char const* regname) } char const* const get_regname(regid_t regid) {$_ - if(regid >= REGCNT) { - RETURN(NULL); - } + regid_assert(regid); RETURN(regmap[regid]); } diff --git a/Processor/LibCommon/src/reginfo.h b/LibCommon/src/reginfo.h similarity index 76% rename from Processor/LibCommon/src/reginfo.h rename to LibCommon/src/reginfo.h index 13e3d76..52aa7ad 100644 --- a/Processor/LibCommon/src/reginfo.h +++ b/LibCommon/src/reginfo.h @@ -7,6 +7,8 @@ typedef unsigned char regid_t; extern char const* regmap[]; +int const regid_ok(regid_t regid); +void regid_assert(regid_t regid); regid_t const get_regid(char const* regname); char const* const get_regname(regid_t regid); diff --git a/Processor/Assembler/bin/assembler b/Processor/Assembler/bin/assembler deleted file mode 100755 index fda6779..0000000 Binary files a/Processor/Assembler/bin/assembler and /dev/null differ diff --git a/Processor/makefile b/Processor/makefile deleted file mode 100644 index eb46802..0000000 --- a/Processor/makefile +++ /dev/null @@ -1,9 +0,0 @@ -run: example.bin - ./Disassembler/bin/disassembler example.bin disasm.asm - ./Emulator/bin/emulator example.bin - -build: example.bin; - -example.bin: example.asm - ./Assembler/bin/assembler example.asm example.bin - diff --git a/SquareEquation/src/main.c b/SquareEquation/src/main.c index 2b4c2d1..6401ce9 100644 --- a/SquareEquation/src/main.c +++ b/SquareEquation/src/main.c @@ -41,8 +41,8 @@ void ReadCoeff(double* pa, double* pb, double* pc, double* eps) { break; } - // scanf("%*[^\n]"); - fflush(stdin); + scanf("%*[^\n]"); + //fflush(stdin); printf("Damn, dude! How could you fail this?!\n"); } diff --git a/ttrack-lib/hdr/ttrack/binbuf.h b/ttrack-lib/hdr/ttrack/binbuf.h index 51d1523..d5c4629 100644 --- a/ttrack-lib/hdr/ttrack/binbuf.h +++ b/ttrack-lib/hdr/ttrack/binbuf.h @@ -3,6 +3,7 @@ #include #include +#include "hash.h" typedef enum { BINBUF_ERR_OK = 0, @@ -11,6 +12,7 @@ typedef enum { BINBUF_ERR_DATA, BINBUF_ERR_STDIO, BINBUF_ERR_ERRRANGE, + BINBUF_ERR_HASH, BINBUF_NERRORS } binbuf_err_t; @@ -18,6 +20,9 @@ char const* binbuf_errstr(binbuf_err_t errc); binbuf_err_t const binbuf_init(size_t capacity); binbuf_err_t const binbuf_initf(FILE* stream); + +binbuf_err_t const binbuf_inithf(FILE* stream); + void binbuf_free(); binbuf_err_t binbuf_check(); @@ -38,6 +43,7 @@ size_t const binbuf_pos(); binbuf_read(&value, sizeof(type)) binbuf_err_t const binbuf_flush(FILE* stream); +binbuf_err_t const binbuf_flushh(FILE* stream); void binbuf_reset(); binbuf_err_t const binbuf_seek(size_t pos); @@ -45,7 +51,7 @@ binbuf_err_t const binbuf_seek(size_t pos); binbuf_err_t const binbuf_error(); void binbuf_clearerr(); - int const binbuf_ok(); + #endif /* BINBUF_H */ diff --git a/ttrack-lib/hdr/ttrack/dbg.h b/ttrack-lib/hdr/ttrack/dbg.h index ac95cdd..5e1cfe3 100644 --- a/ttrack-lib/hdr/ttrack/dbg.h +++ b/ttrack-lib/hdr/ttrack/dbg.h @@ -120,7 +120,7 @@ void dbg__message(char const* const file, int line, FILE* const stream, char const* const head_format, char const* const body_format, ...); -/* \def DBG(...) +/** \def DBG(...) * \brief Prints debug message formated with printf rules to stdout stream in debug mode. * Does nothing in release mode (NDEBUG is defined). * @@ -135,7 +135,7 @@ void dbg__message(char const* const file, int line, FILE* const stream, dbg__message(__FILE__, __LINE__, stdout, "DEBUG %s (%i): ", __VA_ARGS__) #endif -/* \def stream_assert(stream) +/** \def stream_assert(stream) * \brief Проверяет поток на неравенство NULL и на отсутствие флагов ошибок ferror(). * * Если опререлен NDEBUG не делает ничего. @@ -149,7 +149,7 @@ void dbg__message(char const* const file, int line, FILE* const stream, assert(ferror(stream) == 0); \ } while(0) -/* \def DUMP_BUFSIZE +/** \def DUMP_BUFSIZE * \brief Максимально возможное количество напечатанных символов за один вызов * функции dump. * @@ -160,7 +160,7 @@ void dbg__message(char const* const file, int line, FILE* const stream, # define DUMP_BUFSIZE (1024 * 4) #endif -/* \def DUMP_MAXDEPTH +/** \def DUMP_MAXDEPTH * \brief Максимальное количество автоматически сгенерированных функцикй dump. * отступов. * @@ -171,7 +171,7 @@ void dbg__message(char const* const file, int line, FILE* const stream, # define DUMP_MAXDEPTH 10 #endif -/* \def DUMP_HEX_BLOCK_SIZE +/** \def DUMP_HEX_BLOCK_SIZE * \brief Размер блока при печати шестнадцатиричных данных при помощи функции dump_hex. * * Может быть переопределено при компиляции. @@ -181,7 +181,7 @@ void dbg__message(char const* const file, int line, FILE* const stream, # define DUMP_HEX_BLOCK_SIZE 4 #endif -/* \def DUMP_HEX_BLOCKS_IN_LINE +/** \def DUMP_HEX_BLOCKS_IN_LINE * \brief Число блоков в строке при печати шестнадцатиричных данных при помощи * функции dump_hex. * @@ -192,22 +192,45 @@ void dbg__message(char const* const file, int line, FILE* const stream, # define DUMP_HEX_BLOCKS_IN_LINE 4 #endif +/** \def DUMP_PUSHDEPTH + * \brief Stores DUMP_DEPTH value in local variable. + * + */ #define DUMP_PUSHDEPTH \ size_t dump_depth = DUMP_DEPTH; +/** \def DUMP_POPDEPTH + * \brief Restores DUMP_DEPTH value stored with DUMP_PUSHDEPTH + * + */ + #define DUMP_POPDEPTH \ DUMP_DEPTH = dump_depth; +/** \def DUMP_PUSHTFL + * \brief Stores DUMP_TAB_FIRST_LINE value in local variable. + * + */ + #define DUMP_PUSHTFL \ size_t dump_tab_first_line = DUMP_TAB_FIRST_LINE; +/** \def DUMP_POPFTL + * \brief Restores DUMP_TAB_FIRST_LINE value stored with DUMP_PUSHTFL + * + */ + #define DUMP_POPTFL \ DUMP_TAB_FIRST_LINE = dump_tab_first_line; - +/// Number of '\t' symbols to be inserted in front of dump text extern size_t DUMP_DEPTH; + +/// Stream dump text will be written info extern FILE* DUMP_STREAM; + +/// Tab first line of dump text or not extern int DUMP_TAB_FIRST_LINE; void dump(char const* format, ...); diff --git a/ttrack-lib/hdr/ttrack/strv.h b/ttrack-lib/hdr/ttrack/strv.h new file mode 100644 index 0000000..a84dc7f --- /dev/null +++ b/ttrack-lib/hdr/ttrack/strv.h @@ -0,0 +1,58 @@ +#ifndef TTRACK_STRV_H +#define TTRACK_STRV_H + +typedef enum { + STRV_ERR_OK = 0, + STRV_ERR_NULL, + STRV_ERR_STATE, + STRV_ERR_PFIRST, + STRV_ERR_PLAST, + + STRV_NERRORS +} strv_err_t; + +char const* strv_errstr(strv_err_t err); + +typedef struct { + char const* pfirst; + char const* plast; +} strv_t; + +strv_t const strv_init(char const* pfirst, char const* plast); +strv_t const strv_make(char const* string); + +size_t const strv_len(strv_t const* strv); +int const strv_empty(strv_t const* strv); +char const strv_nth(strv_t const* strv, size_t idx); +char const strv_front(strv_t const* strv); +char const strv_back(strv_t const* strv); + +char const* strv_begin(strv_t const* strv); +char const* strv_end(strv_t const* strv); + +void strv_chomp(strv_t* strv); + +int const strv_cmp(strv_t const* lstrv, strv_t const* rstrv); +int const strv_ccmp(strv_t const* strv, char const* cstr); + +strv_t const strv_ntok(strv_t* strv, char const* delimers); +size_t const strv_tok(strv_t* strv, char const* delimers, strv_t* tokens, + size_t max_count); + +strv_err_t const strv_check(strv_t const* strv); +int const strv_ok(strv_t const* strv); + +void strv_dump_body(strv_t const* strv); +void strv__dump(strv_t const* strv, char const* funcname, char const* filename, + size_t nline); + +#define strv_dump(strv) \ + strv__dump(strv, __func__, __FILE__, __LINE__) + +void strv__assert(strv_t const* strv, char const* funcname, char const* filename, + size_t nline); + +#define strv_assert(strv) \ + strv__assert(strv, __func__, __FILE__, __LINE__) + +#endif /* TTRACK_STRING_VIEW_H */ diff --git a/ttrack-lib/hdr/ttrack/text.h b/ttrack-lib/hdr/ttrack/text.h index d9a544e..f85201a 100644 --- a/ttrack-lib/hdr/ttrack/text.h +++ b/ttrack-lib/hdr/ttrack/text.h @@ -1,5 +1,5 @@ -#ifndef TEXT_H -#define TEXT_H +#ifndef TTRACK_TEXT_H +#define TTRACK_TEXT_H #ifdef __GNUC__ @@ -9,68 +9,13 @@ #endif /* __GNUC__ */ - #include #include - -#define stream_assert(stream) \ - do { \ - assert(stream != NULL); \ - assert(ferror(stream) == 0); \ - } while(0) +#include "strv.h" /// Function FileSize() returns this value if any error occured. #define FSIZE_ERR SIZE_MAX -/// Contains pointers to first and last ('\0') line symbols. -typedef struct { - char * first; ///< pointer to the first symbol. - char * last; ///< pointer to the last symbol. -} string_t; - -typedef enum { - STRING_ERR_OK = 0, - STRING_ERR_FIRST_PTR, - STRING_ERR_LAST_PTR, - STRING_ERR_STATE, - STRING_ERR_NULL, - - STRING_NERRORS -} string_err_t; - -char const* const string_errstr(string_err_t const errc); - -string_t const string_init(char* begin, char* end); -string_t const string_make(char* const cstr); - -size_t const string_length(string_t const* const string); - -void string_chomp(string_t* const string); - -size_t const string_tok(string_t const* const string, string_t* const toks, - size_t const max_toks, char const sep); -// TODO: rewrite split_text with string_tok using - -int const string_ceq(string_t const* const string, char const* const cstring); - -string_err_t const string_check(string_t const* const string); -void string__dump(string_t const* const string, FILE* const stream, - char const* const funcname, char const* const filename, - size_t const nline); - -#define string_dump(string, stream) \ - string__dump(string, stream, __func__, __FILE__, __LINE__) - -void string__assert(string_t const* const string, char const* const funcname, - char const* const filename, size_t const nline); - -#ifdef NDEBUG -# define string_assert(string) \ - string__assert(string, __func__, __FILE__, __LINE__) -#else -# define string_assert(string) -#endif - /** * \brief Returns size of the file in bytes. Rewinds the stream. * @@ -137,7 +82,7 @@ char* const read_text2(char const* const fname, size_t* const psize, RF_err_t* c * * \warning You have to call free() for the return value. */ -string_t* const get_text_lines(char * const text, size_t const size, char const sep, +strv_t* const get_text_lines(char * const text, size_t const size, char const sep, size_t* const pnlines); /** @@ -161,7 +106,7 @@ size_t const count_lines(char const * const text, size_t const size, char const * \return count of lines. */ size_t const split_text(char * const text, size_t const size, char const sep, - string_t* const lines); + strv_t* const lines); /** @@ -174,7 +119,7 @@ size_t const split_text(char * const text, size_t const size, char const sep, * * \return 1 in case of success, 0 otherwise. */ -int const write_lines(FILE* const file, string_t const * const lines, +int const write_lines(FILE* const file, strv_t const * const lines, size_t const nlines); /** @@ -186,7 +131,7 @@ int const write_lines(FILE* const file, string_t const * const lines, * * \return 1 in case of success, 0 otherwise. */ -int const write_lines2(char const* const fname, string_t const * const lines, +int const write_lines2(char const* const fname, strv_t const * const lines, size_t const nlines); /* diff --git a/ttrack-lib/lib/ttrack-lib.a b/ttrack-lib/lib/ttrack-lib.a index 7b0f4dc..2626429 100644 Binary files a/ttrack-lib/lib/ttrack-lib.a and b/ttrack-lib/lib/ttrack-lib.a differ diff --git a/ttrack-lib/makefile b/ttrack-lib/makefile index 6862038..1a82685 100644 --- a/ttrack-lib/makefile +++ b/ttrack-lib/makefile @@ -1,18 +1,18 @@ -LDFLAGS := -lm + +LDFLAGS := \ + -lm + CFLAGS := \ -Wall -Wextra \ -g \ -DSTACKTRACE \ -DOCPATH := doc-html OBJPATH := obj SRCPATH := src BINPATH := lib - HDRPATH := hdr/ttrack BINNAME := ttrack-lib.a -DOXCONF := doxygen _CFILES := $(wildcard $(SRCPATH)/*.c) _HFILES := $(wildcard $(SRCPATH)/*.h) @@ -23,24 +23,15 @@ _HEADERS := $(patsubst $(SRCPATH)/%, $(HDRPATH)/%, $(_HFILES)) build: $(BINPATH)/$(BINNAME) $(_HEADERS) -doc: $(DOCPATH) - clean: -rm -rf $(OBJPATH)/* -rm -rf $(BINPATH)/* -rm -rf $(DOCPATH) -rm -rf $(HDRPATH)/* -include $(_DFILES) - -$(DOCPATH): $(_CFILES) $(_HFILES) - doxygen $(DOXCONF) - -$(OBJPATH)/%.o: $(SRCPATH)/%.c - $(CC) -c $< -o $@ $(CFLAGS) - $(OBJPATH)/%.d: $(SRCPATH)/%.c $(CC) -MM $< | sed 's/.*:/$(OBJPATH)\/$*.o $(OBJPATH)\/$*.d:/g' > $@ + echo -e '\t$$(CC) -c $$< -o $$@ $$(CFLAGS)' >> $@ $(BINPATH)/$(BINNAME): $(_OFILES) ar rcs $(BINPATH)/$(BINNAME) $^ @@ -48,5 +39,7 @@ $(BINPATH)/$(BINNAME): $(_OFILES) $(HDRPATH)/%.h: $(SRCPATH)/%.h cp $< $@ +include $(_DFILES) + .PHONY: all clean doc build diff --git a/ttrack-lib/src/binbuf.c b/ttrack-lib/src/binbuf.c index 03d0c98..eb07b98 100644 --- a/ttrack-lib/src/binbuf.c +++ b/ttrack-lib/src/binbuf.c @@ -22,6 +22,19 @@ static binbuf_err_t binbuf__set_error(binbuf_err_t err) $$ } +static uint32_t const binbuf__hash_till_size() +{$_ + binbuf_assert(); + + RETURN( gnu_hash(binbuf.data, binbuf.capacity) ); +} +static uint32_t const binbuf__hash_till_cap() +{$_ + binbuf_assert(); + + RETURN( gnu_hash(binbuf.data, binbuf.capacity) ); +} + char const* binbuf_errstr(binbuf_err_t errc) {$_ if(errc < 0 || errc >= BINBUF_NERRORS) { @@ -34,7 +47,8 @@ char const* binbuf_errstr(binbuf_err_t errc) "out of range", "data pointer is null", "error in stdio", - "invalid error value" + "invalid error value", + "invalid hash" }; RETURN(TABLE[errc]); } @@ -51,7 +65,7 @@ binbuf_err_t const binbuf_init(size_t capacity) binbuf.size = 0; binbuf.capacity = capacity; binbuf.err = BINBUF_ERR_OK; - RETURN(binbuf__set_error(BINBUF_ERR_OK)); + RETURN(BINBUF_ERR_OK); } binbuf_err_t const binbuf_initf(FILE* stream) @@ -60,11 +74,38 @@ binbuf_err_t const binbuf_initf(FILE* stream) RT_err_t errc; binbuf.data = (unsigned char*)read_text(stream, &binbuf.capacity, &errc); - if(errc != RT_OK) { + if(errc == RT_IO) { RETURN(binbuf__set_error(BINBUF_ERR_STDIO)); } + if(errc == RT_MEMORY) { + RETURN(binbuf__set_error(BINBUF_ERR_MEM)); + } + binbuf.size = binbuf.capacity; - RETURN(binbuf__set_error(BINBUF_ERR_OK)); + RETURN(BINBUF_ERR_OK); +} + +binbuf_err_t const binbuf_inithf(FILE* stream) +{$_ + stream_assert(stream); + + uint32_t hash; + if(fread(&hash, sizeof(uint32_t), 1, stream) != 1) { + RETURN(BINBUF_ERR_STDIO); + } + + binbuf_err_t err = binbuf_initf(stream); + + if(err != BINBUF_ERR_OK) { + RETURN(err); + } + + uint32_t real_hash = binbuf__hash_till_cap(); + if(real_hash != hash) { + RETURN(binbuf__set_error(BINBUF_ERR_HASH)); + } + RETURN(BINBUF_ERR_OK); +$$ } void binbuf_free() @@ -176,6 +217,16 @@ binbuf_err_t const binbuf_flush(FILE* stream) RETURN(binbuf__set_error(written == binbuf.size ? BINBUF_ERR_OK : BINBUF_ERR_STDIO)); } +binbuf_err_t const binbuf_flushh(FILE* stream) { + stream_assert(stream); + + uint32_t hash = binbuf__hash_till_size(); + if(fwrite(&hash, sizeof(uint32_t), 1, stream) != 1) { + RETURN(binbuf__set_error(BINBUF_ERR_STDIO)); + } + return binbuf_flush(stream); +} + void binbuf_reset() {$_ binbuf_assert(); @@ -210,3 +261,4 @@ int const binbuf_ok() { return(binbuf.err == BINBUF_ERR_OK); } + diff --git a/ttrack-lib/src/binbuf.h b/ttrack-lib/src/binbuf.h index 51d1523..d5c4629 100644 --- a/ttrack-lib/src/binbuf.h +++ b/ttrack-lib/src/binbuf.h @@ -3,6 +3,7 @@ #include #include +#include "hash.h" typedef enum { BINBUF_ERR_OK = 0, @@ -11,6 +12,7 @@ typedef enum { BINBUF_ERR_DATA, BINBUF_ERR_STDIO, BINBUF_ERR_ERRRANGE, + BINBUF_ERR_HASH, BINBUF_NERRORS } binbuf_err_t; @@ -18,6 +20,9 @@ char const* binbuf_errstr(binbuf_err_t errc); binbuf_err_t const binbuf_init(size_t capacity); binbuf_err_t const binbuf_initf(FILE* stream); + +binbuf_err_t const binbuf_inithf(FILE* stream); + void binbuf_free(); binbuf_err_t binbuf_check(); @@ -38,6 +43,7 @@ size_t const binbuf_pos(); binbuf_read(&value, sizeof(type)) binbuf_err_t const binbuf_flush(FILE* stream); +binbuf_err_t const binbuf_flushh(FILE* stream); void binbuf_reset(); binbuf_err_t const binbuf_seek(size_t pos); @@ -45,7 +51,7 @@ binbuf_err_t const binbuf_seek(size_t pos); binbuf_err_t const binbuf_error(); void binbuf_clearerr(); - int const binbuf_ok(); + #endif /* BINBUF_H */ diff --git a/ttrack-lib/src/dbg.h b/ttrack-lib/src/dbg.h index ac95cdd..5e1cfe3 100644 --- a/ttrack-lib/src/dbg.h +++ b/ttrack-lib/src/dbg.h @@ -120,7 +120,7 @@ void dbg__message(char const* const file, int line, FILE* const stream, char const* const head_format, char const* const body_format, ...); -/* \def DBG(...) +/** \def DBG(...) * \brief Prints debug message formated with printf rules to stdout stream in debug mode. * Does nothing in release mode (NDEBUG is defined). * @@ -135,7 +135,7 @@ void dbg__message(char const* const file, int line, FILE* const stream, dbg__message(__FILE__, __LINE__, stdout, "DEBUG %s (%i): ", __VA_ARGS__) #endif -/* \def stream_assert(stream) +/** \def stream_assert(stream) * \brief Проверяет поток на неравенство NULL и на отсутствие флагов ошибок ferror(). * * Если опререлен NDEBUG не делает ничего. @@ -149,7 +149,7 @@ void dbg__message(char const* const file, int line, FILE* const stream, assert(ferror(stream) == 0); \ } while(0) -/* \def DUMP_BUFSIZE +/** \def DUMP_BUFSIZE * \brief Максимально возможное количество напечатанных символов за один вызов * функции dump. * @@ -160,7 +160,7 @@ void dbg__message(char const* const file, int line, FILE* const stream, # define DUMP_BUFSIZE (1024 * 4) #endif -/* \def DUMP_MAXDEPTH +/** \def DUMP_MAXDEPTH * \brief Максимальное количество автоматически сгенерированных функцикй dump. * отступов. * @@ -171,7 +171,7 @@ void dbg__message(char const* const file, int line, FILE* const stream, # define DUMP_MAXDEPTH 10 #endif -/* \def DUMP_HEX_BLOCK_SIZE +/** \def DUMP_HEX_BLOCK_SIZE * \brief Размер блока при печати шестнадцатиричных данных при помощи функции dump_hex. * * Может быть переопределено при компиляции. @@ -181,7 +181,7 @@ void dbg__message(char const* const file, int line, FILE* const stream, # define DUMP_HEX_BLOCK_SIZE 4 #endif -/* \def DUMP_HEX_BLOCKS_IN_LINE +/** \def DUMP_HEX_BLOCKS_IN_LINE * \brief Число блоков в строке при печати шестнадцатиричных данных при помощи * функции dump_hex. * @@ -192,22 +192,45 @@ void dbg__message(char const* const file, int line, FILE* const stream, # define DUMP_HEX_BLOCKS_IN_LINE 4 #endif +/** \def DUMP_PUSHDEPTH + * \brief Stores DUMP_DEPTH value in local variable. + * + */ #define DUMP_PUSHDEPTH \ size_t dump_depth = DUMP_DEPTH; +/** \def DUMP_POPDEPTH + * \brief Restores DUMP_DEPTH value stored with DUMP_PUSHDEPTH + * + */ + #define DUMP_POPDEPTH \ DUMP_DEPTH = dump_depth; +/** \def DUMP_PUSHTFL + * \brief Stores DUMP_TAB_FIRST_LINE value in local variable. + * + */ + #define DUMP_PUSHTFL \ size_t dump_tab_first_line = DUMP_TAB_FIRST_LINE; +/** \def DUMP_POPFTL + * \brief Restores DUMP_TAB_FIRST_LINE value stored with DUMP_PUSHTFL + * + */ + #define DUMP_POPTFL \ DUMP_TAB_FIRST_LINE = dump_tab_first_line; - +/// Number of '\t' symbols to be inserted in front of dump text extern size_t DUMP_DEPTH; + +/// Stream dump text will be written info extern FILE* DUMP_STREAM; + +/// Tab first line of dump text or not extern int DUMP_TAB_FIRST_LINE; void dump(char const* format, ...); diff --git a/ttrack-lib/src/strv.c b/ttrack-lib/src/strv.c new file mode 100644 index 0000000..81af9af --- /dev/null +++ b/ttrack-lib/src/strv.c @@ -0,0 +1,217 @@ +#include +#include +#include "dbg.h" +#include "strv.h" + +char const* strv_errstr(strv_err_t err) +{$_ + ASSERT(err >= 0 && err < STRV_NERRORS); + + char const* TABLE[STRV_NERRORS] = { + "ok", + "instance pointer is null", + "invalid state (pfirst > plast)", + "pointer to the first character is null", + "pointer to the last character is null" + }; + RETURN(TABLE[err]); +$$ +} + +strv_t const strv_init(char const* pfirst, char const* plast) +{$_ + ASSERT(pfirst != NULL); + ASSERT(plast != NULL); + ASSERT(pfirst <= plast); + + strv_t strv = { pfirst, plast }; + strv_assert(&strv); + + RETURN(strv); +$$ +} + +strv_t const strv_make(char const* string) +{$_ + ASSERT(string != NULL); + strv_t strv = strv_init(string, string + strlen(string)); + strv_assert(&strv); + + RETURN(strv); +$$ +} + +size_t const strv_len(strv_t const* strv) +{$_ + strv_assert(strv); + RETURN(strv->plast - strv->pfirst); +$$ +} + +int const strv_empty(strv_t const* strv) +{$_ + strv_assert(strv); + RETURN(strv->pfirst == strv->plast); +$$ +} + +char const strv_nth(strv_t const* strv, size_t idx) +{$_ + strv_assert(strv); + ASSERT(idx < strv_len(strv)); + RETURN(*(strv->pfirst + idx)); +$$ +} + +char const strv_front(strv_t const* strv) +{$_ + strv_assert(strv); + ASSERT(!strv_empty(strv)); + RETURN(*strv->pfirst); +$$ +} + +char const strv_back(strv_t const* strv) +{$_ + strv_assert(strv); + ASSERT(!strv_empty(strv)); + RETURN(*(strv->plast - 1)); +$$ +} + +char const* strv_begin(strv_t const* strv) +{$_ + strv_assert(strv); + RETURN(strv->pfirst); +$$ +} +char const* strv_end(strv_t const* strv) +{$_ + strv_assert(strv); + RETURN(strv->plast); +$$ +} + +void strv_chomp(strv_t* strv) +{$_ + strv_assert(strv); + + while(strv->pfirst < strv->plast && isalpha(*strv->pfirst)) { + ++strv->pfirst; + } + while(strv->pfirst < strv->plast && isalpha(*(strv->plast - 1))) { + --strv->plast; + } + + strv_assert(strv); +$$ +} + +int const strv_cmp(strv_t const* lstrv, strv_t const* rstrv) +{$_ + strv_assert(lstrv); + strv_assert(rstrv); + + size_t llen = strv_len(lstrv); + size_t rlen = strv_len(rstrv); + size_t min_len = llen < rlen ? llen : rlen; + + int cmd_res = memcmp(lstrv->pfirst, rstrv->pfirst, min_len); + RETURN(cmd_res); +$$ +} + +int const strv_ccmp(strv_t const* strv, char const* cstr) +{$_ + strv_assert(strv); + ASSERT(cstr != NULL); + + return strncmp(strv->pfirst, cstr, strv_len(strv)); +$$ +} + +strv_t const strv_ntok(strv_t* strv, char const* delimers) +{$_ + strv_assert(strv); + ASSERT(delimers != NULL); + + while(strv->pfirst < strv->plast && strchr(delimers, *strv->pfirst) != NULL) { + ++strv->pfirst; + } + + char const* rover = strv->pfirst; + + for(; strv->pfirst < strv->plast; ++strv->pfirst) { + if(strchr(delimers, *strv->pfirst) != NULL) { + RETURN(strv_init(rover, strv->pfirst)); + } + } + + RETURN(*strv); +$$ +} + +size_t const strv_tok(strv_t* strv, char const* delimers, strv_t* tokens, + size_t max_count) +{$_ + strv_assert(strv); + ASSERT(delimers != NULL); + ASSERT(tokens != NULL); + + size_t count = 0; + for(strv_t cstrv = strv_ntok(strv, delimers); + !strv_empty(&cstrv) && count < max_count; + cstrv = strv_ntok(strv, delimers)) + { + *tokens = cstrv; + ++tokens; + ++count; + } + + RETURN(count); +$$ +} + +strv_err_t const strv_check(strv_t const* strv) +{$_ + if(strv == NULL) { RETURN(STRV_ERR_NULL); } + if(strv->pfirst == NULL) { RETURN(STRV_ERR_PFIRST); } + if(strv->plast == NULL) { RETURN(STRV_ERR_PLAST); } + if(strv->pfirst > strv->plast) { RETURN(STRV_ERR_STATE); } + RETURN(STRV_ERR_OK); +$$ +} + +int const strv_ok(strv_t const* strv) +{$_ + RETURN(strv_check(strv) == STRV_ERR_OK); +$$ +} + +void strv__dump(strv_t const* strv, char const* funcname, char const* filename, + size_t nline) +{$_ + strv_err_t err = strv_check(strv); + dump("strv_t [%p] dump from %s (%s %zu), reason %i (%s) {\n", + strv, funcname, filename, nline, strv_errstr(err)); + + if(strv != NULL) { + dump("\tpfirst = %p\n", strv->pfirst); + dump("\tplast = %p\n", strv->plast); + } + dump("}\n"); +$$ +} + +void strv__assert(strv_t const* strv, char const* funcname, char const* filename, + size_t nline) +{$_ + if(!strv_ok(strv)) { + strv__dump(strv, funcname, filename, nline); + ASSERT(!"invalid strv"); + } +$$ +} + + + diff --git a/ttrack-lib/src/strv.h b/ttrack-lib/src/strv.h new file mode 100644 index 0000000..a84dc7f --- /dev/null +++ b/ttrack-lib/src/strv.h @@ -0,0 +1,58 @@ +#ifndef TTRACK_STRV_H +#define TTRACK_STRV_H + +typedef enum { + STRV_ERR_OK = 0, + STRV_ERR_NULL, + STRV_ERR_STATE, + STRV_ERR_PFIRST, + STRV_ERR_PLAST, + + STRV_NERRORS +} strv_err_t; + +char const* strv_errstr(strv_err_t err); + +typedef struct { + char const* pfirst; + char const* plast; +} strv_t; + +strv_t const strv_init(char const* pfirst, char const* plast); +strv_t const strv_make(char const* string); + +size_t const strv_len(strv_t const* strv); +int const strv_empty(strv_t const* strv); +char const strv_nth(strv_t const* strv, size_t idx); +char const strv_front(strv_t const* strv); +char const strv_back(strv_t const* strv); + +char const* strv_begin(strv_t const* strv); +char const* strv_end(strv_t const* strv); + +void strv_chomp(strv_t* strv); + +int const strv_cmp(strv_t const* lstrv, strv_t const* rstrv); +int const strv_ccmp(strv_t const* strv, char const* cstr); + +strv_t const strv_ntok(strv_t* strv, char const* delimers); +size_t const strv_tok(strv_t* strv, char const* delimers, strv_t* tokens, + size_t max_count); + +strv_err_t const strv_check(strv_t const* strv); +int const strv_ok(strv_t const* strv); + +void strv_dump_body(strv_t const* strv); +void strv__dump(strv_t const* strv, char const* funcname, char const* filename, + size_t nline); + +#define strv_dump(strv) \ + strv__dump(strv, __func__, __FILE__, __LINE__) + +void strv__assert(strv_t const* strv, char const* funcname, char const* filename, + size_t nline); + +#define strv_assert(strv) \ + strv__assert(strv, __func__, __FILE__, __LINE__) + +#endif /* TTRACK_STRING_VIEW_H */ diff --git a/ttrack-lib/src/text.c b/ttrack-lib/src/text.c index 9e9c007..ca52a88 100644 --- a/ttrack-lib/src/text.c +++ b/ttrack-lib/src/text.c @@ -4,118 +4,6 @@ #include "dbg.h" #include "text.h" -char const* const string_errstr(string_err_t const errc) -{$_ - if(errc >= STRING_NERRORS || errc < 0) { - RETURN(NULL); - } - - static char const* const _TABLE[STRING_NERRORS] = { - "ok", - "invalid pointer to the first element", - "invalid pointer to the last element", - "invalid state (first > last)", - "string is null" - }; - RETURN(_TABLE[errc]); -} - -string_t const string_init(char* begin, char* end) -{$_ - ASSERT(begin != NULL); - ASSERT(end != NULL); - ASSERT(end >= begin); - - string_t string = { begin, end }; - string.last = '\0'; - RETURN(string); -} -string_t const string_make(char* const cstr) -{$_ - ASSERT(cstr != NULL); - - string_t string = { cstr, cstr + strlen(cstr) }; - RETURN(string); -} - -size_t const string_length(string_t const* const string) -{$_ - string_assert(string); - RETURN(string->last - string->first); -} - -void string_chomp(string_t* const string) -{$_ - string_assert(string); - - while(string->first < string->last && isspace(*string->first)) { - ++string->first; - } - while(string->last > string->first && isspace(*(string->last - 1))) { - --string->last; - } - *string->last = '\0'; - string_assert(string); -$$ -} - -string_err_t const string_check(string_t const* const string) -{$_ - if(string == NULL) { RETURN(STRING_ERR_NULL); } - if(string->first == NULL) { RETURN(STRING_ERR_FIRST_PTR); } - if(string->last == NULL) { RETURN(STRING_ERR_LAST_PTR); } - if(string->last < string->first) { RETURN(STRING_ERR_STATE); } - RETURN(STRING_ERR_OK); -} - -void string__dump(string_t const* const string, FILE* const stream, - char const* const funcname, char const* const filename, - size_t const nline) -{$_ - ASSERT(stream != NULL); - ASSERT(ferror(stream) == 0); - ASSERT(funcname != NULL); - ASSERT(filename != NULL); - - string_err_t errc = string_check(string); - fprintf(stream, "string_t [%p] dump from %s (%s %zu), reason: %i (%s)\n", - string, funcname, filename, nline, errc, string_errstr(errc)); - - fputs("{\n", stream); - if(string != NULL) { - fprintf(stream, "\tfirst = %p\n", string->first); - fprintf(stream, "\tlast = %p\n\n", string->last); - - fprintf(stream, "\t[length] = %li\n", string->last - string->first); - fprintf(stream, "\t[data] = "); - if(string->first != NULL && string->last != NULL && - string->first <= string->last) { - - fputc('\"', stream); - fwrite(string->first, sizeof(char), string->last - string->first, stream); - fputs("\"\n", stream); - } - else { - fprintf(stream, "invalid\n"); - } - } - fputs("}\n", stream); -$$ -} - -void string__assert(string_t const* const string, char const* const funcname, - char const* const filename, size_t const nline) -{$_ - ASSERT(funcname != NULL); - ASSERT(filename != NULL); - - if(string_check(string) != STRING_ERR_OK) { - string__dump(string, stderr, funcname, filename, nline); - ASSERT(!"invalid string"); - } -$$ -} - size_t const fsize(FILE* const file) {$_ ASSERT(file != NULL); @@ -147,29 +35,26 @@ size_t const count_lines(char const * const text, size_t const size, char const } size_t const split_text(char * const text, size_t const size, char const sep, - string_t* const lines) + strv_t* const lines) {$_ ASSERT(text != NULL); ASSERT(lines != NULL); // test: empty text - string_t* curline = lines; + strv_t* curline = lines; char * rover = text; for(char * ch = text; ch < text + size; ++ch) { if(*ch == sep) { - curline->first = rover; - curline->last = ch; - *curline->last = '\0'; + *curline = strv_init(rover, ch); ++curline; rover = ch + 1; } } - curline->first = rover; - curline->last = text + size; + *curline = strv_init(rover, text + size); RETURN(curline - lines + 1); } @@ -203,7 +88,7 @@ char* const read_text(FILE* const file, size_t* const psize, RT_err_t* const err RETURN(text); } -int const write_lines(FILE* const file, string_t const * const lines, +int const write_lines(FILE* const file, strv_t const * const lines, size_t const nlines) {$_ ASSERT(file != NULL); @@ -211,8 +96,8 @@ int const write_lines(FILE* const file, string_t const * const lines, ASSERT(lines != NULL); for(size_t i = 0; i < nlines; ++i) { - size_t size = lines[i].last - lines[i].first; - if(fwrite(lines[i].first, sizeof(char), size, file) != size) + size_t size = strv_len(&lines[i]); + if(fwrite(strv_begin(&lines[i]), sizeof(char), size, file) != size) RETURN(0); if(fputc((int)'\n', file) == EOF) @@ -222,7 +107,7 @@ int const write_lines(FILE* const file, string_t const * const lines, RETURN(1); } -string_t* const get_text_lines(char * const text, size_t const size, char const sep, +strv_t* const get_text_lines(char * const text, size_t const size, char const sep, size_t* const pnlines) {$_ ASSERT(text != NULL); @@ -230,7 +115,7 @@ string_t* const get_text_lines(char * const text, size_t const size, char const size_t const nlines = count_lines(text, size, sep); - string_t* lines = (string_t*)calloc(nlines, sizeof(string_t)); + strv_t* lines = (strv_t*)calloc(nlines, sizeof(strv_t)); if(lines == NULL) { RETURN(NULL); } @@ -284,7 +169,7 @@ char* const read_text2(char const* const fname, size_t* const psize, RETURN(text); } -int const write_lines2(char const* const fname, string_t const * const lines, +int const write_lines2(char const* const fname, strv_t const * const lines, size_t const nlines) {$_ ASSERT(fname != NULL); diff --git a/ttrack-lib/src/text.h b/ttrack-lib/src/text.h index d9a544e..f85201a 100644 --- a/ttrack-lib/src/text.h +++ b/ttrack-lib/src/text.h @@ -1,5 +1,5 @@ -#ifndef TEXT_H -#define TEXT_H +#ifndef TTRACK_TEXT_H +#define TTRACK_TEXT_H #ifdef __GNUC__ @@ -9,68 +9,13 @@ #endif /* __GNUC__ */ - #include #include - -#define stream_assert(stream) \ - do { \ - assert(stream != NULL); \ - assert(ferror(stream) == 0); \ - } while(0) +#include "strv.h" /// Function FileSize() returns this value if any error occured. #define FSIZE_ERR SIZE_MAX -/// Contains pointers to first and last ('\0') line symbols. -typedef struct { - char * first; ///< pointer to the first symbol. - char * last; ///< pointer to the last symbol. -} string_t; - -typedef enum { - STRING_ERR_OK = 0, - STRING_ERR_FIRST_PTR, - STRING_ERR_LAST_PTR, - STRING_ERR_STATE, - STRING_ERR_NULL, - - STRING_NERRORS -} string_err_t; - -char const* const string_errstr(string_err_t const errc); - -string_t const string_init(char* begin, char* end); -string_t const string_make(char* const cstr); - -size_t const string_length(string_t const* const string); - -void string_chomp(string_t* const string); - -size_t const string_tok(string_t const* const string, string_t* const toks, - size_t const max_toks, char const sep); -// TODO: rewrite split_text with string_tok using - -int const string_ceq(string_t const* const string, char const* const cstring); - -string_err_t const string_check(string_t const* const string); -void string__dump(string_t const* const string, FILE* const stream, - char const* const funcname, char const* const filename, - size_t const nline); - -#define string_dump(string, stream) \ - string__dump(string, stream, __func__, __FILE__, __LINE__) - -void string__assert(string_t const* const string, char const* const funcname, - char const* const filename, size_t const nline); - -#ifdef NDEBUG -# define string_assert(string) \ - string__assert(string, __func__, __FILE__, __LINE__) -#else -# define string_assert(string) -#endif - /** * \brief Returns size of the file in bytes. Rewinds the stream. * @@ -137,7 +82,7 @@ char* const read_text2(char const* const fname, size_t* const psize, RF_err_t* c * * \warning You have to call free() for the return value. */ -string_t* const get_text_lines(char * const text, size_t const size, char const sep, +strv_t* const get_text_lines(char * const text, size_t const size, char const sep, size_t* const pnlines); /** @@ -161,7 +106,7 @@ size_t const count_lines(char const * const text, size_t const size, char const * \return count of lines. */ size_t const split_text(char * const text, size_t const size, char const sep, - string_t* const lines); + strv_t* const lines); /** @@ -174,7 +119,7 @@ size_t const split_text(char * const text, size_t const size, char const sep, * * \return 1 in case of success, 0 otherwise. */ -int const write_lines(FILE* const file, string_t const * const lines, +int const write_lines(FILE* const file, strv_t const * const lines, size_t const nlines); /** @@ -186,7 +131,7 @@ int const write_lines(FILE* const file, string_t const * const lines, * * \return 1 in case of success, 0 otherwise. */ -int const write_lines2(char const* const fname, string_t const * const lines, +int const write_lines2(char const* const fname, strv_t const * const lines, size_t const nlines); /*