# Process this file with automake to produce Makefile.in.
#
# Copyright (C) 2015 Alexander Andrejevic <theflash AT sdf DOT lonestar DOT org>
-# Copyright (C) 2019 Jason Self <j@jxself.org>
+# Copyright (C) 2019, 2020 Jason Self <j@jxself.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
bin_PROGRAMS = zilasm
man_MANS = zilasm.1
-zilasm_SOURCES = main.cpp opcodes.c symtable.c header.cpp parser.cpp directives.c labels.cpp string_table.cpp zmem.c
+zilasm_SOURCES = main.cpp opcodes.c symtable.c header.cpp parser.cpp directives.cpp labels.cpp string_table.cpp zmem.c
include_HEADERS = opcodes.h symtable.h header.h parser.h directives.h labels.h string_table.h zmem.h
+++ /dev/null
-/*
- * directives.c -- part of ZilUtils/ZilAsm
- *
- * Copyright (C) 2016 Jason Self <j@jxself.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#include <stdlib.h> /* bsearch */
-#include <string.h> /* strcmp */
-
-#include "directives.h"
-
-#define ARRAY_SIZE(x) ((sizeof(x)) / (sizeof(x[0])))
-
-static int
-byte_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-end_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-endi_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-endt_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-fstr_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-funct_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-gstr_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-gvar_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-insert_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-len_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-new_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-object_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-prop_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-str_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-strl_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-table_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-vocbeg_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-vocend_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-word_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-static int
-zword_handler (const char *args)
-{
- /* !!! TODO !!! */
- return 0;
-}
-
-// Sorted array
-static Directive Directives[] = {
- "BYTE", byte_handler,
- "END", end_handler,
- "ENDI", endi_handler,
- "ENDT", endt_handler,
- "FSTR", fstr_handler,
- "FUNCT", funct_handler,
- "GSTR", gstr_handler,
- "GVAR", gvar_handler,
- "INSERT", insert_handler,
- "LEN", len_handler,
- "NEW", new_handler,
- "OBJECT", object_handler,
- "PROP", prop_handler,
- "STR", str_handler,
- "STRL", strl_handler,
- "TABLE", table_handler,
- "VOCBEG", vocbeg_handler,
- "VOCEND", vocend_handler,
- "WORD", word_handler,
- "ZWORD", zword_handler
-};
-
-typedef struct
-{
- const char *contents;
- unsigned length;
-} Name;
-
-static int
-namecmp (const void *key, const void *elem)
-{
- const Name *p = (Name *) key;
- const Directive *d = (Directive *) elem;
-
- int len1 = p->length;
- int len2 = strlen (d->name);
-
- int rc = memcmp (p->contents, elem, len1 < len2 ? len1 : len2);
- return rc ? rc : (len1 - len2);
-}
-
-Directive_handler
-directive_lookup (const char *name, unsigned namelen)
-{
- Name n = { name, namelen };
- Directive *p =
- (Directive *) bsearch (&n, Directives, ARRAY_SIZE (Directives),
- sizeof (Directive), namecmp);
- return p ? p->handler : NULL;
-}
--- /dev/null
+/*
+ * directives.c -- part of ZilUtils/ZilAsm
+ *
+ * Copyright (C) 2016, 2020 Jason Self <j@jxself.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <stdlib.h> /* bsearch */
+#include <string.h> /* strcmp */
+#include <stdio.h>
+#include <stack>
+#include <string>
+using namespace std;
+
+#include "header.h"
+#include "parser.h"
+#include "directives.h"
+
+#define ARRAY_SIZE(x) ((sizeof(x)) / (sizeof(x[0])))
+
+int g_stopParsing = 0;
+stack<FILE*> g_fileHandlers;
+
+
+
+static int
+byte_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+end_handler (const char *args)
+{
+ g_stopParsing = 1;
+ return 0;
+}
+
+static int
+endi_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+endt_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+fstr_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+funct_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+gstr_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+gvar_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+insert_handler (const char *args)
+{
+ string file_name;
+ char *p = (char*)args;
+ while (*p == ' ') p++;
+
+ if (*p == '"')
+ {
+ p++;
+ do
+ {
+ file_name += *p;
+ p++;
+ }
+ while (*p != '"' && *p != 0 ) ;
+ }
+ else
+ {
+ do
+ {
+ file_name += *p;
+ p++;
+ } while (*p != ' ' && *p != '\n' && *p != '\r' && *p != '\t' && *p != 0);
+ }
+
+ if (file_name.find('.') == string::npos)
+ {
+ file_name += ".zap";
+ }
+
+#ifdef WIN32
+ char delimeter = '\\';
+#else
+ char delimeter = '/';
+#endif
+
+ Parsing_Context pc;
+ if (file_name.rfind(delimeter) == string::npos)
+ {
+ pc.current_directory = "";
+ pc.current_file_name = file_name;
+ }
+ else
+ {
+ pc.current_directory = file_name.substr(0, file_name.rfind(delimeter)+1);
+ pc.current_file_name = file_name.substr(file_name.rfind(delimeter)+1);
+ }
+
+ pc.current_directory = g_parsing_contexts.top().current_directory + pc.current_directory;
+ //pc.current_file_name = s;
+ g_parsing_contexts.push(pc);
+
+
+ unsigned saveLineNumber = g_currentLineNumber;
+ parse_file(); //s.c_str());
+ g_currentLineNumber = saveLineNumber;
+ return strlen(args);
+}
+
+static int
+len_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+newdirective_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+object_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+prop_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+str_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+strl_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+table_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+vocbeg_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+vocend_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+word_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+static int
+zword_handler (const char *args)
+{
+ /* !!! TODO !!! */
+ return 0;
+}
+
+// Sorted array
+static Directive Directives[] = {
+ "BYTE", byte_handler,
+ "END", end_handler,
+ "ENDI", endi_handler,
+ "ENDT", endt_handler,
+ "FSTR", fstr_handler,
+ "FUNCT", funct_handler,
+ "GSTR", gstr_handler,
+ "GVAR", gvar_handler,
+ "INSERT", insert_handler,
+ "LEN", len_handler,
+ "NEW", newdirective_handler,
+ "OBJECT", object_handler,
+ "PROP", prop_handler,
+ "STR", str_handler,
+ "STRL", strl_handler,
+ "TABLE", table_handler,
+ "VOCBEG", vocbeg_handler,
+ "VOCEND", vocend_handler,
+ "WORD", word_handler,
+ "ZWORD", zword_handler
+};
+
+typedef struct
+{
+ const char *contents;
+ unsigned length;
+} Name;
+
+static int
+namecmp (const void *key, const void *elem)
+{
+ const Name *p = (Name *) key;
+ const Directive *d = (Directive *) elem;
+
+ int len1 = p->length;
+ int len2 = strlen (d->name);
+
+ int rc = memcmp (p->contents, elem, len1 < len2 ? len1 : len2);
+ return rc ? rc : (len1 - len2);
+}
+
+Directive_handler
+directive_lookup (const char *name, unsigned namelen)
+{
+ Name n = { name, namelen };
+ Directive *p =
+ (Directive *) bsearch (&n, Directives, ARRAY_SIZE (Directives),
+ sizeof (Directive), namecmp);
+ return p ? p->handler : NULL;
+}
/*
* directives.h -- part of ZilUtils/ZilAsm
*
- * Copyright (C) 2016 Jason Self <j@jxself.org>
+ * Copyright (C) 2016, 2020 Jason Self <j@jxself.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
} Directive;
Directive_handler directive_lookup (const char *name, unsigned namelen);
+extern int g_stopParsing;
+extern stack<FILE*> g_fileHandlers;
#endif /* ifndef ZILASM_DIRECTIVES */
* main.c
*
* Copyright (C) 2015 Alexander Andrejevic <theflash AT sdf DOT lonestar DOT org>
- * Copyright (C) 2015, 2019 Jason Self <j@jxself.org>
+ * Copyright (C) 2015, 2019, 2020 Jason Self <j@jxself.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
+#include <string>
+#include <list>
+#include <stack>
+using namespace std;
+
+
extern "C"
{
#include <strings.h>
}
#include "parser.h"
-#include <string>
-#include <list>
-using namespace std;
+
const int DEFAULT_ZVERSION = 6;
++m_code_size;
// write instructions' codes
- for (int i = 0; i < g_numberOfInstructions; ++i)
+ for (int i = 0; i < g_number_of_instructions; ++i)
{
for (int j = 0; j < g_codes[i]->used_size; ++j)
{
init_parser ();
- for (int i = optind; i < argc; i++)
- parse_file (argv[i]);
- main.assembly ();
+ //for (int i = optind; i < argc; i++)
+ // parse_file(argv[i]);
+
+ string file_name = argv[optind];
+ Parsing_Context pc;
+
+#ifdef WIN32
+ char delimeter = '\\';
+#else
+ char delimeter = '/';
+#endif
+
+ if (file_name.rfind(delimeter) == string::npos)
+ {
+ pc.current_directory = "";
+ pc.current_file_name = file_name;
+ }
+ else
+ {
+ pc.current_directory = file_name.substr(0, file_name.rfind(delimeter)+1);
+ pc.current_file_name = file_name.substr(file_name.rfind(delimeter)+1);
+ }
+ g_parsing_contexts.push(pc);
+
+ parse_file();// argv[optind]);
+ if ( !g_haveErrors )
+ main.assembly ();
/* TODO! List global symbols */
/* TODO! Find abbreviations */
/*
* parser.c -- part of ZilUtils/ZilAsm
*
- * Copyright (C) 2016, 2019 Jason Self <j@jxself.org>
+ * Copyright (C) 2016, 2019, 2020 Jason Self <j@jxself.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
#include <string.h> /* strlen */
#include <ctype.h>
#include <string>
+#include <stack>
using namespace std;
#include "header.h"
#include "parser.h"
+#include "directives.h"
extern "C"
{
-#include "directives.h"
#include "opcodes.h"
}
#include "labels.h"
#define isbindigit(c) ((c) == '0' || (c) == '1')
/* !!! TODO !!! */
-#define fatal_error(errmsg) printf(errmsg)
+//#define fatal_error(errmsg) printf(errmsg)
#define PC NULL
-unsigned g_numberOfInstructions = 0;
+unsigned g_number_of_instructions = 0;
+
+unsigned g_currentLineNumber = 0;
+//string g_source_directory;
+bool g_haveErrors = false;
+
+stack<Parsing_Context> g_parsing_contexts;
ZMemblock (*g_codes[MAX_NUMBER_OF_INSTRUCTIONS]);
+string
+build_error_message(const char *message)
+{
+ char buff[300];
+ sprintf(buff, "error at %s%s line %d: %s", g_parsing_contexts.top().current_directory.c_str(),
+ g_parsing_contexts.top().current_file_name.c_str(), g_currentLineNumber, message);
+ return string(buff);
+}
+
+
+void
+fatal_error(const char *errmsg)
+{
+ printf( "%s\n", errmsg);
+ g_haveErrors = true;
+}
+
+
void
checksep (const char *p)
{
if (!*p || iscomment (*p) || isspace (*p))
return;
- fatal_error ("wrong chars");
+ fatal_error (build_error_message ("wrong chars").c_str());
}
Directive_handler f = directive_lookup (a, b - a);
if (!f)
return 0;
- return (*f) (b);
+ return (b-a) + (*f) (b);
}
}
else
{
- fatal_error ("wrong label type");
+ fatal_error (build_error_message("wrong label type").c_str());
}
while (*c++ == ':');
int
tryparse_instruction (const char *a)
{
- const char *b = pass_alnums (a);
- if (b != a)
- {
- int len = b ? b - a : strlen (a);
- ZOpcode *op = (ZOpcode *) symtable_lookup2 (Opcodes, a, len);
- if (!op)
- return 0;
- ZOpcode_flags flags = op->flags;
- /* !!! TODO !!! */
-
-
- ZMemblock *mem_additional = NULL;
-
- switch (op->opcode)
+ bool display_error = false;
+ int len = 0;
+ const char *b = pass_alnums(a);
+ if (b != a)
{
- case Opcode_CRLF:
- case Opcode_PRINT:
- case Opcode_QUIT:
- break;
-
- case Opcode_PRINTI:
- case Opcode_PRINTR:
- {
- char *p = (char *) a + len;
- p = (char *) pass_spaces (p);
- if (*p == '\"')
- {
- p++;
- string str;
- while (*p != '\"')
- {
- str += *p;
- ++p;
- }
- len = p - a;
- mem_additional =
- String_table::encrypt_string (str.c_str (), NULL);
- }
- break;
- }
- default:
- fatal_error ("error! instruction not supported");
- return 0;
+ len = b ? b - a : strlen(a);
+ ZOpcode *op = (ZOpcode *)symtable_lookup2(Opcodes, a, len);
+ if (op)
+ {
+ ZOpcode_flags flags = op->flags;
+ ZMemblock *mem_additional = NULL;
+
+ switch (op->opcode)
+ {
+ case Opcode_CRLF:
+ case Opcode_PRINT:
+ case Opcode_QUIT:
+ break;
+
+ case Opcode_PRINTI:
+ case Opcode_PRINTR:
+ {
+ char *p = (char *)a + len;
+ p = (char *)pass_spaces(p);
+ if (*p == '\"')
+ {
+ p++;
+ string str;
+ while (*p != '\"')
+ {
+ str += *p;
+ ++p;
+ }
+ len = p - a;
+ mem_additional =
+ String_table::encrypt_string(str.c_str(), NULL);
+ }
+ break;
+ }
+ default:
+ {
+ display_error = true;
+ }
+ }
+
+
+ if (display_error == false)
+ {
+
+ int instruction_size = 1;
+ if (mem_additional)
+ instruction_size += mem_additional->used_size;
+
+ g_codes[g_number_of_instructions] = zmem_init(instruction_size);
+ zmem_putbyte(g_codes[g_number_of_instructions], op->opcode);
+
+ if (mem_additional)
+ {
+ for (int i = 0; i < mem_additional->used_size; ++i)
+ zmem_putbyte(g_codes[g_number_of_instructions],
+ mem_additional->contents[i]);
+ zmem_destroy(mem_additional);
+ }
+
+ ++g_number_of_instructions;
+ return len;
+ }
+ }
+ else
+ {
+ //display_error = true;
+ string message = "wrong line \"" + string(a) + string("\"");
+ fatal_error(build_error_message(message.c_str()).c_str());
+ }
}
- int instruction_size = 1;
- if (mem_additional)
- instruction_size += mem_additional->used_size;
- //printf("instruction %s", a);
-
- g_codes[g_numberOfInstructions] = zmem_init (instruction_size);
- zmem_putbyte (g_codes[g_numberOfInstructions], op->opcode);
-
- if (mem_additional)
+ if (display_error)
{
- for (int i = 0; i < mem_additional->used_size; ++i)
- zmem_putbyte (g_codes[g_numberOfInstructions],
- mem_additional->contents[i]);
- zmem_destroy (mem_additional);
+ char buff[300];
+ if (len == 0)
+ len = strlen(a);
+ char *instrcution_name = (char *)malloc(len + 1);
+ memcpy(instrcution_name, a, len);
+ instrcution_name[len] = 0;
+ string message = "instruction " + string(instrcution_name) + string(" is not supported yet");
+ fatal_error(build_error_message(message.c_str()).c_str());
+ free(instrcution_name);
}
- ++g_numberOfInstructions;
- return len;
- }
-
- return 0;
+ return strlen(a);
}
return n; // ..label or assignment
if (n = tryparse_instruction (p))
return n;
- fatal_error ("wrong line");
+ //fatal_error ("wrong line");
}
return 0;
}
#define MAX_LINESIZE 1024
int
-parse_file (const char *filename)
+parse_file (/*const char *filename*/)
{
- FILE *fp = fopen (filename, "r");
- if (!fp)
- fatal_error ("wrong file");
+ if (g_parsing_contexts.size() > 0)
+ {
+ string filename = g_parsing_contexts.top().current_directory + g_parsing_contexts.top().current_file_name;
- //const int MAX_LINESIZE = 1024;
- char line[MAX_LINESIZE];
- int newline_missing = 0;
+ FILE *fp = fopen(filename.c_str(), "r");
+ if (fp)
+ {
- while (fgets (line, MAX_LINESIZE, fp))
- {
- if (newline_missing)
- fatal_error ("line too long");
+ g_currentLineNumber = 0;
- int n = strlen (line);
- if (!n)
- continue;
+ //const int MAX_LINESIZE = 1024;
+ char line[MAX_LINESIZE];
+ int newline_missing = 0;
- parse_line (line);
+ while (g_stopParsing == 0 && fgets(line, MAX_LINESIZE, fp))
+ {
+ ++g_currentLineNumber;
- newline_missing = (line[n - 1] != '\n');
- }
+ if (newline_missing)
+ fatal_error(build_error_message("line too long").c_str());
- fclose (fp);
- return 0;
+ int n = strlen(line);
+ if (!n)
+ continue;
+
+ parse_line(line);
+
+ newline_missing = (line[n - 1] != '\n');
+ }
+
+ fclose(fp);
+ }
+ else
+ {
+ string message = string("can't open file ") + filename;
+ fatal_error(message.c_str());
+ }
+
+ g_parsing_contexts.pop();
+ }
+ return 0;
}
/*
void
init_parser ()
{
- g_numberOfInstructions = 0;
+ g_number_of_instructions = 0;
}
+
+
+
void
relase_parser ()
{
- for (int i = 0; i < g_numberOfInstructions; ++i)
+ for (int i = 0; i < g_number_of_instructions; ++i)
{
zmem_destroy (g_codes[i]);
}
- g_numberOfInstructions = 0;
+ g_number_of_instructions = 0;
}
/*
* parser.h -- part of ZilUtils/ZilAsm
*
- * Copyright (C) 2016, 2019 Jason Self <j@jxself.org>
+ * Copyright (C) 2016, 2019, 2020 Jason Self <j@jxself.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
void init_parser ();
-int parse_file (const char *filename);
+int parse_file();// const char *filename);
-extern unsigned g_numberOfInstructions;
+extern unsigned g_number_of_instructions;
#define MAX_NUMBER_OF_INSTRUCTIONS 65536
extern ZMemblock (*g_codes[MAX_NUMBER_OF_INSTRUCTIONS]);
+struct Parsing_Context
+{
+ string current_directory;
+ string current_file_name;
+};
+
+extern stack<Parsing_Context> g_parsing_contexts;
+extern unsigned g_currentLineNumber;
+extern bool g_haveErrors;
+
#endif /* ifndef ZILASM_PARSER */
/*
* string_table.cpp -- part of ZilUtils/ZilAsm
*
- * Copyright (C) 2019 Jason Self <j@jxself.org>
+ * Copyright (C) 2019, 2020 Jason Self <j@jxself.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
}
else if (c == ' ')
{
- write_one_word_to_string_table (zmb, &w, &numberOfSymbolsInWord, 0);
+ //if (numberOfSymbolsInWord != 0)
+ //{
+ // zmem_putbyte(zmb, (w >> 8) & 255);
+ // zmem_putbyte(zmb, w & 255);
+ // numberOfSymbolsInWord = 0;
+ // w = 0;
+ //}
+ write_one_word_to_string_table (zmb, &w, &numberOfSymbolsInWord, 0);
}
else
{
numberOfSymbolsInWord = 0;
w = 0;
}
- zmb->contents[zmb->used_size - 2] |= 0x80;
+
+ if ((zmb->contents[zmb->used_size - 1] & 31) == 0) // if the last symbol is a space or not filled
+ zmb->contents[zmb->used_size - 2] |= 0x80; // then we mark this word as the last word
+ else
+ {
+ zmem_putbyte(zmb, 0x80); // otherwise we add one more empty word
+ zmem_putbyte(zmb, 0x0); // with 15-th bit set
+ }
return zmb;
}