inital commit

This commit is contained in:
zongor 2023-02-04 14:06:00 -05:00
parent 70c12e6706
commit 02d37d3bcc
20 changed files with 3316 additions and 3 deletions

1
.clang-format Normal file
View File

@ -0,0 +1 @@
BasedOnStyle: GNU

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.ccls-cache/
*.mod
*.wasm
varaq

10
Makefile Normal file
View File

@ -0,0 +1,10 @@
CC = gcc
CCFLAGS= -g
all: varaq
varaq:
$(CC) $(CCFLAGS) -o varaq main.c compiler.c tokenizer.c
clean:
rm -f *.o varaq

View File

@ -1,5 +1,7 @@
# varaq-wasm-c # varaq-wasm-c
Playing around with wasm. Playing around with wasm.
Creating a compiler in C for var'aq Creating a wasm compiler in C for var'aq
*very early wip*

15
common.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef COMMON_H
#define COMMON_H
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#endif

340
compiler.c Normal file
View File

@ -0,0 +1,340 @@
#include "compiler.h"
#include "common.h"
#include "tokenizer.h"
Code *
signedLEB128 (size_t num)
{
bool more = true;
Code *buffer = (Code *)malloc (sizeof (Code));
buffer->count = 0;
int n = (int)num;
while (more)
{
uint8_t byte = n & 0x7f;
n >>= 7;
if ((n == 0 && (byte & 0x40) == 0) || (n == -1 && (byte & 0x40) != 0))
{
more = false;
}
else
{
byte |= 0x80;
}
size_t old_count = buffer->count;
uint8_t *tmp = (uint8_t *)calloc (
(old_count + 1),
sizeof (uint8_t)); // really slow and bad refactor later
memcpy (tmp, buffer->cells, buffer->count * sizeof (uint8_t));
if (tmp)
{
buffer->cells = tmp;
}
buffer->cells[old_count] = byte;
buffer->count += 1;
}
return buffer;
}
Code *
unsignedLEB128 (size_t num)
{
Code *buffer = (Code *)malloc (sizeof (Code));
buffer->count = 0;
int n = (int)num;
do
{
uint8_t byte = n & 0x7f;
n >>= 7;
if (n != 0)
{
byte |= 0x80;
}
size_t old_count = buffer->count;
uint8_t *tmp = (uint8_t *)calloc (
(old_count + 1),
sizeof (uint8_t)); // really slow and bad refactor later
memcpy (tmp, buffer->cells, buffer->count * sizeof (uint8_t));
if (tmp)
{
buffer->cells = tmp;
}
buffer->cells[old_count] = byte;
buffer->count += 1;
}
while (n != 0);
return buffer;
}
Code *
append_byte (Code *tape, uint8_t data)
{
size_t old_count = tape->count;
uint8_t *tmp = (uint8_t *)calloc ((old_count + 1), sizeof (uint8_t));
if (old_count > 0)
{
memcpy (tmp, tape->cells, tape->count * sizeof (uint8_t));
}
if (tmp)
{
tape->cells = tmp;
}
tape->cells[old_count] = data;
tape->count += 1;
return tape;
}
Code *
append_f64 (Code *tape, double data)
{
size_t old_count = tape->count;
uint8_t *tmp
= (uint8_t *)calloc ((old_count + sizeof (data)), sizeof (uint8_t));
if (old_count > 0)
{
memcpy (tmp, tape->cells, tape->count * sizeof (uint8_t));
}
if (tmp)
{
tape->cells = tmp;
}
memcpy ((tape->cells + old_count), (unsigned char *)&data, sizeof (data));
tape->count += sizeof (data);
return tape;
}
Code *
append (Code *tape, Code *data)
{
size_t old_count = tape->count;
uint8_t *tmp
= (uint8_t *)calloc ((old_count + data->count), sizeof (uint8_t));
memcpy (tmp, tape->cells, tape->count * sizeof (uint8_t));
if (tmp)
{
tape->cells = tmp;
}
memcpy ((tape->cells + old_count), data->cells,
data->count * sizeof (uint8_t));
tape->count += data->count;
return tape;
}
Code *
encodeString (char *string)
{
Code *buffer = (Code *)malloc (sizeof (Code));
buffer->cells = (uint8_t *)malloc (sizeof (uint8_t));
buffer->cells[0] = strlen (string);
buffer->count = 1;
uint8_t *tmp = (uint8_t *)malloc ((1 + strlen (string)) * sizeof (char));
memcpy (tmp, buffer->cells, buffer->count * sizeof (uint8_t));
if (tmp)
{
buffer->cells = tmp;
}
memcpy ((buffer->cells + 1), string, strlen (string) * sizeof (char));
buffer->count += strlen (string);
return buffer;
}
Code *
encodeVector (Code *data)
{
size_t count = data->override ? data->override_count : data->count;
Code *buffer = unsignedLEB128 (count);
append (buffer, data);
return buffer;
}
Code *
createSection (uint8_t section, Code *data)
{
Code *buffer = (Code *)malloc (sizeof (Code));
buffer->cells = (uint8_t *)malloc (sizeof (uint8_t));
buffer->cells[0] = section;
buffer->count = 1;
return append (buffer, encodeVector (data));
}
Code *
demo_function_compile ()
{
Code *add_args_code = (Code *)calloc (1, sizeof (Code));
append_byte (add_args_code, f32);
append_byte (add_args_code, f32);
Code *add_return_code = (Code *)calloc (1, sizeof (Code));
append_byte (add_return_code, f32);
Code *add_function_type = (Code *)calloc (1, sizeof (Code));
append_byte (add_function_type, FUNCTION);
append (add_function_type, encodeVector (add_args_code));
append (add_function_type, encodeVector (add_return_code));
add_function_type->override = true;
add_function_type->override_count = 1;
Code *type_section = createSection (TYPE, encodeVector (add_function_type));
Code *return_type_code = (Code *)calloc (1, sizeof (Code));
append_byte (return_type_code, 0x00);
return_type_code->override = true;
return_type_code->override_count = 1;
Code *func_section = createSection (FUNC, encodeVector (return_type_code));
Code *exp = encodeString ("main");
append_byte (exp, EXPORT_FUNC);
append_byte (exp, 0x00);
exp->override = true;
exp->override_count = 1;
Code *export_section = createSection (EXPORT, encodeVector (exp));
Code *code = (Code *)calloc (1, sizeof (Code));
append_byte (code, LOCAL_GET);
append (code, unsignedLEB128 (0));
append_byte (code, LOCAL_GET);
append (code, unsignedLEB128 (1));
append_byte (code, F32_ADD);
Code *body = (Code *)calloc (1, sizeof (Code));
append_byte (body, EMPTY_ARRAY);
append (body, code);
append_byte (body, END);
Code *function_body = (Code *)calloc (1, sizeof (Code));
append (function_body, encodeVector (body));
function_body->override = true;
function_body->override_count = 1;
Code *code_section = createSection (CODE, encodeVector (function_body));
Code *tape = (Code *)malloc (sizeof (Code));
tape->cells = calloc (8, sizeof (uint8_t));
tape->cells[0] = 0;
tape->cells[1] = 'a';
tape->cells[2] = 's';
tape->cells[3] = 'm';
tape->cells[4] = 1;
tape->cells[5] = 0;
tape->cells[6] = 0;
tape->cells[7] = 0;
tape->count = 8;
append (tape, type_section);
append (tape, func_section);
append (tape, export_section);
append (tape, code_section);
return tape;
}
Code *
demo_add_compile ()
{
Code *add_args_code = (Code *)calloc (1, sizeof (Code));
Code *add_return_code = (Code *)calloc (1, sizeof (Code));
append_byte (add_return_code, f64);
Code *add_function_type = (Code *)calloc (1, sizeof (Code));
append_byte (add_function_type, FUNCTION);
append (add_function_type, encodeVector (add_args_code));
append (add_function_type, encodeVector (add_return_code));
add_function_type->override = true;
add_function_type->override_count = 1;
Code *type_section = createSection (TYPE, encodeVector (add_function_type));
Code *return_type_code = (Code *)calloc (1, sizeof (Code));
append_byte (return_type_code, 0x00);
return_type_code->override = true;
return_type_code->override_count = 1;
Code *func_section = createSection (FUNC, encodeVector (return_type_code));
Code *exp = encodeString ("main");
append_byte (exp, EXPORT_FUNC);
append_byte (exp, 0x00);
exp->override = true;
exp->override_count = 1;
Code *export_section = createSection (EXPORT, encodeVector (exp));
Code *code = (Code *)calloc (1, sizeof (Code));
append_byte (code, F64_CONST);
append_f64 (code, 6.7);
append_byte (code, F64_CONST);
append_f64 (code, 8.5);
append_byte (code, F64_ADD);
Code *body = (Code *)calloc (1, sizeof (Code));
append_byte (body, EMPTY_ARRAY);
append (body, code);
append_byte (body, END);
Code *function_body = (Code *)calloc (1, sizeof (Code));
append (function_body, encodeVector (body));
function_body->override = true;
function_body->override_count = 1;
Code *code_section = createSection (CODE, encodeVector (function_body));
Code *tape = (Code *)malloc (sizeof (Code));
tape->cells = calloc (8, sizeof (uint8_t));
tape->cells[0] = 0;
tape->cells[1] = 'a';
tape->cells[2] = 's';
tape->cells[3] = 'm';
tape->cells[4] = 1;
tape->cells[5] = 0;
tape->cells[6] = 0;
tape->cells[7] = 0;
tape->count = 8;
append (tape, type_section);
append (tape, func_section);
append (tape, export_section);
append (tape, code_section);
return tape;
}
Code *
compile (char *buffer)
{
Code *tape = (Code *)malloc (sizeof (Code));
tape->cells = calloc (8, sizeof (uint8_t));
tape->cells[0] = 0;
tape->cells[1] = 'a';
tape->cells[2] = 's';
tape->cells[3] = 'm';
tape->cells[4] = 1;
tape->cells[5] = 0;
tape->cells[6] = 0;
tape->cells[7] = 0;
tape->count = 8;
initTokenizer (buffer);
Token t = nextToken ();
while (t.type != TOKEN_EOF)
{
debug_printToken (t);
t = nextToken ();
}
return tape;
}

259
compiler.h Normal file
View File

@ -0,0 +1,259 @@
#ifndef COMPILER_H
#define COMPILER_H
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
typedef enum Opcodes
{
UNREACHABLE = 0,
NOP = 1,
BLOCK = 2,
LOOP = 3,
IF = 4,
ELSE = 5,
TRY = 6, // PROPOSED
CATCH = 7, // PROPOSED
THROW = 8, // PROPOSED
RETHROW = 9, // PROPOSED
BR_ON_EXN = 10, // PROPOSED
END = 11,
BR = 12,
BR_IF = 13,
BR_TABLE = 14,
RETURN = 15,
CALL = 16,
CALL_INDIRECT = 17,
RETURN_CALL = 18, // PROPOSED
RETURN_CALL_INDIRECT = 19, // PROPOSED
DROP = 26,
SELECT = 27,
SELECT_T = 28, // PROPOSED
LOCAL_GET = 32,
LOCAL_SET = 33,
LOCAL_TEE = 34,
GLOBAL_GET = 35,
GLOBAL_SET = 36,
TABLE_GET = 37, // PROPOSED
TABLE_SET = 38, // PROPOSED
I32_LOAD = 40,
I64_LOAD = 41,
F32_LOAD = 42,
F64_LOAD = 43,
I32_LOAD8_S = 44,
I32_LOAD8_U = 45,
I32_LOAD16_S = 46,
I32_LOAD16_U = 47,
I64_LOAD8_S = 48,
I64_LOAD8_U = 49,
I64_LOAD16_S = 50,
I64_LOAD16_U = 51,
I64_LOAD32_S = 52,
I64_LOAD32_U = 53,
I32_STORE = 54,
I64_STORE = 55,
F32_STORE = 56,
F64_STORE = 57,
I32_STORE8 = 58,
I32_STORE16 = 59,
I64_STORE8 = 60,
I64_STORE16 = 61,
I64_STORE32 = 62,
MEMORY_SIZE = 63,
MEMORY_GROW = 64,
I32_CONST = 65,
I64_CONST = 66,
F32_CONST = 67,
F64_CONST = 68,
I32_EQZ = 69,
I32_EQ = 70,
I32_NE = 71,
I32_LT_S = 72,
I32_LT_U = 73,
I32_GT_S = 74,
I32_GT_U = 75,
I32_LE_S = 76,
I32_LE_U = 77,
I32_GE_S = 78,
I32_GE_U = 79,
I64_EQZ = 80,
I64_EQ = 81,
I64_NE = 82,
I64_LT_S = 83,
I64_LT_U = 84,
I64_GT_S = 85,
I64_GT_U = 86,
I64_LE_S = 87,
I64_LE_U = 88,
I64_GE_S = 89,
I64_GE_U = 90,
F32_EQ = 91,
F32_NE = 92,
F32_LT = 93,
F32_GT = 94,
F32_LE = 95,
F32_GE = 96,
F64_EQ = 97,
F64_NE = 98,
F64_LT = 99,
F64_GT = 100,
F64_LE = 101,
F64_GE = 102,
I32_CLZ = 103,
I32_CTZ = 104,
I32_POPCNT = 105,
I32_ADD = 106,
I32_SUB = 107,
I32_MUL = 108,
I32_DIV_S = 109,
I32_DIV_U = 110,
I32_REM_S = 111,
I32_REM_U = 112,
I32_AND = 113,
I32_OR = 114,
I32_XOR = 115,
I32_SHL = 116,
I32_SHR_S = 117,
I32_SHR_U = 118,
I32_ROTL = 119,
I32_ROTR = 120,
I64_CLZ = 121,
I64_CTZ = 122,
I64_POPCNT = 123,
I64_ADD = 124,
I64_SUB = 125,
I64_MUL = 126,
I64_DIV_S = 127,
I64_DIV_U = 128,
I64_REM_S = 129,
I64_REM_U = 130,
I64_AND = 131,
I64_OR = 132,
I64_XOR = 133,
I64_SHL = 134,
I64_SHR_S = 135,
I64_SHR_U = 136,
I64_ROTL = 137,
I64_ROTR = 138,
F32_ABS = 139,
F32_NEG = 140,
F32_CEIL = 141,
F32_FLOOR = 142,
F32_TRUNC = 143,
F32_NEAREST = 144,
F32_SQRT = 145,
F32_ADD = 146,
F32_SUB = 147,
F32_MUL = 148,
F32_DIV = 149,
F32_MIN = 150,
F32_MAX = 151,
F32_COPYSIGN = 152,
F64_ABS = 153,
F64_NEG = 154,
F64_CEIL = 155,
F64_FLOOR = 156,
F64_TRUNC = 157,
F64_NEAREST = 158,
F64_SQRT = 159,
F64_ADD = 160,
F64_SUB = 161,
F64_MUL = 162,
F64_DIV = 163,
F64_MIN = 164,
F64_MAX = 165,
F64_COPYSIGN = 166,
I32_WRAP_I64 = 167,
I32_TRUNC_F32_S = 168,
I32_TRUNC_F32_U = 169,
I32_TRUNC_F64_S = 170,
I32_TRUNC_F64_U = 171,
I64_EXTEND_I32_S = 172,
I64_EXTEND_I32_U = 173,
I64_TRUNC_F32_S = 174,
I64_TRUNC_F32_U = 175,
I64_TRUNC_F64_S = 176,
I64_TRUNC_F64_U = 177,
F32_CONVERT_I32_S = 178,
F32_CONVERT_I32_U = 179,
F32_CONVERT_I64_S = 180,
F32_CONVERT_I64_U = 181,
F32_DEMOTE_F64 = 182,
F64_CONVERT_I32_S = 183,
F64_CONVERT_I32_U = 184,
F64_CONVERT_I64_S = 185,
F64_CONVERT_I64_U = 186,
F64_PROMOTE_F32 = 187,
I32_REINTERPRET_F32 = 188,
I64_REINTERPRET_F64 = 189,
F32_REINTERPRET_I32 = 190,
F64_REINTERPRET_I64 = 191,
OP_NULL = 0xD0,
IS_NULL = 0xD1,
REF_FUNC = 0xD2,
} Opcodes;
typedef enum Types
{
i32 = 0x7F,
i64 = 0x7E,
f32 = 0x7D,
f64 = 0x7C,
v128 = 0x7B,
funcref = 0x70,
externref = 0x6F,
} Types;
typedef enum FunctionTypes
{
EMPTY_ARRAY = 0,
FUNCTION = 96
} FunctionTypes;
typedef enum ExportTypes
{
EXPORT_FUNC = 0,
EXPORT_TABLE = 1,
EXPORT_MEM = 2,
EXPORT_GLOBAL = 3
} ExportTypes;
typedef enum Section
{
CUSTOM = 0,
TYPE = 1,
IMPORT = 2,
FUNC = 3,
TABLE = 4,
MEMORY = 5,
GLOBAL = 6,
EXPORT = 7,
START = 8,
ELEMENT = 9,
CODE = 10,
DATA = 11
} Section;
typedef struct Code Code;
struct Code
{
uint8_t *cells;
size_t count;
bool override;
size_t override_count;
};
Code *signedLEB128 (size_t num);
Code *unsignedLEB128 (size_t num);
Code *append_byte (Code *tape, uint8_t data);
Code *append (Code *tape, Code *data);
Code *encodeString (char *string);
Code *encodeVector (Code *data);
Code *createSection (uint8_t section, Code *data);
Code *demo_function_compile ();
Code *demo_add_compile ();
Code *compile (char *buffer);
#endif

141
docs/current.html Normal file
View File

@ -0,0 +1,141 @@
<title>var'aq Reference Implementation 9/20/2000</title>
<h1><i>var'aq</i> Release Notes</h1><p>
<hr>
<i>maintained by <a href="mailto:connorbd@yahoo.com">Brian Connors</a><br>
revised 2 January 2001</i><p>
<h3>Version Information</h3>
This is the status of the <i>var'aq</i> project as of 20 September 2000. <p>
This is the <b>Azetbur</b> release, after Chancellor Gorkon's daughter and successor in <i>Star Trek VI: The Undiscovered Country</i>.<p>
<h3>Status Summary</h3><p>
We are moving ahead! Console I/O (on a very rudimentary level) is here, as well as much of the mathematical functionality and string handling. Lists are not here yet, and a more robust I/O model must await a better understanding of Klingon hacker culture to understand issues like authentication and how distributed processing might be used. <p>
This release is approaching usability. Files are not here yet (still under discussion), but there is console-level I/O and enough string support to do something useful. <p>
<a href="mailto:jproctor@oit.umass.edu">j proctor</a> from the <i>varaq-dev</i> mailing list has contributed some sample code and a more flexible translator program than the one I wrote and distributed. His interpreter will be found in the <i>translators</i> directory.<p>
<h3>Interpreter Status</h3><p>
The interpreter is available with both Klingon and English keywords; however, keep in mind that maintenance is done mostly on the English version and the translator program is not ready for prime time. This will be fixed eventually.<p>
The following keywords are currently supported:<p>
<ul>
<li>Control Structures
<ul>
<li><b>ifyes/HIja'chugh</b>
<li><b>ifno/ghobe'chugh</b>
<li><b>choose/wIv</b>
<li><b>~ (quote/lI'moH)</b>
<li><b>name/pong</b>
<li><b>set/cher</b>
<li><b>repeat/vangqa'</b>
<li><b>eval/chov</b>
</ul>
<p>
<li>Stack Operations
<ul>
<li><b>pop/woD</b>
<li><b>dup/latlh</b>
<li><b>exch/tam</b>
<li><b>clear/chImmoH</b>
<li><b>remember/qaw</b>
<li><b>forget/qawHa'</b>
</ul>
<p>
<li>Arithmetic Operators
<ul>
<li><b>add/boq</b>
<li><b>sub/boqHa'</b>
<li><b>mul/boq'egh</b>
<li><b>div/boqHa'egh</b>
<li><b>mod/chuv</b>
<li><b>pow/law'qa'moH</b>
<li><b>rand/mIS</b>
<li><b>add1/wa'boq</b>
<li><b>sub1/wa'boqHa'</b>
<li><b>pi/HeHmI'</b>
<li><b>e/ghurmi'</b>
<li><b>clip/poD</b>
<li><b>smooth/Hab</b>
<li><b>howmuch/'ar</b>
</ul>
<p>
<li>Trig/Log operators
<ul>
<li><b>sin/joq</b>
<li><b>cos/joqHa'</b>
<li><b>tan/qojmI'</b>
<li><b>atan/qojHa'</b>
<li><b>ln/ghurtaH</b>
</ul>
<p>
<li>Relational Operators<p>
All relational operators have been implemented. Thanks to j proctor for <b>null?/pagh'a', negative?/taH'a', int?/HabmI''a'</b>, and <b>number/mI''a'</b>.<p>
<li>I/O Operators<p>
The <i>var'aq</i> I/O model remains to be defined, but the basic console I/O functions are now present. <p>
<li>List Operators<p>
List support does not exist yet.<p>
<li>String Operators<p>
The current set of operators is sufficient to implement the others in the spec, but they are a lower priority.</b>
<ul>
<li><b>strtie/tlheghrar</b>
<li><b>streq?/tlheghrap'a'</b>
<li><b>strcut/tlhleghpe'</b>
<li><b>strmeasure/tlheghjuv</b>
<li><b>compose/naQmoH</b>
</ul>
</ul>
<h4>Implementation Issues and/or Bug Fixes</h4><p>
<ul>
<li>The interpreter now knows to ignore hashbang (i.e. #!/usr/bin/varaq-whatever) lines. They can double as end-of-line comments if you like, but you really shouldn't; these are here primarily to allow the forthcoming <i>vqmake</i> program to spit out program files that a Unix shell can execute directly (which would be .vqx files on any other platform).
<li>Took the "\t" out of disp/cha' to facilitate a possible CGI conversion. Better formatted output will be a priority very shortly.
<li>The interpreter also doesn't see lines beginning with //. This is to allow for static linking of .vql files (though if someone wants to implement <i>var'aq</i> "shared libraries" I'll be glad to add the revs to the interpreter).
<li>Cleaned up the execution logic a bit -- the code to execute a proc object was already in there about four times and was about to go in again for compose/naqmoH, so I abstracted it into a routine called execblock() per Chris' advice (RTFC).
<li>Merged in j proctor's additions.
</ul>
<h3>Specification Status</h3><p>
A few changes:<p>
<ul>
<li>A number of operators have been added:
<ul>
<li><b>//<i>name</i></b> -- equivalent to C <code>#include</code>.
<li>Numerous "constants" (actually more like environment variables).
</ul>
<li>Several operators have been renamed:
<ul>
<li><b>strcat</b> is now <b>strtie</b> to bring it in line with the Klingon <b>tlheghrar</b>.
<li>The basic arithmetic operators have been given new
Klingon names to coincide with recent additions to the Klingon linguistic
canon.
</ul>
<li>More coinages in the section headings.
</ul>
<h3>Acknowledgements</h3><p>
The <a href="http://www.egroups.com/group/varaq-dev">varaq-dev</a> mailing
list, especially <a href="mailto:jproctor@oit.umass.edu">j proctor</a> for
his code contributions and Alan Anderson for providing the canonical
Klingon math operators, and to Glenn Gaslin for the impetus to finally
get this thing out the freakin' door. <p>
<hr>
Click <a href="http://www.geocities.com/connorbd/varaq">here</a> to go to the <i>var'aq</i> home page.

View File

@ -0,0 +1,273 @@
<script src="//archive.org/includes/analytics.js?v=cf34f82" type="text/javascript"></script>
<script type="text/javascript">window.addEventListener('DOMContentLoaded',function(){var v=archive_analytics.values;v.service='wb';v.server_name='wwwb-app226.us.archive.org';v.server_ms=201;archive_analytics.send_pageview({});});</script>
<script type="text/javascript" src="/_static/js/bundle-playback.js?v=UfTkgsKx" charset="utf-8"></script>
<script type="text/javascript" src="/_static/js/wombat.js?v=UHAOicsW" charset="utf-8"></script>
<script type="text/javascript">
__wm.init("https://web.archive.org/web");
__wm.wombat("http://geocities.com/connorbd/varaq/proposals/vqfs.html","20091026220614","https://web.archive.org/","web","/_static/",
"1256594774");
</script>
<link rel="stylesheet" type="text/css" href="/_static/css/banner-styles.css?v=omkqRugM" />
<link rel="stylesheet" type="text/css" href="/_static/css/iconochive.css?v=qtvMKcIJ" />
<!-- End Wayback Rewrite JS Include -->
<title>var'aq Filesystem Supplement</title>
<!-- BEGIN WAYBACK TOOLBAR INSERT -->
<style type="text/css">
body {
margin-top:0 !important;
padding-top:0 !important;
/*min-width:800px !important;*/
}
</style>
<script>__wm.rw(0);</script>
<div id="wm-ipp-base" lang="en" style="display:none;direction:ltr;">
<div id="wm-ipp" style="position:fixed;left:0;top:0;right:0;">
<div id="wm-ipp-inside">
<div style="position:relative;">
<div id="wm-logo" style="float:left;width:110px;padding-top:12px;">
<a href="/web/" title="Wayback Machine home page"><img src="/_static/images/toolbar/wayback-toolbar-logo-200.png" srcset="/_static/images/toolbar/wayback-toolbar-logo-100.png, /_static/images/toolbar/wayback-toolbar-logo-150.png 1.5x, /_static/images/toolbar/wayback-toolbar-logo-200.png 2x" alt="Wayback Machine" style="width:100px" border="0" /></a>
</div>
<div class="r" style="float:right;">
<div id="wm-btns" style="text-align:right;height:25px;">
<div id="wm-save-snapshot-success">success</div>
<div id="wm-save-snapshot-fail">fail</div>
<a id="wm-save-snapshot-open" href="#"
title="Share via My Web Archive" >
<span class="iconochive-web"></span>
</a>
<a href="https://archive.org/account/login.php"
title="Sign In"
id="wm-sign-in"
>
<span class="iconochive-person"></span>
</a>
<span id="wm-save-snapshot-in-progress" class="iconochive-web"></span>
<a href="http://faq.web.archive.org/" title="Get some help using the Wayback Machine" style="top:-6px;"><span class="iconochive-question" style="color:rgb(87,186,244);font-size:160%;"></span></a>
<a id="wm-tb-close" href="#close" onclick="__wm.h(event);return false;" style="top:-2px;" title="Close the toolbar"><span class="iconochive-remove-circle" style="color:#888888;font-size:240%;"></span></a>
</div>
<div id="wm-share">
<a href="/web/20091026220614/http://web.archive.org/screenshot/http://geocities.com/connorbd/varaq/proposals/vqfs.html"
id="wm-screenshot"
title="screenshot">
<span class="wm-icon-screen-shot"></span>
</a>
<a href="#"
id="wm-video"
title="video">
<span class="iconochive-movies"></span>
</a>
<a id="wm-share-facebook" href="#" data-url="https://web.archive.org/web/20091026220614/http://geocities.com/connorbd/varaq/proposals/vqfs.html" title="Share on Facebook" style="margin-right:5px;" target="_blank"><span class="iconochive-facebook" style="color:#3b5998;font-size:160%;"></span></a>
<a id="wm-share-twitter" href="#" data-url="https://web.archive.org/web/20091026220614/http://geocities.com/connorbd/varaq/proposals/vqfs.html" title="Share on Twitter" style="margin-right:5px;" target="_blank"><span class="iconochive-twitter" style="color:#1dcaff;font-size:160%;"></span></a>
</div>
</div>
<table class="c" style="">
<tbody>
<tr>
<td class="u" colspan="2">
<form target="_top" method="get" action="/web/submit" name="wmtb" id="wmtb"><input type="text" name="url" id="wmtbURL" value="http://geocities.com/connorbd/varaq/proposals/vqfs.html" onfocus="this.focus();this.select();" /><input type="hidden" name="type" value="replay" /><input type="hidden" name="date" value="20091026220614" /><input type="submit" value="Go" /></form>
</td>
<td class="n" rowspan="2" style="width:110px;">
<table>
<tbody>
<!-- NEXT/PREV MONTH NAV AND MONTH INDICATOR -->
<tr class="m">
<td class="b" nowrap="nowrap"><a href="https://web.archive.org/web/20090830125352/http://geocities.com/connorbd/varaq/proposals/vqfs.html" title="30 Aug 2009"><strong>Aug</strong></a></td>
<td class="c" id="displayMonthEl" title="You are here: 22:06:14 Oct 26, 2009">OCT</td>
<td class="f" nowrap="nowrap">Nov</td>
</tr>
<!-- NEXT/PREV CAPTURE NAV AND DAY OF MONTH INDICATOR -->
<tr class="d">
<td class="b" nowrap="nowrap"><a href="https://web.archive.org/web/20091024132344/http://geocities.com/connorbd/varaq/proposals/vqfs.html" title="13:23:44 Oct 24, 2009"><img src="/_static/images/toolbar/wm_tb_prv_on.png" alt="Previous capture" width="14" height="16" border="0" /></a></td>
<td class="c" id="displayDayEl" style="width:34px;font-size:24px;white-space:nowrap;" title="You are here: 22:06:14 Oct 26, 2009">26</td>
<td class="f" nowrap="nowrap"><img src="/_static/images/toolbar/wm_tb_nxt_off.png" alt="Next capture" width="14" height="16" border="0" /></td>
</tr>
<!-- NEXT/PREV YEAR NAV AND YEAR INDICATOR -->
<tr class="y">
<td class="b" nowrap="nowrap"><a href="https://web.archive.org/web/20030415033054/http://www.geocities.com:80/connorbd/varaq/proposals/vqfs.html" title="15 Apr 2003"><strong>2003</strong></a></td>
<td class="c" id="displayYearEl" title="You are here: 22:06:14 Oct 26, 2009">2009</td>
<td class="f" nowrap="nowrap">2010</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td class="s">
<div id="wm-nav-captures">
<a class="t" href="/web/20091026220614*/http://geocities.com/connorbd/varaq/proposals/vqfs.html" title="See a list of every capture for this URL">5 captures</a>
<div class="r" title="Timespan for captures of this URL">24 Feb 2003 - 26 Oct 2009</div>
</div>
</td>
<td class="k">
<a href="" id="wm-graph-anchor">
<div id="wm-ipp-sparkline" title="Explore captures for this URL" style="position: relative">
<canvas id="wm-sparkline-canvas" width="650" height="27" border="0"></canvas>
</div>
</a>
</td>
</tr>
</tbody>
</table>
<div style="position:absolute;bottom:0;right:2px;text-align:right;">
<a id="wm-expand" class="wm-btn wm-closed" href="#expand" onclick="__wm.ex(event);return false;"><span id="wm-expand-icon" class="iconochive-down-solid"></span> <span style="font-size:80%">About this capture</span></a>
</div>
</div>
<div id="wm-capinfo" style="border-top:1px solid #777;display:none; overflow: hidden">
<div id="wm-capinfo-collected-by">
<div style="background-color:#666;color:#fff;font-weight:bold;text-align:center">COLLECTED BY</div>
<div style="padding:3px;position:relative" id="wm-collected-by-content">
<div style="display:inline-block;vertical-align:top;width:50%;">
<span class="c-logo" style="background-image:url(https://archive.org/services/img/webwidecrawl);"></span>
Organization: <a style="color:#33f;" href="https://archive.org/details/webwidecrawl" target="_new"><span class="wm-title">Internet Archive</span></a>
<div style="max-height:75px;overflow:hidden;position:relative;">
<div style="position:absolute;top:0;left:0;width:100%;height:75px;background:linear-gradient(to bottom,rgba(255,255,255,0) 0%,rgba(255,255,255,0) 90%,rgba(255,255,255,255) 100%);"></div>
The Internet Archive discovers and captures web pages through many different web crawls.
At any given time several distinct crawls are running, some for months, and some every day or longer.
View the web archive through the <a href="http://archive.org/web/web.php">Wayback Machine</a>.
</div>
</div>
<div style="display:inline-block;vertical-align:top;width:49%;">
<span class="c-logo" style="background-image:url(https://archive.org/services/img/geocities)"></span>
<div>Collection: <a style="color:#33f;" href="https://archive.org/details/geocities" target="_new"><span class="wm-title">Geocities Closing Crawl</span></a></div>
<div style="max-height:75px;overflow:hidden;position:relative;">
<div style="position:absolute;top:0;left:0;width:100%;height:75px;background:linear-gradient(to bottom,rgba(255,255,255,0) 0%,rgba(255,255,255,0) 90%,rgba(255,255,255,255) 100%);"></div>
Geocities crawl performed by Internet Archive. This data is currently not publicly accessible.
<br /><br />
from <a href="https://en.wikipedia.org/wiki/Geocities">Wikipedia</a>:
<br />
Yahoo! GeoCities is a Web hosting service. GeoCities was originally founded by David Bohnett and John Rezner in late 1994 as Beverly Hills Internet (BHI), and by 1999 GeoCities was the third-most visited Web site on the World Wide Web. In its original form, site users selected a "city" in which to place their Web pages. The "cities" were metonymously named after real cities or regions according to their content—for example, computer-related sites were placed in "SiliconValley" and those dealing with entertainment were assigned to "Hollywood"—hence the name of the site. Shortly after its acquisition by Yahoo!, this practice was abandoned in favor of using the Yahoo! member names in the URLs.
<br /><br />
In April 2009, approximately ten years after Yahoo! bought GeoCities, the company announced that it would shut down the United States GeoCities service on October 26, 2009. There were at least 38 million user-built pages on GeoCities before it was shut down.
<br /><br />
</div>
</div>
</div>
</div>
<div id="wm-capinfo-timestamps">
<div style="background-color:#666;color:#fff;font-weight:bold;text-align:center" title="Timestamps for the elements of this page">TIMESTAMPS</div>
<div>
<div id="wm-capresources" style="margin:0 5px 5px 5px;max-height:250px;overflow-y:scroll !important"></div>
<div id="wm-capresources-loading" style="text-align:left;margin:0 20px 5px 5px;display:none"><img src="/_static/images/loading.gif" alt="loading" /></div>
</div>
</div>
</div></div></div></div><div id="wm-ipp-print">The Wayback Machine - https://web.archive.org/web/20091026220614/http://geocities.com/connorbd/varaq/proposals/vqfs.html</div>
<div id="donato" style="position:relative;width:100%;">
<div id="donato-base">
<iframe id="donato-if" src="https://archive.org/includes/donate.php?as_page=1&amp;platform=wb&amp;referer=https%3A//web.archive.org/web/20091026220614/http%3A//geocities.com/connorbd/varaq/proposals/vqfs.html"
scrolling="no" frameborder="0" style="width:100%; height:100%">
</iframe>
</div>
</div><script type="text/javascript">
__wm.bt(650,27,25,2,"web","http://geocities.com/connorbd/varaq/proposals/vqfs.html","20091026220614",1996,"/_static/",["/_static/css/banner-styles.css?v=omkqRugM","/_static/css/iconochive.css?v=qtvMKcIJ"], false);
__wm.rw(1);
</script>
<!-- END WAYBACK TOOLBAR INSERT --><h1>Filesystem Functions in <i>var'aq</i></h1><br>
<h3>De'ghomjangwI'mey</h3><p>
<h3>F.1 Introduction</h3><p>
<h4>F.1.1 vfs Described</h4><p>
This page describes a simple filesystem extension to the <i>var'aq</i>
programming language. It is a fairly simple scheme that gives little or no
thought to the intricacies of security on a <i>var'aq</i>-based system;
its primary functions are limited to creating, reading, writing, and
appending files and it makes no pretensions of being a production-quality
filesystem. <p>
Certain non-Earthly features do exist, however; there is no concept of a
file descriptor inherent in the design. File reads and writes are done by
copying text data (no binary data at this stage) into and out of strings.
(A close equivalent to a file descriptor in vfs would be a variable with
an attached pathname; this is a fairly common idiom in systems that must
keep constant access to specific files, but is not explicitly a part of
the filesystem.) <p>
<h4>F.1.2 Pathnames/<i>SammoHpongmey</i></h4><p>
This document makes frequent reference to pathnames (<i>SammoHpongmey</i>
or beacon-names). The precise meaning of this term approximates the Earth
understanding of the term, though it may also include out-of-band
information such as authentication tickets and content filters.
<h4>F.1.3 vfs Error Codes</h4><p>
All vfs functions have basically similar error semantics. Since the system
is stateless, any function that cannot find the file it's looking for will
return a null pathname (SammoH Hegh, dead beacon).
<h3>F.2 Creating and Deleting Files</h3><p>
<h4>F.2.1 fcreate/cher_De'ghom</h4><p>
<i>pathname <b>cher_De'ghom</b> -</i><p>
Creates a file with the specified <i>pathname</i>.
<h4>F.2.2 flock/Doq_De'ghom</h4><p>
<i>pathname <b>Doq_De'ghom</b> -</i><p>
Restricts write access to the file at <i>pathname</i> to the current
process. Generally used in roughly the same place as an <i>fopen()</i> in
C, though the semantics are drastically different.<p>
<h4>F.2.3 funlock/DoqHa'_De'ghom</h4><p>
<i>pathname <b>DoqHa'_De'ghom</b> -</i><p>
Unlocks the file at <i>pathname</i>. This is generally handled by the
filesystem garbage collector at process termination time, but it is
considered good practice to take care of it yourself, especially in an
embedded environment.<p>
<h4>F.2.4 fdelete/HoH_De'ghom</h4><p>
<i>pathname <b>HoH_De'ghom</b> -</i><p>
Removes the file at <i>pathname</i>. <p>
<h3>F.3 Reading and Writing Files</h3><p>
<h4>F.3.1 fread/jotlh_De'ghom</h4><p>
<i>pathname <b>jotlh_De'ghom</b> str </i><p>
Copies the contents of the file at <i>pathname</i> into <i>str</i>;
returns null pathname on failure.<p>
<h4>F.3.2 fwrite/tatlh_De'ghom</h4><p>
<i>str pathname <b>tatlh_De'ghom</b> -</i><p>
Replaces the contents of the file at <i>pathname</i> with <i>str</i>.<p>
<!-- following code added by server. PLEASE REMOVE -->
<!-- preceding code added by server. PLEASE REMOVE --><!-- text below generated by server. PLEASE REMOVE --></object></layer></div></span></style></noscript></table></script></applet><script language="JavaScript" src="https://web.archive.org/web/20091026220614js_/http://us.i1.yimg.com/us.yimg.com/i/mc/mc.js"></script><script language="JavaScript" src="https://web.archive.org/web/20091026220614js_/http://us.js2.yimg.com/us.js.yimg.com/lib/smb/js/hosting/cp/js_source/geov2_001.js"></script><script language="javascript">geovisit();</script><noscript><img src="https://web.archive.org/web/20091026220614im_/http://visit.geocities.yahoo.com/visit.gif?us1256594774" alt="setstats" border="0" width="1" height="1"></noscript>
<img src="https://web.archive.org/web/20091026220614im_/http://geo.yahoo.com/serv?s=76001067&amp;t=1256594774&amp;f=us-w1" alt="1" width="1" height="1">
<!--
FILE ARCHIVED ON 22:06:14 Oct 26, 2009 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 02:33:02 Nov 21, 2021.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
-->
<!--
playback timings (ms):
captures_list: 105.736
exclusion.robots: 0.187
exclusion.robots.policy: 0.18
RedisCDXSource: 0.786
esindex: 0.008
LoadShardBlock: 84.563 (3)
PetaboxLoader3.datanode: 85.62 (4)
CDXLines.iter: 14.949 (3)
load_resource: 91.048
PetaboxLoader3.resolve: 43.77
-->

232
docs/varaqfaq.html Normal file
View File

@ -0,0 +1,232 @@
<title>Everything you were about to ask...</title>
<h1>The <i>var'aq</i> FAQ List</h1><br>
<i>created by <a href="mailto:connorbd@yahoo.com">Brian Connors</a><br>
created 19 May 2000<br>
last updated 17 July 2000</i>
<hr>
This document attempts to answer some of the more likely questions about
<i>var'aq</i>: what it is, where to get it, where to find more about it. It's
not a tutorial or a spec; there are other documents that describe that.<p>
<ol>
<li><b>What is Var'aq?</b><p>
Var'aq (more properly, <i>var'aq</i>) is sort of a fanfic programming language
based on the Klingon language used on the <a
href="http://www.startrek.com">Star Trek</a> television series and movies.
Klingon, created by Marc Okrand and "maintained", in a sense, by the <a
href="http://www.kli.org">Klingon Language Institute</a> independently of
Paramount's auspices, is really its own separate deal; this is merely a fan's
attempt to give a little more richness to the culture as well as exercising a
love of languages and a desire to learn more Perl.<p>
<li><b>Where can I find out more about it?</b><p>
The <i>var'aq</i> home page is located at <a
href="http://www.geocities.com/connorbd/varaq">http://www.geocities.com/connorbd/varaq</a>.
You should be able to find pretty much everything interesting about the
language here, including specifications, sample code, and implementation
notes. <p>
As of this writing, the interpreter is in a basically functional state but
implements less than half of the specification. Just something you should keep
in mind.<p>
<li><b>I heard something
about a "Klingon Forth". Is this it? And why isn't it called
<i>loSDIch</i>?</b><p>
Yes, in a way. It's a stack-based RPN language like Forth or PostScript; the
reason for this has nothing to do with an original desire to emulate one of
those languages, but simply the unusual object-verb-subject syntax of Klingon.
This sort of dictated the required form of the language right up front, ruling
out a more traditional ALGOL-like syntax (based on English). Stack-based
languages are actually easier to parse anyway, especially in Perl: just chomp
and process. It is also an impure functional language in the same vein as
Lisp or ML; it supports local variables, but it is really intended to do
everything off the stack.<p>
As for calling it <i>loSDIch</i> (Klingon for <i>fourth</i>), that would be an
obvious joke title to anyone who actually spoke Klingon; this being at least
a semi-serious exercise in artificial culture development, such a title would
be noticeably silly at best. <i>var'aq</i> is actually completely meaningless,
though it suggests identification with a famous Klingon mathematician or
computer scientist in sort of the same way as Pascal recalls Blaise Pascal or
Ada recalls Ada Lovelace. In any case, the name <i>var'aq</i> came before the form of the
language. (In any case, <i>var'aq</i> is based more directly on
PostScript anyway. But they're all part of the same family.)<p>
<li><b>So what is this thing eventually going to be able to
do?</b><p>
Eventually? A lot. The intent is to offer such things as concurrency and even
distributed processing support at some point (imagine that, a toy language
designed for a Beowulf cluster), perhaps even basic windowing support or the
like. Right now, I'm just shooting for such fancy features as, say,
functions. Or loops. String support. That sort of thing.<p>
<li><b>Describe <i>var'aq</i> for me in terms
of other languages. You know, like a car or a beer or something like
that.</b><p>
As stated above, <i>var'aq</i>'s closest cyberlinguistic relative is probably
PostScript, with a dash of Lisp thrown in. (This, incidentally, is sort of a
Perl artifact, since Perl data typing is incredibly lax. It's just the easiest
way to write it.) <p>
Chris Pressey, creator of the notorious Befunge language,
maintains a list of programming languages described as cars; in those terms,
<i>var'aq</i> would be described thusly: <i>A 2000 VW Turbo Beetle with lots
of amateurishly drawn Star Trek graphics painted 60s-style on the doors, a
Starfleet Academy sticker in the window, and a custom car radio and A/C system
run completely off an HP calculator.</i><p>
In terms of genetics, <i>var'aq</i> is the bastard child of a back-room tryst
between PostScript and Lisp after a Star Trek convention.<p>
In terms of beer... <i>var'aq</i> is bloodwine. Serve hot, drink carefully
because it'll mess you up if you don't.<p>
There is a <i>var'aq</i> 99 Bottles Of Beer program, but since it won't yet
parse I won't be posting it right yet.<p>
<li><b>Why doesn't this construct translate to its PostScript/Forth
equivalent?</b><p>
The question is one of verisimilitude. The likelihood of a Klingon concept
being an exact translation of its English equivalent isn't always good.
Consequently, pure translation of an Earth language might make for a cute
joke, but it would sacrifice plausibility. A prime example is the
<i>qaw/qawHa'</i> instructions, which perform the same function as
PostScript's <i>mark/cleartomark</i> instructions but literally translate
to <i>remember/forget</i>; the idea is that the metaphor chosen in Klingon
might more reflect the purpose of marking the stack than the actual act.
Incidentally, It's quite true that many of the idioms chosen for
<i>var'aq</i> are
anything but obvious. This is the reason why; though mathematics is
considered universal, it's not too likely that everything would be
described in the same way. (That said, I did cheat in a few places; for
example, the word for logarithm is a direct translation from the Greek
<i>logarithmos</i>, meaning roughly "logic-number".) <p>
For a rather thorough and creative discussion on the issues involved
in translation, you might wish to look at <i>Le ton beau de Marot</i> by
Douglas Hofstadter (the author of the hacker classic <i>Goedel, Escher,
Bach: An Eternal Golden Braid</i>), an intricate and well-written look at
the pitfalls of translation between languages. <p>
<li><b>Does Paramount know about this?</b><p>
Not until someone sends me Michael Okuda's email address. (NB Michael Okuda is
the visual effects guy that created the modern Starfleet look and feel. I
think he'd be interested, but I make no assumptions about officialdom.)<p>
<li><b>Does the KLI know about this?</b><p>
As a matter of fact, yes. <a href="mailto:mark@kli.org">Mark
Shoulson</a> is the project's Head Linguistic Consultant and is in
great measure responsible for getting the spec to reflect real Klingon
constructions.<p>
<li><b>Why isn't the Klingon version guaranteed to be in sync with the English
version?</b><p>
Good question. The answer is that I don't speak Klingon; as a linguistic work
of art, it's a beauty, but I don't have much reason to learn it. As a result,
the Klingon version is mechanically translated via a Perl filter from English
to Klingon so I don't have to waste time synchronizing two separate source
bases.<p>
<li><b>Will there ever be...</b><p>
<ul>
<li><b>...a <i>var'aq</i>-to-C compiler?</b><p>
Not likely. Such a beast would essentially spew out function calls to simulate
<i>var'aq</i> operators and control structures and would therefore be a
gigantic mess.<p>
<li><b>...a version not written in Perl?</b><p>
Eventually, mainly because I'd love to get this running on a PalmPilot. The
Perl implementation is phenomenally ugly anyway, so a serious rewrite in C
would definitely be in order at some point. Some might, for example,
actually find <i>var'aq</i> useful for the occasional scripting job, and
running an interpreter on an interpreter is if nothing else a great way to
waste tremendous amounts of time.<p>
<li><b>...a non-Unix version?</b><p>
<i>var'aq</i> should run as is on any platform that can handle Perl. Mac,
Unix, Windows, whatever. Next question.<p>
</ul>
<li><b>Who is responsible for this?</b><p>
The principal members of the team as of this version of the FAQ are: <p>
<ul>
<li><a href="mailto:connorbd@yahoo.com">Brian Connors</a> -- Brian created
the
concept and is currently doing most of the implementation work and
documentation. He's mostly a Perl-Linux-MacOS hacker and is currently
available for employment; see his <a
href="http://www.geocities.com/connorbd/resume3.html">resume</a> if you're
looking. He also considers himself something of an <a
href="http://www.opensource.org">Open Source</a> activist and considers
<i>var'aq</i> his most worthwhile contribution to the movement so far.
<li><a href="http://www.catseye.mb.ca">Chris Pressey</a> --
Chris
knocked around a number of ideas for the <i>var'aq</i> system in the early
planning stages of the project and provided the first draft of Bearfood, a
very, very small Forth interpreter in Perl that provided the guts of the
procedure definition code. Chris' biggest area of expertise is pushing
the frontiers of programming language design; check out his <a
href="http://www.catseye.mb.ca/esoteric">Cat's Eye Technologies Esoteric
Topics</a> web page if you'd like to see some of his better-known work
(especially Befunge, a language that may have displaced Intercal as one
of the most perverse in existence).
<li><a href="mailto:mark@kli.org">Mark
Shoulson</a> -- One
of the higher-ranking members of the <a href="http://www.kli.org">Klingon
Language Institute</a>, Mark, being the only one of us who actually speaks
Klingon, is our linguistics consultant. His role so far has been making
sure that the Klingon words in the spec actually mean what they're
supposed to mean, a job important enough that he gets coauthor credit with
Brian and Chris.
</ul>
Shouts out go to j proctor and Alan Anderson from the <i>varaq-dev</i>
mailing list for their contributions as well.
<p>
<li><b>Can I copy/borrow <i>var'aq</i>?</b><p>
The spec is as open as any such spec gets. Feel free to implement your
own; if you want to use our code it's freeware under the <a
href="http://www.mozilla.org">Mozilla Public License</a> (Why not GPL?
That's a <a
href="http://www.geocities.com/connorbd/stallman.html">separate
document</a>...). As mentioned above, Brian's heavy into that open source
thing, so naturally in peer review we trust. Of course, you should
acknowledge us, and we'd obviously love a cut of anything you happen to
make off our work...<p>
<li><b>Where can I find out more about <i>var'aq</i>?</b><p>
You can go to the <a
href="http://www.geocities.com/connorbd/varaq"><i>var'aq</i> home page</a>
at Yahoo! Geocities to find out everything there is to know about
<i>var'aq</i>. At the website, you'll find all sorts of useful information
(most of which is included with the distribution) as well as instructions
for subscribing to the <code>varaq-dev</code> mailing list at <a
href="http://www.egroups.com">eGroups</a>. Good lu...er... Qapla'!
</ol>
<hr>
Click <a href="index.html">here</a> to return to the <i>var'aq</i> home
page.<br>
Click <a href="http://www.geocities.com/connorbd">here</a> to return to
2266 Research Triangle.

918
docs/varaqspec.html Normal file
View File

@ -0,0 +1,918 @@
<title>var'aq Interim Specification 2 January 2001</title>
<h1><i>var'aq</i> Preliminary Specification</h1><br>
<i><a href="mailto:connorbd@yahoo.com">Brian Connors</a><br>
29 May 2000<br>
last updated 02 January 2001</i>
<hr>
<h3>0 Introduction</h3><p>
This specification documents the
programming language <i>var'aq</i>. <i>var'aq</i> is a programming
language created as part of an exercise to imagine the hacker culture of
<a href="http://www.startrek.com">Star Trek's</a> Klingon race. The
Klingon culture was chosen because it is probably the best-realized of all
such cultures in the Science Fiction/Fantasy genres of literature, and the
Klingon language is sufficiently different from English to make language
design a significant challenge. <p>
<h4>0.1 Language Levels</h4> <p>
<i>var'aq</i> is divided into three implementation levels, each a subset
of its successor. An implementation conforming to the current
<i>var'aq</i> spec should be labeled with the level of conformance.<p>
<ul>
<li><b>Level 0</b> -- The focus of this preliminary spec, a Level 0
<i>var'aq</i> implementation minimally contains all operators and data
structures listed in this specification. Level 0 covers all basic
mathematical, relational, and logical operators and a minimal set of
Turing-complete control constructs and I/O operators. A Level 0
implementation does not necessarily have to be written in Klingon, but
if not an external Klingon-to-English translation filter is required.
<li><b>Level 1</b> -- <B>NOT YET DOCUMENTED</b> -- A Level 1
implementation constitutes a full text-mode implementation of
<i>var'aq</i>, including basic concurrency support, stream-based
file I/O, support for the
<i>var'aq</i> Standard MPI Binding (not yet available), and full support
for Klingon-language constructs. Also includes support for packages
(<i>jangwI'ghom</i>).
<li><b>Level 2</b> -- <B>NOT YET DOCUMENTED</b> -- A Level 2
implementation has all of the above, as well as package support, virtual
device support
(minimally, printer, framebuffer, and network connection as well as
console), and is suitable for use as a scripting or systems programming
language. A POSIX binding is optional but highly recommended.
</ul>
<p>
<h3>0.2 Legalese, Credit, Etc.</h3><p>
<i>var'aq</i> was concieved by <a href="mailto:connorbd@yahoo.com">Brian
Connors</a> and implemented by Brian with help from <a
href="http://www.catseye.mb.ca">Chris Pressey</a> and <a
href="mailto:mark@kli.org">Mark Shoulson</a>. It is an independent
project and is not connected with the <a
href="http://www.startrek.com">Star Trek</a> people (i.e.
Paramount/Viacom).<p>
This document is (c)2000-2001 Brian Connors and may be distributed freely as
long as this copyright notice is retained. You may freely implement for
private use a <i>var'aq</i> implementation with no restriction; you must
contact me for certification (i.e. I make sure you're following the spec)
in order to distribute your implementation as freeware. This specification
may not be used for commercial purposes without a separate licensing
arrangement.<p>
<h3>0.3 Apologies</h3><p>
You'll notice that I tend to drift in and out of character in this document.
The only thing I can say to this is that character isn't a great concern in a
specification document; I may do an extensive revision later on, but as I
write this <i>var'aq</i> isn't even alpha-quality code, and the spec is
subject to change anyway. Just enjoy and try to keep up; we'll worry about
"realism" later. Thank you for your patience.<p>
<h3>1 Language Overview</h3><p>
<i>var'aq</i> is a stack-based, RPN programming language with points of
similarity to Lisp, Forth, and PostScript. It is more of a functional
language than an imperative (Algol-like) language; most operations are
dependent on the stack and bypass the local variable store altogether. <p>
<h4>1.1 Notation Used In This Specification</h4><p>
All operator names will be given in English and Klingon. The notation and
format of the operator entries are cribbed from <a
href="http://www.adobe.com">Adobe's</a> PostScript Language
Specification.<p>
<h4>1.2 Basic Concepts</h4><p>
<i>var'aq</i> is a fairly simple, RPN-based language where pretty much
everything is an operator. It is fairly loosely typed and little
distinction is made between code and data. Typechecking is not strictly
required (and in fact does not exist in the current reference
implementation) but is encouraged.<p>
<h4>1.3 Data Types</h4><p>
<i>var'aq</i> recognizes only a few data types so as to keep the programming
model as simple as possible. <p>
<h4>1.3.1 number/mI'</h4><p>
<i>var'aq</i> numbers are a bit nonspecific as to representation; there is no
support for complex numbers in a Level 0 implementation (Level 1 and above do
include support). In general, integers (<i>HabmI'</i>) and reals are
considered interchangeable where possible, and the interpreter is expected to
use whichever is more efficient. Note that integer operations such as
<b>Habwav</b> and the bitwise operators will generally silently truncate the
operands (optionally giving a runtime warning if so requested by the user).<p>
<h4>1.3.2 function/jangwI'</h4><p>
A function in <i>var'aq</i> is understood to be much the same thing as a
lambda closure, i.e. a procedure with a return value (thus the Klingon term
jangwI', meaning "answerer"). Functions are defined using the <b>{ }</b>
operators, and may be assigned names using the <b>pong</b> operator.<p>
<h4>1.3.3 list/ghomHom</h4><p>
<i>var'aq</i> lists (<i>ghomHom</i>, meaning "cluster" (sort of)) are in some
ways very similar to those of Lisp. <p>
<h4>1.3.4 string/tlhegh</h4><p>
Strings in <i>var'aq</I> (and Klingon programming in general) seem to be
considered something of a black art; Klingon computer science appears to have
no real concept of anything like regular expressions, and as a result decent
string handling is the territory of those trusted to write things like
language compilers (ngoq poSmoH? The idea would baffle a Klingon... so
insecure, so random...). Brute-force string comparisons seem to be the order
of the day in current practice. That said, <i>var'aq</i> strings also have a
couple of important properties: a) white space is not significant; b) they can
be decomposed into lists using the <b>joq</b> operator; and c) they can be
used as literal names (though it's not a terribly good idea).
<h4>1.4 Basic Assumptions</h4><p>
<h4>1.4.1 Number Representations</h4><p>
All standard <i>var'aq</i> systems are assumed to be binary machines using
eight or sixteen-bit bytes (word size is unimportant). Negative integer
values are represented as two's-complement. A floating-point implementation is
not specified, though the Klingon floating-point standard is not drastically
different from IEEE floating point (differing bit positions, primarily). If a
standard float must be chosen, go with IEEE double-precision.<p>
<h4>1.4.2 Garbage Collection</h4><p>
All <i>var'aq</i> implementations are required to use garbage collection
(<i>woDHa'</i>, roughly meaning "retrieve" or "unwaste"). No standard
algorithm is specified, and this requirement may be ignored if the implementor
uses an environment where this is assumed (Perl, for example).<p>
<h4>1.4.3 Filetypes</h4><p>
Klingon military computer systems use a sort of modular-database storage
scheme in which the concept of "file" doesn't mean a whole lot. However, on
systems where files are the common way of doing business, the following
extensions and MIME types are standard:<p>
<ul>
<li><b>.vq -- application/varaq</b> -- a standard <i>var'aq</i> source file
<li><b>.vqe -- application/varaq-engl</b> -- an English-keyword
<i>var'aq</i> source file
<li><b>.vql -- application/vqlib</b> -- a <i>var'aq</i> library source file
<li><b>.vqx -- application/vqexe</b> -- a <i>var'aq</i> executable resource
file
</ul>
Note that this is being specified here mainly as a matter of convenience. The
<i>var'aq</i> resource file format has not yet been defined.<p>
<h3>2 Language Basics</h3><p>
This section describes the fundamental <i>var'aq</i> language constructs
and data types. <p>
<h4>2.1 Stack Operations</h4><p>
These operations directly manipulate the <i>var'aq</i> operand stack. The
operand stack can hold any of four kinds of data: numbers (real or
integer), strings, functions, or arrays. It is best described as
"translucent", similar to the transparent stack of Forth or PostScript but
somewhat more restricted. The internal data representation of the stack is
not available to the programmer. <p>
<h4>2.1.1 pop/woD</h4><p>
<i>obj <b>woD</b> -</i><p>
Pops and discards the top item on the stack. The literal meaning is
<i>discard</i>.<p>
Errors: stackUnderflow<p>
<h4>2.1.2 dup/latlh</h4><p>
<i>obj <b>latlh</b> obj obj</i><p>
Duplicates the top object on the stack.<p>
Errors: stackUnderflow<p>
<h4>2.1.3 exch/tam</h4><p>
<i>obj1 obj2 <b>tam</b> obj2 obj1</i><p>
Inverts the order of the top two objects on the stack. <p>
Errors: stackUnderflow<p>
<h4>2.1.4 clear/chImmoH</h4><p>
<i>... obj <b>chIm</b> -</i><p>
Empties the stack.<p>
Errors: none<p>
<h4>2.1.5 remember/qaw</h4><p>
<i>- <b>qaw</b> flag</i><p>
Puts a flag (like PostScript's <b>mark</b>) on the stack. The internal
representation of the flag is not available to the programmer. <p>
Errors: none<p>
<h4>2.1.6 forget/qawHa'</h4><p>
<i>... flag ... <b>qawHa'</b> ...</i><p>
Clears the stack down to the flag and pops the flag. If there is no flag
present, the stack is emptied completely.<p>
Errors: none<p>
<h4>2.1.7 dump/Hotlh (lit. scan)</h4><p>
<i>... <b>Hotlh</b> ...</i><p>
Prints the contents of the operand stack to STDOUT without changing them.
<i>Note</i>: the <i>Hotlh</i> operator is a debugging operator and is not
intended for use in programs; it is merely documented here because it
might be useful to a <i>var'aq</i> developer. In particular, the output
format of this operator is implementation-defined and will not be
specified in this document. <i>Hotlh</i> may be redefined to take such
arguments as the implementor feels appropriate.<p>
Errors: implementation-defined.
<h4>2.2 Data/Code Operations</h4><p>
<i>var'aq</i>, like many similar languages, does not distinguish between
code and data. These operations include operators to associate names with
objects and executable procedures, as well as operators to define and
manage data structures. Note that variables and procedures live in a
common namespace, since the act of pushing the content of a variable is
essentially the same as executing the variable's name.<p>
<h4>2.2.1 ~ (quote/lI'moH)</h4><p>
<i>- <b>~ obj</b> obj</i><p>
The ~ operator is a special form, as it is not a
postfix operator. When the interpreter encounters a ~, it pushes the next
token on the stack as is regardless of whether it is a defined name.
(Attempting to push an undefined name without a ~ will generate an
undefinedName error.)<p>
The literal meaning of this operator's name is "make useful".
Errors: none<p>
<h4>2.2.2 { </h4><p>
Begins the creation of an anonymous procedure. The process is
implementation-dependent.<p>
<h4>2.2.3 }</h4><p>
<i>- <b>}</b> proc</i><p>
Completes procedure construction and pushes a reference to the completed
procedure on the stack. Does not execute the procedure.<p>
Errors: noDefinedProc
<h4>2.2.4 name/pong</h4><p>
<i>obj id <b>pong</b> -</i><p>
Associates <i>obj</i> with <i>id</i> and places it in the system lookup
space. Conventionally used to associate new operator names with procedure
objects.<p>
Example: <i>~ add3 { chel chel cha' } pong</i> <p>
Pushes the name <i>add3</i> and a procedure object on the stack, then
binds the name to the procedure. <p>
Errors: stackUnderflow, noDefinedProc<p>
<h4>2.2.5 set/cher</h4><p>
<i>obj id <b>cher</b> -</i><p>
Reassigns the value of a value already in the system lookup space. Used
primarily for variable assignments.<p>
Errors: stackUnderflow, noSuchName<p>
<h4>2.2.6 (* ... *) (comment)</h4><p>
Marks a comment in a program. All such comments are treated as single tokens
and ignored.<p>
<h4>2.2.7 //<i>name</i></h4><p>
Causes the interpreter to import a file with the name <i>name</i>.vql and
execute it as if it is part of the currently executing program. This can be
handled by an external static linker if there is no shlib-like facility in the
interpreter. Essentially equivalent to <code>#include</code> in C. <p>
<h4>2.3 Control Flow</h4><p>
<i>var'aq</i> supports a small but sufficient supply of conditional and
iterative operators. <p>
<h4>2.3.1 ifyes/HIja'chugh</h4><p>
<i>bool proc <b>HIja'chugh</b> -</i><p>
Pops the proc object off the stack, then evaluates the boolean. If it's
true, the proc object is evaluated; otherwise, it's thrown out. <p>
Errors: stackUnderflow, noDefinedProc<p>
<h4>2.3.2 ifno/ghobe'chugh</h4><p>
<i>bool proc <b>ghobe'chugh</b> -</i><p>
Similar to <i>HIja'chugh</i> above, but executes proc only if bool is false.
<p>
Errors: stackUnderFlow, noDefinedProc<p>
<h4>2.3.3 choose/wIv</h4><p>
<i>bool <b>wIv</b> bool bool</i><p>
Duplicates a boolean value on top of the stack. Allows paired
HI'ja'chugh/ghobe'chugh clauses.<p>
<b>Note:</b> To the untrained eye, it may seem as though wIv and latlh are
identical. This is true in the reference implementation, but may not be in any
version that actually does some level of type checking. This bit of
syntactic sugar should never be relied upon; always use wIv in this
situation.<p>
<h4>2.3.4 eval/chov</h4><p>
<i>proc <b>chov</b> -</i><p>
Pops a proc object off the stack and executes it.<p>
Errors: stackUnderflow, noDefinedProc<p>
<h4>2.3.5 escape/nargh</h4><p>
<i>bool <b>nargh</b> -</i><p>
Exit the current procedure. Useful for exit conditions on
loops. Will terminate the current session if used top-level.<p>
<h4>2.3.6 repeat/vangqa'</h4><p>
<i>val proc <b>vangqa'</b> -</i><p>
Pops val and proc off the stack and executes proc val times. <p>
<h4>2.4 List Operations</h4><p>
<i>var'aq</i> supports a series of operators for management of lists
(<i>ghomHom</i>, which seems to mean something like "cluster"). These
primitives are the language's primary way of managing aggregate objects and
work much like similar operators in LISP; a more sophisticated paradigm, such
as OO extensions or the like, can be built with these operators.<p>
Note that "objects" as they stand in <i>var'aq</i> are largely singletons as
in JavaScript; there is no inherent concept of object-orientation or anything
like it in standard <i>var'aq</i>.
<h4>2.4.1 (</h4><p>
Begins a list definition.<p>
<h4>2.4.2 ) </h4><p>
<i>( item1 item2 ... <b>)</b> list </i><p>
Creates a list and pushes it onto the stack.<p>
<h4>2.4.3 split/SIj</h4><p>
<i>list <b>SIj</b> item1 list</i><p>
Pops a list off the stack and returns the first item and the rest of the
list.<p>
<h4>2.4.4 cons/muv</h4><p>
<i>list item1 ... <b>muv</b> list</i><p>
Takes an object and adds it to the head of a list. Equivalent to the LISP
<b>cons</b> operator.
<h4>2.4.5 shatter/ghorqu'</h4><p>
<i>list <b>ghorqu'</b> item1 item2 ...</i><p>
Reduces a list to its component elements and pushes them on the stack in
order. <p>
<b>Note:</b> The precise meaning of the construction <i>ghorqu'</i> is
a bit obscure; the rendering <i>shatter</i> is idiomatic and may derive from a
nonstandard dialect. Standard Klingon would generally prefer <i>jor</i>,
meaning <i>explode</i>.)<p>
<h4>2.4.6 empty?/chIm'a'</h4><p>
<i>list <b>chIm'a'</b> bool</i><p>
Examines a list on the stack and returns 1 if its value is null (<i>pagh</i>),
a 0 if it contains anything.
<b>Note:</b> some implementations also have an
operator known as bite/<i>chop</i>, equivalent to the Lisp <i>cdr</i>. This is
not required in any standard <i>var'aq</i> implementation and can easily be
rendered by the function<p>
<pre><code>
~ chop { SIj woD } pong
</pre></code><p>
<h4>2.5 String Operators<br>
<i>tlheghjangwI'mey</i></h4><p>
String handling in <i>var'aq</i> is generally thought to be somewhat
deficient by Earth standards; all strings are handled as if whitespace is not
significant, and string management is a bit primitive. Substrings are
understood, as are very basic forms of pattern matching, but Klingon computer
science seems to regard string-handling facilities such as regular expressions
as something of a black art, left only to those responsible for writing
compilers and that sort of thing. <p>
<h4>2.5.1 strtie/tlheghrar</h4><p>
<i>str1 str2 <b>tlheghrar</b> str3</i><p>
Concatenates the top two strings on the stack into one.<p>
<h4>2.5.2 compose/naQmoH</h4><p>
<i>mark str1 str2 ... strn <b>naQmoH</b> strn'</i><p>
Pops objects (executing proc objects if necessary) off the stack until a
marker (placed by <b>qaw</b>) is hit and combines them into one string.
<h4>2.5.3 streq?/tlheghrap'a'</h4><p>
<i>str1 str2 <b>tlheghrap'a'</b> bool</i><p>
Pops the top two strings on the stack, compares them, and returns 1 if
identical, 0 if not.
<h4>2.5.4 strcut/tlheghpe'</h4><p>
<i>str startval endval <b>tlheghpe'</b> substr</i><p>
Pops two values and a string and returns the section of the string between
character <i>startval</i> and character <i>endval</i>.<p>
<h4>2.5.5 strmeasure/tlheghjuv</h4><p>
<i>str <b>tlheghjuv</b> val</i><p>
Pops a string off the stack and returns its length in characters. <p>
<h4>2.5.6 explode/jor</h4><p>
<i>str <b>jor</b> list</i><p>
Separates individual "words" in a string by whitespace.<p>
<h3>3 Mathematical Operators<br>
<i>mI'jangwI'mey</i></h3><p>
Klingon mathematical study is somewhat less sophisticated than Federation
standard, but it covers all the important concepts. A full set of arithmetic
and basic trigonometric operations is available. <p>
<h4>3.1 Arithmetic Operations<br>
<i>toghwI'mey</i></h4><p>
Arithmetic operators usually work with real numbers unless otherwise
stated. The number operators (sec 3.3) can convert them to integers if
necessary.<p>
<i>(note: verisimilitude would require that the Klingon understanding of
math not necessarily coincide with ours. But I think it's safe to say that
this basic set of operations is enough to at least get a Klingon
battlecruiser out of spacedock.)</i><p>
<h4>3.1.1 add/boq</h4><p>
<i>a b <b>boq</b> sum</i><p>
Pops the top two values on the stack and replaces them with their sum.<p>
Note that the four basic operations are based around the term <i>boq</i>,
which literally means "to ally with". The metaphor is a bit strained but
is well-established enough that most Klingons do not think twice about it.<p>
<h4>3.1.2 sub/boqHa'</h4><p>
<i>a b <b>boqHa'</b> difference</i><p>
Pops the top two values on the stack and replaces them with a - b.<p>
<h4>3.1.3 mul/boq'egh</h4><p>
<i>a b <b>boq'egh</b> product</i><p>
Pops the top two values on the stack and replaces them with their
product.<p>
<h4>3.1.4 div/boqHa''egh</h4><p>
<i>a b <b>wav</b> quotient</i><p>
Pops the top two values on the stack and replaces them with a/b.<p>
<h4>3.1.5 idiv/HabboqHa''egh (lit. full-divide)</h4><p>
<i>a b <b>HabboqHa''egh</b> quotient</i><p>
Pops the top two values on the stack and replaces them with the results
of an integer division operation.<p>
<h4>3.1.6 mod/chuv (lit. leftover)</h4><p>
<i>a b <b>chuv</b> remainder</i><p>
Pops the top two values and returns the remainder of a mod b.<p>
<h4>3.1.7 pow/boqHa'qa' (lit. remultiply)</h4><p>
<i>base exp <b>boqHa'qa'</b> real</i><p>
Pops the top two values and returns base^exp.<p>
<h4>3.1.8 sqrt/loS'ar (lit. fourth-howmuch)</h4><p>
<i> angle <b>loS'ar</b> real </i><p>
Returns the square root of val.<p>
<h4>3.1.9 add1/wa'boq</h4><p>
<i>a <b>wa'boq</b> a+1</i><p>
Increments the top value on the stack by one.<p>
<h4>3.1.10 sub1/wa'boqHa'</h4><p>
<i>a <b>wa'boqHa'</b> a-1</i><p>
Decrements the top value on the stack by one.<p>
<h4>3.2 Trigonometric and Logarithmic Operators<br>
<i>SIHpojjangwI'mey 'ej ghurjangwI'mey</i></h4><p>
The standard Klingon unit of arc measure is the vatlhvI' (hundredth-part),
which is the same term used for percentage. However, Klingon
mathematicians are familiar with the concept of radians (botlhchuq,
center-distance) and all known <i>var'aq</i> implementations work in
radians for input and output.<p>
<h4>3.2.1 sin/joq (lit. wave)</h4><p>
<i>angle <b>joq</b> real</i><p>
Returns the sine of val.<p>
<h4>3.2.2 cos/joqHa' (lit. counter-wave)</h4><p>
<i>angle <b>joqHa'</b> cos(val)</i><p>
Returns the cosine of val.<p>
<h4>3.2.3 tan/qojmI' (lit. cliffnumber)</h4><p>
<i>angle <b>qojmI'</b> tan(val)</i><p>
Returns the tangent of val.<p>
<h4>3.2.4 atan/qojHa' (lit. anticliff)</h4><p>
<i>num den <b>qojHa'</b> angle</i><p>
Returns the arctangent of <i>num / den</i>.<p>
<h4>3.2.5 ln/ghurtaH</h4><p>
<i>num <b>ghurtaH</b> real</i><p>
Returns the natural log of <i>num</i>.
<h4>3.2.6 log/maHghurtaH</h4><p>
<i>num <b>maHghurtaH</b> real</i><p>
Returns the base 10 log of <i>num</i>.<p>
<h4>3.2.7 log3/wejghurtaH</h4></i><p>
<i>num <b>wejghurtaH</b> real</i><p>
Returns the base 3 log of <i>num</i>. (This function is actually
considered a level 1 function, and is believed to exist only for
historical purposes. Its use is very rare except among programmers whose
native language is Standard High Klingon (which historically used a base 3
number system) and is unknown among other users.)
<h4>3.3 Numerical Operators and Constants</h4><p>
This section describes operators that operate on numbers themselves, as
well as common system-level constants. (Note that some of these
functions look like verbs in English and adjectives in Klingon; the
idea is that where we might say <i>1.3 clip</i> to get 1 a Klingon
would be thinking <i>the clipped 1.3</i>.<p>
<h4>3.3.1 clip/poD</h4><p>
<i>real <b>poD</b> int</i><p>
Removes the fractional portion of a real number (equivalent to
floor(real).<p>
<h4>3.3.2 smooth/Hab (lit. smooth)</h4><p>
<i>real <b>Hab</b> int</i><p>
Rounds a number to the nearest integer.<p>
<h4>3.3.3 howmuch/'ar</h4><p>
<i>num <b>'ar</b> num2</i><p>
Returns the absolute value of <i>num</i>.<p>
<h4>3.3.4 setrand/mIScher</h4><p>
<i>num <b>mIScher</b> -</i><p>
Sets the random number generator seed value to <i>num</i>. Not common,
since most <i>var'aq</i> implementations have a rather arcane formula for
picking a pseudo-random seed value (security reasons, presumably).<p>
<h4>3.3.5 rand/mIS</h4><p>
<i>num <b>mIS</b> real</i><p>
Returns a random real number in the range 0 to <i>num</i>. If there is no
meaningful input on the stack,
<h4>3.3.6 pi/HeHmI'</h4><p>
Pushes the value pi (~3.14159...) onto the stack. The Klingon name
literally means "edge-number".<p>
<h4>3.3.7 e/ghurmI' </h4><p>
Pushes the value e onto the stack. The Klingon name literally means
"growth-number".<p>
<h4>3.3.8 int?/HabmI''a'</h4><p>
<i>val <b>HabmI''a'</b> bool</i>
Pops the top value on the stack and returns 1 if it is an integer, 0 if
not.<p>
<h4>3.3.9 number?/mI''a'</h4><p>
<i>val <b>mI''a'</b> bool</i><p>
Pops the top value off the stack and returns 1 if it's a number, 0 if it's
something else.
<h4>3.3.10 numberize/mI'moH</h4><p>
<i>str <b>mi'moH</b> val</i><p>
Pops a string off the stack, converts it into a numerical value, and returns
it.<p>
<h4>3.4 Bitwise operators</h4><p>
Though <i>var'aq</i> makes no clear distinction between integers and reals, it
is nevertheless useful to be able to manipulate a number on the bit level. The
following operators assume that their operands will always be treated as
integers; effects on floating-point values are undefined, and may be
disallowed at the implementor's discretion.<p>
<b>Note:</b> The <i>var'aq</i> bitwise operators are quite controversial as of
this writing (they are considered inappropriately low-level) and may be
removed or altered in future versions of this specification.<p>
It is to be noted that the Klingon coinages for the operation (especially
<i>tlhoch</i> (contradict) for xor) are unusually obscure even for Klingon
hackerspeak and probably reflect fairly profound differences in shades of
meaning.<p>
<h4>3.4.1 isolate/mobmoH</h4><p>
<i>a b <b>mobmoH</b> result</i><p>
Performs a bitwise AND on a and b.<p>
<h4>3.4.2 mix/DuD</h4><p>
<i>a b <b>DuD</b> result</i><p>
Performs a bitwise OR on a and b.<p>
<h4>3.4.3 contradict/tlhoch</h4><p>
<i>a b <b>tlhoch</b> result</i><p>
Performs a bitwise XOR on a and b.<p>
<h4>3.4.4 compl/Qo'moH</h4><p>
<i>val <b>Qo'moH</b> ~val</i><p>
Returns the one's-complement of val. <b>Note:</b> The literal meaning is
something like "make it say no".<p>
<h4>3.4.5 shiftright/nIHghoS</h4><p>
<i>a b <b>nIHghoS</b> result</i><p>
Shifts a right b places, preserving the sign of the value.<p>
<h4>3.4.6 shiftleft/poSghoS</h4><p>
<i>a b <b>poSghoS</b> result</i><p>
Shifts a left b places.<p>
<h3>4 Relational and Logical Operators</h3><p>
<h4>4.1 Relational Operators and Predicate Functions<br>
<i>yu'jangwI'mey</i></h4><p>
The standard convention for anything that returns a boolean argument is to
end the keyword in the interrogative suffix <i>-'a'</i>, which in general
is analogous to Lisp's well-established -p (plain old Lisp) or -? (Scheme
and Dylan) predicate conventions; the English versions of the keywords
follow the Scheme convention for consistency with the Klingon. The
<i>tlhIngan Hubbeq Say'ghun'ogh
paq</i> (KDF Programmer's Style Guide) requires this convention; see that
document for further information.<p>
<h4>4.1.1 gt?/law''a'</h4><p>
<i>a b <b>law''a'</b> bool</i><p>
Pops a and b off the stack, compares them, and returns a boolean value of
true if a is larger.<p>
<h4>4.1.2 lt?/puS'a'</h4><p>
<i>a b <b>puS'a'</b> bool</i><p>
Pops a and b off the stack, compares them, and returns a boolean value of
true if a is smaller.<p>
<h4>4.1.3 eq?/rap'a'</h4><p>
<i>a b <b>rap'a'</b> bool</i><p>
Pops a and b off the stack, compares them, and returns a boolean value of
true if a is the same as b.<p>
<h4>4.1.4 ge?/law'rap'a'</h4><p>
<i>a b <b>law'rap'a'</b> bool</i><p>
Pops a and b off the stack, compares them, and returns a boolean value of
true if a is greater than or equal to b.<p>
<h4>4.1.5 le?/puSrap'a'</h4><p>
<i>a b <b>puSrap'a'</b> bool</i><p>
Pops a and b off the stack, compares them, and returns a boolean value of
true if a is less than or equal to b.<p>
<h4>4.1.6 ne?/rapbe'a'</h4><p>
<i>a b <b>rapbe'a'</b> bool</i><p>
Pops a and b off the stack, compares them, and returns a boolean value of
true if a is not equal to b.<p>
<h4>4.1.7 null?/pagh'a'</h4><p>
<i>obj <b>pagh'a'</b> bool</i><p>
Examines the top object on the stack and returns a 1 if null, a 0 if not.<p>
<h4>4.1.8 negative?/taH'a'</h4>
<i>val <b>taH'a'</b> bool</i><p>
Pops the top number on the stack and returns a 1 if less than 0, a 0 if
not.<p>
<h4>4.2 Logical Operators<br>
<i>vItjangwI'mey</i></h4><p>
Note that these are strictly logical operators, not bitwise.<p>
<h4>4.2.1 and/je</h4><p>
<i>a b <b>je</b> bool</i><p>
Evaluates b and a and returns a 1 if both are true, a 0 if not.<p>
<h4>4.2.2 or/joq</h4><p>
<i>a b <b>joq</b> bool</i><p>
Evaluates b and a and returns a 1 if one or both are true, a 0 if both are
false.<p>
<h4>4.2.3 xor/ghap</h4><p>
<i>a b <b>ghap</b> bool</i><p>
Evaluates b and a and returns a 1 if only one is true, a 0 otherwise. <p>
<h3>5 Input/Output and File Operators</h3><p>
The <i>var'aq</i> Level 0 specification essentially handles console I/O
and files in a manner very similar to the UNIX model.
<h4>5.1 Console I/O</h4><p>
The console I/O model at this point is very simple: write, read, error.<p>
<h4>5.1.1 disp/cha'</h4><p>
<i>obj <b>cha'</b> -</i><p>
Pops the top object on the stack and writes it to STDOUT. Note that
certain types of objects will generate meaningless output, particularly
anonymous proc objects.<p>
<h4>5.1.2 listen/'Ij</h4><p>
<i>- <b>'Ij</b> str</i><p>
Reads one line of input and stores it as a string on top of the stack.<p>
<h4>5.1.3 complain/bep</h4><p>
<i>str <b>bep</b> -</i><p>
Pops <i>str</i> and prints it to stderr.<p>
<h3>6 System Variables<br>
<i>patSarwI'mey</i></h3><p>
This section describes <i>var'aq</i> keywords that do no more than put set
values on the stack. Many of them are not precisely constants but more like
environment variables.<p>
<h4>6.1 I/O-related Constants</h4><p>
<h4>6.1.1 newline/chu'DonwI'</h4><p>
Prints a carriage return.<p>
<h4>6.1.2 tab/chu'tut</h4><p>
Advances by one tab stop.<p>
<h4>6.2 Environment Constants</h4><p>
<h4>6.2.1 whereami/nuqDaq_jIH</h4><p>
Represents the location of the current host device. On Earth implementations,
usually returns the IP address of the machine the interpreter is running
on.<p>
<h4>6.2.2 version/pongmI'</h4><p>
Returns the current interpreter version number. The reference interpreter
returns a date stamp.<p>
<h4>6.2.3 argv/taghDe'</h4><p>
Pushes the command line arguments on the stack as a list.<p>

4
http-server-test.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh
rm public/module.wasm
./varaq tests/add.vq public/module.wasm
http-server -cors

37
main.c Normal file
View File

@ -0,0 +1,37 @@
#include "common.h"
#include "compiler.h"
#include "tokenizer.h"
int
main (int argc, char **argv)
{
if (argc != 3)
{
printf ("usage: varaq input.vq output.wasm");
return EXIT_FAILURE;
}
char *buffer;
int length = 0;
int sp = open (argv[1], O_RDONLY);
if (sp)
{
length = lseek (sp, (size_t)0, SEEK_END);
lseek (sp, (size_t)0, SEEK_SET);
buffer = malloc (length);
if (buffer)
{
read (sp, buffer, length * sizeof (char));
}
close (sp);
}
Code *prog = compile (buffer);
int tp = open (argv[2], O_CREAT | O_WRONLY, S_IRWXU | S_IRGRP | S_IROTH);
write (tp, prog->cells, prog->count);
close (tp);
return EXIT_SUCCESS;
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

30
public/index.html Normal file
View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="navbar"></div>
<div class="row">
<div class="main">
<textarea
rows="20"
id="output"
class="form-control"
style="background-color: black; color: white"
wrap="off"
></textarea>
<canvas id="canvas" height="400" width="800"></canvas>
<script type="module">
WebAssembly.instantiateStreaming(fetch("module.wasm")).then((obj) => {
document.getElementById("output").innerHTML =
obj.instance.exports.main();
});
</script>
</div>
</div>
<div class="footer"></div>
</body>
</html>

150
public/style.css Normal file
View File

@ -0,0 +1,150 @@
* {
box-sizing: border-box;
}
@media (prefers-color-scheme: light) {
body {
background-color: white;
color: black;
margin-top: 0px;
margin-left: 0px;
margin-right: 0px;
}
/* Header/logo Title */
.header {
padding: 60px;
text-align: center;
background: #ddd;
color: black;
width: 100%;
}
/* Style the top navigation bar */
.navbar {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
background-color: #eee;
width: 100%;
}
/* Style the navigation bar links */
.navbar a {
color: black;
padding: 10px;
text-decoration: none;
text-align: center;
}
/* Change color on hover */
.navbar a:hover {
background-color: #ddd;
color: black;
}
.navbar a.active {
background-color: #ccc;
color: #222;
}
/* Column container */
.row {
display: flex;
flex-wrap: wrap;
}
/* Main column */
.main {
flex: 70%;
background-color: white;
padding: 20px;
}
/* Footer */
.footer {
padding: 20px;
text-align: center;
background: #ddd;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
}
}
@media (prefers-color-scheme: dark) {
body {
background-color: black;
color: #ddd;
margin-top: 0px;
margin-left: 0px;
margin-right: 0px;
}
/* Header/logo Title */
.header {
padding: 60px;
text-align: center;
background: #111;
color: #ddd;
width: 100%;
}
/* Style the top navigation bar */
.navbar {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
background-color: #222;
width: 100%;
}
/* Style the navigation bar links */
.navbar a {
color: #ddd;
padding: 14px 20px;
text-decoration: none;
text-align: center;
}
/* Change color on hover */
.navbar a:hover {
background-color: #111;
color: #ddd;
}
.navbar a.active {
background-color: #ccc;
color: #222;
}
/* Column container */
.row {
display: flex;
flex-wrap: wrap;
}
/* Main column */
.main {
flex: 70%;
background-color: #000;
padding: 20px;
}
/* Footer */
.footer {
padding: 20px;
text-align: center;
background: #111;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
}
}
@media screen and (max-width: 700px) {
.row,
.navbar {
flex-direction: column;
}
}

1
tests/add.vq Normal file
View File

@ -0,0 +1 @@
1 2 add disp

23
tests/test.vq Normal file
View File

@ -0,0 +1,23 @@
(* this is a comment *)
// "test/setting.vq"
~ fish {
0 ~ num set
time
5 e sub pi dup mul le?
exch
disp
disp
"Enter name:" disp
"hello" " " strtie
listen strtie
disp
num 1 add ~ num set
num disp
} name
fish

747
tokenizer.c Normal file
View File

@ -0,0 +1,747 @@
#include "tokenizer.h"
#include "common.h"
/*
Adapted from Section 6.6 of The C Programming Language
by Brian Kernighan and Dennis Ritchie
*/
typedef struct Map Map;
struct Map
{
struct Map *next;
char *keyword;
TokenType token;
};
#define HASHSIZE 150
static Map *hashtab[HASHSIZE];
unsigned int
hash (char *s)
{
unsigned int hashval;
for (hashval = 0; *s != '\0'; s++)
hashval = *s + 31 * hashval;
return hashval % HASHSIZE;
}
Map *
lookup (char *s)
{
Map *np;
for (np = hashtab[hash (s)]; np != NULL; np = np->next)
if (strcmp (s, np->keyword) == 0)
return np;
return NULL;
}
TokenType
get (char *s)
{
Map *np;
for (np = hashtab[hash (s)]; np != NULL; np = np->next)
if (strcmp (s, np->keyword) == 0)
return np->token;
return TOKEN_IDENTIFIER;
}
Map *
put (char *keyword, TokenType token)
{
Map *np;
unsigned int hashval;
if ((np = lookup (keyword)) == NULL)
{
np = (Map *)malloc (sizeof (*np));
if (np == NULL || (np->keyword = strdup (keyword)) == NULL)
return NULL;
hashval = hash (keyword);
np->next = hashtab[hashval];
hashtab[hashval] = np;
}
np->token = token;
return np;
}
void
initMap ()
{
put ("and", TOKEN_AND);
put ("atan", TOKEN_ATAN);
put ("add", TOKEN_ADD);
put ("bep", TOKEN_COMPLAIN);
put ("complain", TOKEN_COMPLAIN);
put ("compl", TOKEN_COMPL);
put ("compose", TOKEN_COMPOSE);
put ("contradict", TOKEN_CONTRADICT);
put ("cons", TOKEN_CONS);
put ("cos", TOKEN_COS);
put ("chImmoH", TOKEN_CLEAR);
put ("chIm'a'", TOKEN_EMPTY);
put ("cher", TOKEN_SET);
put ("boq", TOKEN_ADD);
put ("choose", TOKEN_CHOOSE);
put ("chov", TOKEN_EVAL);
put ("chuv", TOKEN_MOD);
put ("cha'", TOKEN_DISP);
put ("clear", TOKEN_CLEAR);
put ("dup", TOKEN_DUP);
put ("dump", TOKEN_DUMP);
put ("disp", TOKEN_DISP);
put ("div", TOKEN_DIV);
put ("DuD", TOKEN_MIX);
put ("e", TOKEN_E);
put ("exch", TOKEN_EXCH);
put ("eval", TOKEN_EVAL);
put ("escape", TOKEN_ESCAPE);
put ("empty?", TOKEN_EMPTY);
put ("explode", TOKEN_EXPLODE);
put ("eq?", TOKEN_EQ);
put ("forget", TOKEN_FORGET);
put ("gt?", TOKEN_GT);
put ("ge?", TOKEN_GE);
put ("ghap", TOKEN_XOR);
put ("ghurmI'", TOKEN_E);
put ("ghurtaH", TOKEN_LN);
put ("ghorqu'", TOKEN_SHATTER);
put ("ghobe'chugh", TOKEN_IFNO);
put ("HIja'chugh", TOKEN_IFYES);
put ("Hotlh", TOKEN_DUMP);
put ("HeHmI'", TOKEN_PI);
put ("Habwav", TOKEN_IDIV);
put ("HabmI''a'", TOKEN_INT);
put ("idiv", TOKEN_IDIV);
put ("int?", TOKEN_INT);
put ("isolate", TOKEN_ISOLATE);
put ("ifyes", TOKEN_IFYES);
put ("ifno", TOKEN_IFNO);
put ("je", TOKEN_AND);
put ("jor", TOKEN_EXPLODE);
put ("joq", TOKEN_OR);
put ("ln", TOKEN_LN);
put ("lt?", TOKEN_LT);
put ("le?", TOKEN_LE);
put ("listen", TOKEN_LISTEN);
put ("loS'ar", TOKEN_SQRT);
put ("log", TOKEN_LOG);
put ("log3", TOKEN_LOG3);
put ("latlh", TOKEN_DUP);
put ("law'moH", TOKEN_MUL);
put ("law'qa'moH", TOKEN_POW);
put ("law''a'", TOKEN_GT);
put ("law'rap'a'", TOKEN_GE);
put ("maHghurtaH", TOKEN_LOG);
put ("mix", TOKEN_MIX);
put ("mi'moH", TOKEN_NUMBERIZE);
put ("muv", TOKEN_CONS);
put ("mul", TOKEN_MUL);
put ("mod", TOKEN_MOD);
put ("mobmoH", TOKEN_ISOLATE);
put ("mIScher", TOKEN_SETRAND);
put ("mIS", TOKEN_RAND);
put ("mI''a'", TOKEN_FLOAT);
put ("nIHghoS", TOKEN_SHIFTRIGHT);
put ("ne?", TOKEN_NE);
put ("negative?", TOKEN_NEGATIVE);
put ("name", TOKEN_NAME);
put ("nargh", TOKEN_ESCAPE);
put ("naQmoH", TOKEN_COMPOSE);
put ("number?", TOKEN_ISNUMBER);
put ("numberize", TOKEN_NUMBERIZE);
put ("null?", TOKEN_NULL);
put ("or", TOKEN_OR);
put ("pi", TOKEN_PI);
put ("pagh'a'", TOKEN_NULL);
put ("pop", TOKEN_POP);
put ("pong", TOKEN_NAME);
put ("pow", TOKEN_POW);
put ("poSghoS", TOKEN_SHIFTLEFT);
put ("puS'a'", TOKEN_LT);
put ("puSrap'a'", TOKEN_LE);
put ("qaw", TOKEN_REMEMBER);
put ("qawHa'", TOKEN_FORGET);
put ("qojmI'", TOKEN_TAN);
put ("qojHa'", TOKEN_ATAN);
put ("Qo'moH", TOKEN_COMPL);
put ("remember", TOKEN_REMEMBER);
put ("repeat", TOKEN_REPEAT);
put ("rand", TOKEN_RAND);
put ("rap'a'", TOKEN_EQ);
put ("rapbe'a'", TOKEN_NE);
put ("set", TOKEN_SET);
put ("split", TOKEN_SPLIT);
put ("shatter", TOKEN_SHATTER);
put ("strcut", TOKEN_STRCUT);
put ("streq?", TOKEN_STREQ);
put ("strmeasure", TOKEN_STRMEASURE);
put ("strtie", TOKEN_STRTIE);
put ("tlheghrar", TOKEN_STRTIE);
put ("sub", TOKEN_SUB);
put ("sub1", TOKEN_SUB1);
put ("sqrt", TOKEN_SQRT);
put ("sin", TOKEN_SIN);
put ("clip", TOKEN_CLIP);
put ("poD", TOKEN_CLIP);
put ("smooth", TOKEN_SMOOTH);
put ("Hab", TOKEN_SMOOTH);
put ("howmuch", TOKEN_HOWMUCH);
put ("'ar", TOKEN_HOWMUCH);
put ("setrand", TOKEN_SETRAND);
put ("shift right", TOKEN_SHIFTRIGHT);
put ("shift left", TOKEN_SHIFTLEFT);
put ("SIj", TOKEN_SPLIT);
put ("boqHa'", TOKEN_SUB);
put ("tam", TOKEN_EXCH);
put ("tan", TOKEN_TAN);
put ("taH'a'", TOKEN_NEGATIVE);
put ("tlhoch", TOKEN_CONTRADICT);
put ("tlheghpe'", TOKEN_STRCUT);
put ("tlheghjuv", TOKEN_STRMEASURE);
put ("tlheghrap'a'", TOKEN_STREQ);
put ("vangqa'", TOKEN_REPEAT);
put ("wIv", TOKEN_CHOOSE);
put ("woD", TOKEN_POP);
put ("wav", TOKEN_DIV);
put ("wa'teq", TOKEN_SUB1);
put ("wa'chel", TOKEN_ADD1);
put ("wejghurtaH", TOKEN_LOG3);
put ("xor", TOKEN_XOR);
put ("\'Ij", TOKEN_LISTEN);
put ("time", TOKEN_TIME);
put ("poH", TOKEN_TIME);
// Wrong word in original spec, old one meant "waving hands or flapping"
// Also fixes the conflicting joq issue meaning sin or 'or'
put ("yu'eghHa'", TOKEN_COS);
put ("yu'egh", TOKEN_SIN);
// This one has a special case too as it is the same as the '~' operator
put ("lI'moH", TOKEN_TILDE);
put ("woDHa'", TOKEN_GARBAGE_COLLECT);
put ("gc", TOKEN_GARBAGE_COLLECT);
}
typedef struct Tokenizer Tokenizer;
struct Tokenizer
{
char *start;
char *current;
int32_t line;
};
Tokenizer tokenizer;
void
initTokenizer (char *src)
{
tokenizer.start = src;
tokenizer.current = src;
tokenizer.line = 1;
}
static bool
isAlpha (char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
|| c == '\'' || c == '?';
}
static bool
isDigit (char c)
{
return (c >= '0' && c <= '9') || c == '-';
}
static bool
isAtEnd ()
{
return *tokenizer.current == '\0';
}
static Token
makeToken (TokenType type)
{
Token token;
token.type = type;
token.start = tokenizer.start;
token.length = (int32_t)(tokenizer.current - tokenizer.start);
token.line = tokenizer.line;
return token;
}
static Token
errorToken (char *msg)
{
Token token;
token.type = TOKEN_ERROR;
token.start = msg;
token.length = (int32_t)strlen (msg);
token.line = tokenizer.line;
return token;
}
static char
advance ()
{
tokenizer.current++;
return tokenizer.current[-1];
}
static char
peek ()
{
return *tokenizer.current;
}
static char
peekNext ()
{
if (isAtEnd ())
return '\0';
return tokenizer.current[1];
}
static bool
match (char expected)
{
if (isAtEnd ())
return false;
if (*tokenizer.current != expected)
return false;
tokenizer.current++;
return true;
}
static void
skipWhitespace ()
{
for (;;)
{
char c = peek ();
switch (c)
{
case ' ':
case '\r':
case '\t':
advance ();
break;
case '\n':
tokenizer.line++;
advance ();
break;
case '/':
if (peekNext () == '/')
{
// Ignore the preprocessor import until end of the line.
while (peek () != '\n' && !isAtEnd ())
advance ();
}
else
{
return;
}
break;
case '(':
if (peekNext () == '*')
{
advance (); // consume (
advance (); // consume *
while (!isAtEnd () && peek () != '*' && peekNext () != ')')
advance (); // Consume contents
advance (); // consume *
advance (); // consume )
}
break;
default:
return;
}
}
}
static TokenType
checkKeyword (int start, int length, char *rest, TokenType type)
{
if (tokenizer.current - tokenizer.start == start + length
&& memcmp (tokenizer.start + start, rest, length) == 0)
{
return type;
}
return TOKEN_IDENTIFIER;
}
static TokenType
identifierType ()
{
char *check;
int32_t size = tokenizer.current - tokenizer.start;
check = (char *)malloc (sizeof (size));
strncpy (check, tokenizer.start, size);
check[size] = '\0';
TokenType t = get (check);
free (check);
return t;
}
static Token
identifier ()
{
while (isAlpha (peek ()) || isDigit (peek ()))
advance ();
return makeToken (identifierType ());
}
static Token
number ()
{
bool is_float = false;
while (isDigit (peek ()))
advance ();
// Look for a fractional part.
if (peek () == '.' && isDigit (peekNext ()))
{
is_float = true;
// Consume the ".".
advance ();
while (isDigit (peek ()))
advance ();
}
return makeToken (is_float ? TOKEN_FLOAT
: TOKEN_INT); // or measure if ends in postscript
}
static Token
string ()
{
while (peek () != '"' && !isAtEnd ())
{
if (peek () == '\n')
tokenizer.line++;
advance ();
}
if (isAtEnd ())
return errorToken ("Unterminated string.");
// The closing quote.
advance ();
return makeToken (TOKEN_STRING);
}
Token
nextToken ()
{
skipWhitespace ();
tokenizer.start = tokenizer.current;
if (isAtEnd ())
return makeToken (TOKEN_EOF);
char c = advance ();
if (isAlpha (c))
return identifier ();
if (isDigit (c))
return number ();
switch (c)
{
case '(':
return makeToken (TOKEN_LEFT_PAREN);
case ')':
return makeToken (TOKEN_RIGHT_PAREN);
case '{':
return makeToken (TOKEN_LEFT_BRACE);
case '}':
return makeToken (TOKEN_RIGHT_BRACE);
case '-':
return makeToken (TOKEN_NEGATIVE);
case '~':
return makeToken (TOKEN_TILDE);
case '/':
return makeToken (TOKEN_SLASH);
case '"':
return string ();
}
return errorToken ("Unexpected character.");
}
void
debug_printToken (Token t)
{
switch (t.type)
{
case TOKEN_LEFT_PAREN:
printf ("TOKEN_LEFT_PAREN line_no=%d\n", t.line);
break;
case TOKEN_RIGHT_PAREN:
printf ("TOKEN_RIGHT_PAREN line_no=%d\n", t.line);
break;
case TOKEN_LEFT_BRACE:
printf ("TOKEN_LEFT_BRACE line_no=%d\n", t.line);
break;
case TOKEN_RIGHT_BRACE:
printf ("TOKEN_RIGHT_BRACE line_no=%d\n", t.line);
break;
case TOKEN_TILDE:
printf ("TOKEN_TILDE line_no=%d\n", t.line);
break;
case TOKEN_SLASH:
printf ("TOKEN_SLASH line_no=%d\n", t.line);
break;
case TOKEN_MINUS:
printf ("TOKEN_MINUS line_no=%d\n", t.line);
break;
case TOKEN_IDENTIFIER:
printf ("TOKEN_IDENTIFIER line_no=%d\n", t.line);
break;
case TOKEN_STRING:
printf ("TOKEN_STRING line_no=%d\n", t.line);
break;
case TOKEN_FLOAT:
printf ("TOKEN_FLOAT line_no=%d\n", t.line);
break;
case TOKEN_LIST:
printf ("TOKEN_LIST line_no=%d\n", t.line);
break;
case TOKEN_ERROR:
printf ("TOKEN_ERROR line_no=%d\n", t.line);
break;
case TOKEN_FALSE:
printf ("TOKEN_FALSE line_no=%d\n", t.line);
break;
case TOKEN_TRUE:
printf ("TOKEN_TRUE line_no=%d\n", t.line);
break;
case TOKEN_PI:
printf ("TOKEN_PI line_no=%d\n", t.line);
break;
case TOKEN_E:
printf ("TOKEN_E line_no=%d\n", t.line);
break;
case TOKEN_EOF:
printf ("TOKEN_EOF line_no=%d\n", t.line);
break;
case TOKEN_POP:
printf ("TOKEN_POP line_no=%d\n", t.line);
break;
case TOKEN_DUP:
printf ("TOKEN_DUP line_no=%d\n", t.line);
break;
case TOKEN_EXCH:
printf ("TOKEN_EXCH line_no=%d\n", t.line);
break;
case TOKEN_CLEAR:
printf ("TOKEN_CLEAR line_no=%d\n", t.line);
break;
case TOKEN_REMEMBER:
printf ("TOKEN_REMEMBER line_no=%d\n", t.line);
break;
case TOKEN_FORGET:
printf ("TOKEN_FORGET line_no=%d\n", t.line);
break;
case TOKEN_DUMP:
printf ("TOKEN_DUMP line_no=%d\n", t.line);
break;
case TOKEN_NAME:
printf ("TOKEN_NAME line_no=%d\n", t.line);
break;
case TOKEN_SET:
printf ("TOKEN_SET line_no=%d\n", t.line);
break;
case TOKEN_IFYES:
printf ("TOKEN_IFYES line_no=%d\n", t.line);
break;
case TOKEN_IFNO:
printf ("TOKEN_IFNO line_no=%d\n", t.line);
break;
case TOKEN_CHOOSE:
printf ("TOKEN_CHOOSE line_no=%d\n", t.line);
break;
case TOKEN_EVAL:
printf ("TOKEN_EVAL line_no=%d\n", t.line);
break;
case TOKEN_ESCAPE:
printf ("TOKEN_ESCAPE line_no=%d\n", t.line);
break;
case TOKEN_REPEAT:
printf ("TOKEN_REPEAT line_no=%d\n", t.line);
break;
case TOKEN_SPLIT:
printf ("TOKEN_SPLIT line_no=%d\n", t.line);
break;
case TOKEN_CONS:
printf ("TOKEN_CONS line_no=%d\n", t.line);
break;
case TOKEN_SHATTER:
printf ("TOKEN_SHATTER line_no=%d\n", t.line);
break;
case TOKEN_EMPTY:
printf ("TOKEN_EMPTY line_no=%d\n", t.line);
break;
case TOKEN_COMPOSE:
printf ("TOKEN_COMPOSE line_no=%d\n", t.line);
break;
case TOKEN_STREQ:
printf ("TOKEN_STREQ line_no=%d\n", t.line);
break;
case TOKEN_STRCUT:
printf ("TOKEN_STRCUT line_no=%d\n", t.line);
break;
case TOKEN_STRMEASURE:
printf ("TOKEN_STRMEASURE line_no=%d\n", t.line);
break;
case TOKEN_STRTIE:
printf ("TOKEN_STRTIE line_no=%d\n", t.line);
break;
case TOKEN_EXPLODE:
printf ("TOKEN_EXPLODE line_no=%d\n", t.line);
break;
case TOKEN_ADD:
printf ("TOKEN_ADD line_no=%d\n", t.line);
break;
case TOKEN_SUB:
printf ("TOKEN_SUB line_no=%d\n", t.line);
break;
case TOKEN_MUL:
printf ("TOKEN_MUL line_no=%d\n", t.line);
break;
case TOKEN_DIV:
printf ("TOKEN_DIV line_no=%d\n", t.line);
break;
case TOKEN_IDIV:
printf ("TOKEN_IDIV line_no=%d\n", t.line);
break;
case TOKEN_MOD:
printf ("TOKEN_MOD line_no=%d\n", t.line);
break;
case TOKEN_POW:
printf ("TOKEN_POW line_no=%d\n", t.line);
break;
case TOKEN_SQRT:
printf ("TOKEN_SQRT line_no=%d\n", t.line);
break;
case TOKEN_ADD1:
printf ("TOKEN_ADD1 line_no=%d\n", t.line);
break;
case TOKEN_SUB1:
printf ("TOKEN_SUB1 line_no=%d\n", t.line);
break;
case TOKEN_SIN:
printf ("TOKEN_SIN line_no=%d\n", t.line);
break;
case TOKEN_COS:
printf ("TOKEN_COS line_no=%d\n", t.line);
break;
case TOKEN_TAN:
printf ("TOKEN_TAN line_no=%d\n", t.line);
break;
case TOKEN_ATAN:
printf ("TOKEN_ATAN line_no=%d\n", t.line);
break;
case TOKEN_LN:
printf ("TOKEN_LN line_no=%d\n", t.line);
break;
case TOKEN_LOG:
printf ("TOKEN_LOG line_no=%d\n", t.line);
break;
case TOKEN_LOG3:
printf ("TOKEN_LOG3 line_no=%d\n", t.line);
break;
case TOKEN_CLIP:
printf ("TOKEN_CLIP line_no=%d\n", t.line);
break;
case TOKEN_SMOOTH:
printf ("TOKEN_SMOOTH line_no=%d\n", t.line);
break;
case TOKEN_HOWMUCH:
printf ("TOKEN_HOWMUCH line_no=%d\n", t.line);
break;
case TOKEN_SETRAND:
printf ("TOKEN_SETRAND line_no=%d\n", t.line);
break;
case TOKEN_RAND:
printf ("TOKEN_RAND line_no=%d\n", t.line);
break;
case TOKEN_INT:
printf ("TOKEN_INT line_no=%d\n", t.line);
break;
case TOKEN_NUMBERIZE:
printf ("TOKEN_NUMBERIZE line_no=%d\n", t.line);
break;
case TOKEN_ISOLATE:
printf ("TOKEN_ISOLATE line_no=%d\n", t.line);
break;
case TOKEN_MIX:
printf ("TOKEN_MIX line_no=%d\n", t.line);
break;
case TOKEN_CONTRADICT:
printf ("TOKEN_CONTRADICT line_no=%d\n", t.line);
break;
case TOKEN_COMPL:
printf ("TOKEN_COMPL line_no=%d\n", t.line);
break;
case TOKEN_SHIFTRIGHT:
printf ("TOKEN_SHIFTRIGHT line_no=%d\n", t.line);
break;
case TOKEN_SHIFTLEFT:
printf ("TOKEN_SHIFTLEFT line_no=%d\n", t.line);
break;
case TOKEN_GT:
printf ("TOKEN_GT line_no=%d\n", t.line);
break;
case TOKEN_LT:
printf ("TOKEN_LT line_no=%d\n", t.line);
break;
case TOKEN_EQ:
printf ("TOKEN_EQ line_no=%d\n", t.line);
break;
case TOKEN_GE:
printf ("TOKEN_GE line_no=%d\n", t.line);
break;
case TOKEN_LE:
printf ("TOKEN_LE line_no=%d\n", t.line);
break;
case TOKEN_NE:
printf ("TOKEN_NE line_no=%d\n", t.line);
break;
case TOKEN_NULL:
printf ("TOKEN_NULL line_no=%d\n", t.line);
break;
case TOKEN_NEGATIVE:
printf ("TOKEN_NEGATIVE line_no=%d\n", t.line);
break;
case TOKEN_ISNULL:
printf ("TOKEN_ISNULL line_no=%d\n", t.line);
break;
case TOKEN_ISINT:
printf ("TOKEN_ISINT line_no=%d\n", t.line);
break;
case TOKEN_ISNUMBER:
printf ("TOKEN_ISNUMBER line_no=%d\n", t.line);
break;
case TOKEN_AND:
printf ("TOKEN_AND line_no=%d\n", t.line);
break;
case TOKEN_OR:
printf ("TOKEN_OR line_no=%d\n", t.line);
break;
case TOKEN_XOR:
printf ("TOKEN_XOR line_no=%d\n", t.line);
break;
case TOKEN_DISP:
printf ("TOKEN_DISP line_no=%d\n", t.line);
break;
case TOKEN_LISTEN:
printf ("TOKEN_LISTEN line_no=%d\n", t.line);
break;
case TOKEN_COMPLAIN:
printf ("TOKEN_COMPLAIN line_no=%d\n", t.line);
break;
case TOKEN_TIME:
printf ("TOKEN_TIME line_no=%d\n", t.line);
break;
case TOKEN_GARBAGE_COLLECT:
printf ("TOKEN_GARBAGE_COLLECT line_no=%d\n", t.line);
break;
}
}

126
tokenizer.h Normal file
View File

@ -0,0 +1,126 @@
#ifndef TOKENIZER_H
#define TOKENIZER_H
#include "common.h"
typedef enum TokenType
{
// Single char tokens
TOKEN_LEFT_PAREN,
TOKEN_RIGHT_PAREN,
TOKEN_LEFT_BRACE,
TOKEN_RIGHT_BRACE,
TOKEN_TILDE,
TOKEN_SLASH,
TOKEN_MINUS,
// Literals
TOKEN_IDENTIFIER,
TOKEN_STRING,
TOKEN_FLOAT,
TOKEN_LIST,
TOKEN_ERROR,
TOKEN_FALSE,
TOKEN_TRUE,
TOKEN_PI,
TOKEN_E,
TOKEN_EOF,
// Keywords
TOKEN_POP,
TOKEN_DUP,
TOKEN_EXCH,
TOKEN_CLEAR,
TOKEN_REMEMBER,
TOKEN_FORGET,
TOKEN_DUMP,
TOKEN_NAME,
TOKEN_SET,
TOKEN_IFYES,
TOKEN_IFNO,
TOKEN_CHOOSE,
TOKEN_EVAL,
TOKEN_ESCAPE,
TOKEN_REPEAT,
TOKEN_SPLIT,
TOKEN_CONS,
TOKEN_SHATTER,
TOKEN_EMPTY,
TOKEN_COMPOSE,
TOKEN_STREQ,
TOKEN_STRCUT,
TOKEN_STRMEASURE,
TOKEN_STRTIE,
TOKEN_EXPLODE,
TOKEN_ADD,
TOKEN_SUB,
TOKEN_MUL,
TOKEN_DIV,
TOKEN_IDIV,
TOKEN_MOD,
TOKEN_POW,
TOKEN_SQRT,
TOKEN_ADD1,
TOKEN_SUB1,
TOKEN_SIN,
TOKEN_COS,
TOKEN_TAN,
TOKEN_ATAN,
TOKEN_LN,
TOKEN_LOG,
TOKEN_LOG3,
TOKEN_CLIP,
TOKEN_SMOOTH,
TOKEN_HOWMUCH,
TOKEN_SETRAND,
TOKEN_RAND,
TOKEN_INT,
TOKEN_NUMBERIZE,
TOKEN_ISOLATE,
TOKEN_MIX,
TOKEN_CONTRADICT,
TOKEN_COMPL,
TOKEN_SHIFTRIGHT,
TOKEN_SHIFTLEFT,
TOKEN_GT,
TOKEN_LT,
TOKEN_EQ,
TOKEN_GE,
TOKEN_LE,
TOKEN_NE,
TOKEN_NULL,
TOKEN_NEGATIVE,
TOKEN_ISNULL,
TOKEN_ISINT,
TOKEN_ISNUMBER,
TOKEN_AND,
TOKEN_OR,
TOKEN_XOR,
TOKEN_DISP,
TOKEN_LISTEN,
TOKEN_COMPLAIN,
TOKEN_TIME,
TOKEN_GARBAGE_COLLECT,
} TokenType;
typedef struct Token Token;
struct Token
{
TokenType type;
char *start;
int32_t length;
int32_t line;
};
typedef struct SourceCode SourceCode;
struct SourceCode
{
size_t size;
char *buf;
int count;
};
void initTokenizer (char *src);
Token nextToken ();
void initMap ();
void debug_printToken (Token t);
#endif