This commit is contained in:
2025-06-08 21:56:29 +00:00
parent 261e3a4b14
commit 9ef9077368
5 changed files with 1566 additions and 0 deletions

231
xanguage.h Normal file
View File

@@ -0,0 +1,231 @@
/// __ ____ _ _ __ __ _ _ _ __ _ __ _ ___
/// \ \/ / _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \
/// > < (_| | | | | (_| | |_| | (_| | (_| | __/
/// /_/\_\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___|
/// |___/ |___/
///
/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic
///
/// xolatile@chud.cyou - xanguage - Syntax definitions of programming languages that I care about (and some that I don't care about).
///
/// This program is free software, free as in freedom and as in free beer, you can redistribute it and/or modify it under the terms of the GNU
/// General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version if you wish...
///
/// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied
/// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License
/// for more details, if you dare, it is a lot of text that nobody wants to read...
/// Description
///
/// Xanguage, core programming and scripting language definitions created using Xyntax, with few more output definitions that I care about, for
/// example Valgrind. There's not much to document about this library, it's used in my projects Xarbon and Xighlight. You can add support for
/// your language of choice by adding one enumeration value, creating header file similar to existing ones, including it here and editing
/// functions below to match 'language_count'. If you don't like how I highlight one or more of these languages, feel free to add more fields in
/// 'language_structure' or edit existing ones inside 'xanguage' folder. This header file may look unfamiliar, especially to my other projects,
/// but that's the cost of highlighting multiple languages in very low amount of code.
/// Enumeration of supported languages, in no particular order.
typedef enum {
language_common, language_ada, language_c, language_cpp,
language_d, language_eaxhla, language_flat, language_fortran,
language_pascal, language_python, language_go, language_lua,
language_bash, language_haskell, language_valgrind, language_holy_c,
language_count
} language_enumeration;
/// Structure of single language definition, highlighting-wise, this will be initialized below, check out how it is used.
///
/// language_structure * language = null;
typedef struct {
natural comment_colour; /// Colours for basic language syntax information.
natural processor_colour;
natural character_colour;
natural string_colour;
natural keyword_colour;
natural type_colour;
natural bracket_colour;
natural operator_colour;
natural number_colour;
natural lowercase_colour;
natural uppercase_colour;
natural underscore_colour;
natural register_colour;
natural extension_colour;
natural fatal_colour;
natural comment_effect; /// Effects for basic language syntax information.
natural processor_effect;
natural character_effect;
natural string_effect;
natural keyword_effect;
natural type_effect;
natural bracket_effect;
natural operator_effect;
natural number_effect;
natural lowercase_effect;
natural uppercase_effect;
natural underscore_effect;
natural register_effect;
natural extension_effect;
natural fatal_effect;
} language_structure;
/// Warning: Local macros! You don't need to use this at all, it's covered by other functions, don't worry about it.
///
/// You shouldn't care about these local macros, they made few lines of code shorter, we're including files in this order, in this place.
#define language_lowercase "abcdefghijklmnopqrstuvwxyz"
#define language_uppercase "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define language_letters "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define language_digits "0123456789"
#include <xolatile/xanguage/common.h>
#include <xolatile/xanguage/ada.h>
#include <xolatile/xanguage/c.h>
#include <xolatile/xanguage/c++.h>
#include <xolatile/xanguage/d.h>
#include <xolatile/xanguage/eaxhla.h>
#include <xolatile/xanguage/flat.h>
#include <xolatile/xanguage/fortran.h>
#include <xolatile/xanguage/pascal.h>
#include <xolatile/xanguage/python.h>
#include <xolatile/xanguage/go.h>
#include <xolatile/xanguage/holy_c.h>
#include <xolatile/xanguage/lua.h>
#include <xolatile/xanguage/bash.h>
#include <xolatile/xanguage/haskell.h>
#include <xolatile/xanguage/valgrind.h>
#undef language_lowercase
#undef language_uppercase
#undef language_letters
#undef language_digits
/// Array of function pointers enumerated above, these functions are defined in separate header files in 'xanguage' folder.
static procedure (* language_highlighter [language_count]) (language_structure * language, syntax_structure * syntax) = {
language_highlight_common, language_highlight_ada, language_highlight_c, language_highlight_cpp,
language_highlight_d, language_highlight_eaxhla, language_highlight_flat, language_highlight_fortran,
language_highlight_pascal, language_highlight_python, language_highlight_go, language_highlight_lua,
language_highlight_bash, language_highlight_haskell, language_highlight_valgrind, language_highlight_holy_c
};
/// Array of short command line argument enumerated above, makes main function less bloated.
static character * language_short_option [language_count] = {
"-X", "-A", "-C", "-S", "-D", "-E", "-T", "-F", "-P", "-Y", "-G", "-L", "-B", "-H", "-V", "-O"
};
/// Array of long command line argument enumerated above, makes main function less bloated.
static character * language_long_option [language_count] = {
"--common", "--ada", "--c", "--cpp", "--d", "--eaxhla", "--flat", "--fortran",
"--pascal", "--python", "--go", "--lua", "--bash", "--haskell", "--valgrind", "--holyc"
};
/// Array of pretty language name enumerated above, makes things pretty.
static character * language_identifier [language_count] = {
"Common", "Ada", "C", "C++", "D", "EAXHLA", "Flat", "Fortran",
"Pascal", "Python", "Go", "Lua", "Bash", "Haskell", "Valgrind", "Holy C"
};
/// After you've defined global or local language variable, you want to initialize it, edit this function if you dislike my themes.
///
/// language = language_initialize (false); /// You're probably using this library to render an image.
/// language = language_initialize (true); /// You're probably using this library to print to terminal.
static language_structure * language_initialize (boolean true_colour) {
language_structure * language = allocate (sizeof (* language));
if (true_colour == true) {
language->comment_colour = 0xff777777u;
language->processor_colour = 0xff3377aau;
language->character_colour = 0xff7733ccu;
language->string_colour = 0xffcc3377u;
language->keyword_colour = 0xff33cceeu;
language->type_colour = 0xff55cceeu;
language->bracket_colour = 0xffee5533u;
language->operator_colour = 0xffeeaa33u;
language->number_colour = 0xffee33aau;
language->lowercase_colour = 0xffccccccu;
language->uppercase_colour = 0xffeeeeeeu;
language->underscore_colour = 0xffaaaaaau;
language->register_colour = 0xff5577aau;
language->extension_colour = 0xff55aaccu;
language->fatal_colour = 0xffcc7755u;
} else {
language->comment_colour = colour_grey;
language->processor_colour = colour_cyan;
language->character_colour = colour_pink;
language->string_colour = colour_pink;
language->keyword_colour = colour_yellow;
language->type_colour = colour_yellow;
language->bracket_colour = colour_blue;
language->operator_colour = colour_cyan;
language->number_colour = colour_pink;
language->lowercase_colour = colour_white;
language->uppercase_colour = colour_white;
language->underscore_colour = colour_white;
language->register_colour = colour_cyan;
language->extension_colour = colour_yellow;
language->fatal_colour = colour_red;
language->comment_effect = effect_bold;
language->processor_effect = effect_italic;
language->character_effect = effect_bold;
language->string_effect = effect_normal;
language->keyword_effect = effect_bold;
language->type_effect = effect_normal;
language->bracket_effect = effect_bold;
language->operator_effect = effect_normal;
language->number_effect = effect_bold;
language->lowercase_effect = effect_normal;
language->uppercase_effect = effect_bold;
language->underscore_effect = effect_italic;
language->register_effect = effect_italic;
language->extension_effect = effect_italic;
language->fatal_effect = effect_bold;
}
return (language);
}
/// When you're done doing your thing, just call this function nicely to avoid leaking memory.
///
/// language = language_deinitialize (language);
static language_structure * language_deinitialize (language_structure * language) {
return (deallocate (language));
}
/// This is just a helper function that I used a lot, it made sense to define it in this file, so here it is... This function will call specific
/// function from 'xanguage' folder, based on what file type you pass to it, enumerated in Xtandard. It takes natural number as selection value
/// due to avoiding type-related errors that dumb compilers might warn about, because some C compilers treat enumeration values as signed, while
/// others treat them as unsigned, unless you manually define some value there negative, which is braindead.
///
/// language_conditionally_select (language, syntax, selection_index);
static procedure language_conditionally_select (language_structure * language, syntax_structure * syntax, natural select) {
if (syntax->count == 0) {
if ((select == file_type_c_source) || (select == file_type_c_header)) {
language_highlight_c (language, syntax);
} else if ((select == file_type_ada_sexy_body) || (select == file_type_ada_specification)) {
language_highlight_ada (language, syntax);
} else if ((select == file_type_cpp_source) || (select == file_type_cpp_header)) {
language_highlight_cpp (language, syntax);
} else if (select == file_type_flat_assembly) {
language_highlight_flat (language, syntax);
} else if (select == file_type_fortran_90_source) {
language_highlight_fortran (language, syntax);
} else if (select == file_type_pascal_source) {
language_highlight_pascal (language, syntax);
} else if (select == file_type_eax_assembly) {
language_highlight_eaxhla (language, syntax);
} else if (select == file_type_python_script) {
language_highlight_python (language, syntax);
} else {
language_highlight_common (language, syntax);
}
}
}

495
xatrix.h Normal file
View File

@@ -0,0 +1,495 @@
/// _ _
/// __ ____ _| |_ _ __(_)_ __
/// \ \/ / _` | __| '__| \ \/ /
/// > < (_| | |_| | | |> <
/// /_/\_\__,_|\__|_| |_/_/\_\
///
/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic
///
/// xolatile@chud.cyou - xatrix - Very dumb and slow matrix library, mathematical matrix, because I don't like other people ideas...
///
/// This program is free software, free as in freedom and as in free beer, you can redistribute it and/or modify it under the terms of the GNU
/// General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version if you wish...
///
/// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied
/// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License
/// for more details, if you dare, it is a lot of text that nobody wants to read...
/// Description
///
/// Xatrix, my tiny braindead unoptimized matrix library. Unlike vectors that use x, y, z and w structure fields, matrices are double array of
/// 32-bit floating point numbers, and they're accessed with integers, which should've been the same case with vectors, but mathematicians are
/// dumb sometimes (blame it on the one being older than the other one?). Again, nothing much to talk about here, learn linear algebra, include
/// this header file in your project, use it however you want, compilers might optimize this better than my vector library. This library isn't
/// intended for neural networks, as it's not generic, it can be used in simple CPU-based ray tracers and physics simulations.
/// Nice 2D, 3D and 4D matrix structures.
typedef real matrix_2 [2] [2]; /// Tiny 2x2 matrix.
typedef real matrix_3 [3] [3]; /// Tiny 3x3 matrix.
typedef real matrix_4 [4] [4]; /// Tiny 4x4 matrix.
/// Assign values to 2D, 3D or 4D matrix and return address of that matrix.
static matrix_2 * matrix_2_assign (matrix_2 * destination,
real m00, real m01,
real m10, real m11) {
destination [0] [0] = m00; destination [0] [1] = m01;
destination [1] [0] = m10; destination [1] [1] = m11;
return (destination);
}
static matrix_3 * matrix_3_assign (matrix_3 * destination,
real m00, real m01, real m02,
real m10, real m11, real m12,
real m20, real m21, real m22) {
destination [0] [0] = m00; destination [0] [1] = m01; destination [0] [2] = m02;
destination [1] [0] = m10; destination [1] [1] = m11; destination [1] [2] = m12;
destination [2] [0] = m20; destination [2] [1] = m21; destination [2] [2] = m22;
return (destination);
}
static matrix_4 * matrix_4_assign (matrix_4 * destination,
real m00, real m01, real m02, real m03,
real m10, real m11, real m12, real m13,
real m20, real m21, real m22, real m23,
real m30, real m31, real m32, real m33) {
destination [0] [0] = m00; destination [0] [1] = m01; destination [0] [2] = m02; destination [0] [3] = m03;
destination [1] [0] = m10; destination [1] [1] = m11; destination [1] [2] = m12; destination [1] [3] = m13;
destination [2] [0] = m20; destination [2] [1] = m21; destination [2] [2] = m22; destination [2] [3] = m23;
destination [3] [0] = m30; destination [3] [1] = m31; destination [3] [2] = m32; destination [3] [3] = m33;
return (destination);
}
/// Nullify values of 2D, 3D or 4D matrix and return address of that matrix.
static matrix_2 * matrix_2_nullify (matrix_2 * destination) {
for (natural row = 0; row < 2; ++row) {
for (natural column = 0; column < 2; ++column) {
destination [row] [column] = 0.0f;
}
}
return (destination);
}
static matrix_3 * matrix_3_nullify (matrix_3 * destination) {
for (natural row = 0; row < 3; ++row) {
for (natural column = 0; column < 3; ++column) {
destination [row] [column] = 0.0f;
}
}
return (destination);
}
static matrix_4 * matrix_4_nullify (matrix_4 * destination) {
for (natural row = 0; row < 4; ++row) {
for (natural column = 0; column < 4; ++column) {
destination [row] [column] = 0.0f;
}
}
return (destination);
}
/// Identify values of 2D, 3D or 4D matrix and return address of that matrix.
static matrix_2 * matrix_2_identity (matrix_2 * destination) {
destination = matrix_2_nullify (destination);
for (natural index = 0; index < 2; ++index) {
destination [index] [index] = 1.0f;
}
return (destination);
}
static matrix_3 * matrix_3_identity (matrix_3 * destination) {
destination = matrix_3_nullify (destination);
for (natural index = 0; index < 3; ++index) {
destination [index] [index] = 1.0f;
}
return (destination);
}
static matrix_4 * matrix_4_identity (matrix_4 * destination) {
destination = matrix_4_nullify (destination);
for (natural index = 0; index < 4; ++index) {
destination [index] [index] = 1.0f;
}
return (destination);
}
/// Return determinant of 2D, 3D or 4D matrix.
static real matrix_2_determinant (matrix_2 * matrix) {
real a = matrix [0] [0] * matrix [1] [1];
real b = matrix [0] [1] * matrix [1] [0];
return (a - b);
}
static real matrix_3_determinant (matrix_3 * matrix) {
matrix_2 matrix_a = { { matrix [1] [1], matrix [1] [2] },
{ matrix [2] [1], matrix [2] [2] } };
matrix_2 matrix_b = { { matrix [1] [0], matrix [1] [2] },
{ matrix [2] [0], matrix [2] [2] } };
matrix_2 matrix_c = { { matrix [1] [0], matrix [1] [1] },
{ matrix [2] [0], matrix [2] [1] } };
real a = matrix [0] [0] * matrix_2_determinant (& matrix_a);
real b = matrix [0] [1] * matrix_2_determinant (& matrix_b);
real c = matrix [0] [2] * matrix_2_determinant (& matrix_c);
return (a - b + c);
}
static real matrix_4_determinant (matrix_4 * matrix) {
matrix_3 matrix_a = { { matrix [1] [1], matrix [1] [2], matrix [1] [3] },
{ matrix [2] [1], matrix [2] [2], matrix [2] [3] },
{ matrix [3] [1], matrix [3] [2], matrix [3] [3] } };
matrix_3 matrix_b = { { matrix [1] [0], matrix [1] [2], matrix [1] [3] },
{ matrix [2] [0], matrix [2] [2], matrix [2] [3] },
{ matrix [3] [0], matrix [3] [2], matrix [3] [3] } };
matrix_3 matrix_c = { { matrix [1] [0], matrix [1] [1], matrix [1] [3] },
{ matrix [2] [0], matrix [2] [1], matrix [2] [3] },
{ matrix [3] [0], matrix [3] [1], matrix [3] [3] } };
matrix_3 matrix_d = { { matrix [1] [0], matrix [1] [1], matrix [1] [2] },
{ matrix [2] [0], matrix [2] [1], matrix [2] [2] },
{ matrix [3] [0], matrix [3] [1], matrix [3] [2] } };
real a = matrix [0] [0] * matrix_3_determinant (& matrix_a);
real b = matrix [0] [1] * matrix_3_determinant (& matrix_b);
real c = matrix [0] [2] * matrix_3_determinant (& matrix_c);
real d = matrix [0] [3] * matrix_3_determinant (& matrix_d);
return (a - b + c - d);
}
/// Copy 2D, 3D or 4D source matrix into destination matrix.
static matrix_2 * matrix_2_copy (matrix_2 * destination, matrix_2 * source) {
for (natural row = 0; row < 2; ++row) {
for (natural column = 0; column < 2; ++column) {
destination [row] [column] = source [row] [column];
}
}
return (destination);
}
static matrix_3 * matrix_3_copy (matrix_3 * destination, matrix_3 * source) {
for (natural row = 0; row < 3; ++row) {
for (natural column = 0; column < 3; ++column) {
destination [row] [column] = source [row] [column];
}
}
return (destination);
}
static matrix_4 * matrix_4_copy (matrix_4 * destination, matrix_4 * source) {
for (natural row = 0; row < 4; ++row) {
for (natural column = 0; column < 4; ++column) {
destination [row] [column] = source [row] [column];
}
}
return (destination);
}
/// Scale 2D, 3D or 4D matrix by scalar value and return address of that matrix.
static matrix_2 * matrix_2_scale (matrix_2 * destination, real scale) {
for (natural row = 0; row < 2; ++row) {
for (natural column = 0; column < 2; ++column) {
destination [row] [column] *= scale;
}
}
return (destination);
}
static matrix_3 * matrix_3_scale (matrix_3 * destination, real scale) {
for (natural row = 0; row < 3; ++row) {
for (natural column = 0; column < 3; ++column) {
destination [row] [column] *= scale;
}
}
return (destination);
}
static matrix_4 * matrix_4_scale (matrix_4 * destination, real scale) {
for (natural row = 0; row < 4; ++row) {
for (natural column = 0; column < 4; ++column) {
destination [row] [column] *= scale;
}
}
return (destination);
}
/// Scale 2D, 3D or 4D source matrix by scalar value into destination matrix and return its address.
static matrix_2 * matrix_2_scale_to (matrix_2 * destination, matrix_2 * source, real scale) {
for (natural row = 0; row < 2; ++row) {
for (natural column = 0; column < 2; ++column) {
destination [row] [column] = source [row] [column] * scale;
}
}
return (destination);
}
static matrix_3 * matrix_3_scale_to (matrix_3 * destination, matrix_3 * source, real scale) {
for (natural row = 0; row < 3; ++row) {
for (natural column = 0; column < 3; ++column) {
destination [row] [column] = source [row] [column] * scale;
}
}
return (destination);
}
static matrix_4 * matrix_4_scale_to (matrix_4 * destination, matrix_4 * source, real scale) {
for (natural row = 0; row < 4; ++row) {
for (natural column = 0; column < 4; ++column) {
destination [row] [column] = source [row] [column] * scale;
}
}
return (destination);
}
/// Add 2D, 3D or 4D source matrix onto destination matrix and return address of destination matrix.
static matrix_2 * matrix_2_add (matrix_2 * destination, matrix_2 * source) {
for (natural row = 0; row < 2; ++row) {
for (natural column = 0; column < 2; ++column) {
destination [row] [column] += source [row] [column];
}
}
return (destination);
}
static matrix_3 * matrix_3_add (matrix_3 * destination, matrix_3 * source) {
for (natural row = 0; row < 3; ++row) {
for (natural column = 0; column < 3; ++column) {
destination [row] [column] += source [row] [column];
}
}
return (destination);
}
static matrix_4 * matrix_4_add (matrix_4 * destination, matrix_4 * source) {
for (natural row = 0; row < 4; ++row) {
for (natural column = 0; column < 4; ++column) {
destination [row] [column] += source [row] [column];
}
}
return (destination);
}
/// Add two 2D, 3D or 4D matrices into destination matrix and return address of destination matrix.
static matrix_2 * matrix_2_add_to (matrix_2 * destination, matrix_2 * matrix_a, matrix_2 * matrix_b) {
for (natural row = 0; row < 2; ++row) {
for (natural column = 0; column < 2; ++column) {
destination [row] [column] = matrix_a [row] [column] + matrix_b [row] [column];
}
}
return (destination);
}
static matrix_3 * matrix_3_add_to (matrix_3 * destination, matrix_3 * matrix_a, matrix_3 * matrix_b) {
for (natural row = 0; row < 3; ++row) {
for (natural column = 0; column < 3; ++column) {
destination [row] [column] = matrix_a [row] [column] + matrix_b [row] [column];
}
}
return (destination);
}
static matrix_4 * matrix_4_add_to (matrix_4 * destination, matrix_4 * matrix_a, matrix_4 * matrix_b) {
for (natural row = 0; row < 4; ++row) {
for (natural column = 0; column < 4; ++column) {
destination [row] [column] = matrix_a [row] [column] + matrix_b [row] [column];
}
}
return (destination);
}
/// Subtract 2D, 3D or 4D source matrix from destination matrix and return address of destination matrix.
static matrix_2 * matrix_2_subtract (matrix_2 * destination, matrix_2 * source) {
for (natural row = 0; row < 2; ++row) {
for (natural column = 0; column < 2; ++column) {
destination [row] [column] -= source [row] [column];
}
}
return (destination);
}
static matrix_3 * matrix_3_subtract (matrix_3 * destination, matrix_3 * source) {
for (natural row = 0; row < 3; ++row) {
for (natural column = 0; column < 3; ++column) {
destination [row] [column] -= source [row] [column];
}
}
return (destination);
}
static matrix_4 * matrix_4_subtract (matrix_4 * destination, matrix_4 * source) {
for (natural row = 0; row < 4; ++row) {
for (natural column = 0; column < 4; ++column) {
destination [row] [column] -= source [row] [column];
}
}
return (destination);
}
/// Subtract two 2D, 3D or 4D matrices, save values into destination matrix and return address of destination matrix.
static matrix_2 * matrix_2_subtract_to (matrix_2 * destination, matrix_2 * matrix_a, matrix_2 * matrix_b) {
for (natural row = 0; row < 2; ++row) {
for (natural column = 0; column < 2; ++column) {
destination [row] [column] = matrix_a [row] [column] - matrix_b [row] [column];
}
}
return (destination);
}
static matrix_3 * matrix_3_subtract_to (matrix_3 * destination, matrix_3 * matrix_a, matrix_3 * matrix_b) {
for (natural row = 0; row < 3; ++row) {
for (natural column = 0; column < 3; ++column) {
destination [row] [column] = matrix_a [row] [column] - matrix_b [row] [column];
}
}
return (destination);
}
static matrix_4 * matrix_4_subtract_to (matrix_4 * destination, matrix_4 * matrix_a, matrix_4 * matrix_b) {
for (natural row = 0; row < 4; ++row) {
for (natural column = 0; column < 4; ++column) {
destination [row] [column] = matrix_a [row] [column] - matrix_b [row] [column];
}
}
return (destination);
}
/// Multiply two 2D, 3D or 4D matrices, save values into destination matrix and return address of destination matrix.
static matrix_2 * matrix_2_multiply (matrix_2 * result, matrix_2 * matrix_a, matrix_2 * matrix_b) {
for (natural row = 0; row < 2; ++row) {
for (natural column = 0; column < 2; ++column) {
result [row] [column] = 0.0f;
for (natural index = 0; index < 2; ++index) {
result [row] [column] += matrix_a [row] [index] * matrix_b [index] [column];
}
}
}
return (result);
}
static matrix_3 * matrix_3_multiply (matrix_3 * result, matrix_3 * matrix_a, matrix_3 * matrix_b) {
for (natural row = 0; row < 3; ++row) {
for (natural column = 0; column < 3; ++column) {
result [row] [column] = 0.0f;
for (natural index = 0; index < 3; ++index) {
result [row] [column] += matrix_a [row] [index] * matrix_b [index] [column];
}
}
}
return (result);
}
static matrix_4 * matrix_4_multiply (matrix_4 * result, matrix_4 * matrix_a, matrix_4 * matrix_b) {
for (natural row = 0; row < 4; ++row) {
for (natural column = 0; column < 4; ++column) {
result [row] [column] = 0.0f;
for (natural index = 0; index < 4; ++index) {
result [row] [column] += matrix_a [row] [index] * matrix_b [index] [column];
}
}
}
return (result);
}
/// Return trace of 2D, 3D or 4D matrix.
static real matrix_2_trace (matrix_2 * matrix) {
return (matrix [0] [0] + matrix [1] [1]);
}
static real matrix_3_trace (matrix_3 * matrix) {
return (matrix [0] [0] + matrix [1] [1] + matrix [2] [2]);
}
static real matrix_4_trace (matrix_4 * matrix) {
return (matrix [0] [0] + matrix [1] [1] + matrix [2] [2] + matrix [3] [3]);
}
/// Compare if two 2D, 3D or 4D matrices are identical and return boolean value of it.
static boolean matrix_2_compare (matrix_2 * matrix_a, matrix_2 * matrix_b) {
for (natural row = 0; row < 2; ++row) {
for (natural column = 0; column < 2; ++column) {
if (matrix_a [row] [column] != matrix_b [row] [column]) {
return (false);
}
}
}
return (true);
}
static boolean matrix_3_compare (matrix_3 * matrix_a, matrix_3 * matrix_b) {
for (natural row = 0; row < 3; ++row) {
for (natural column = 0; column < 3; ++column) {
if (matrix_a [row] [column] != matrix_b [row] [column]) {
return (false);
}
}
}
return (true);
}
static boolean matrix_4_compare (matrix_4 * matrix_a, matrix_4 * matrix_b) {
for (natural row = 0; row < 4; ++row) {
for (natural column = 0; column < 4; ++column) {
if (matrix_a [row] [column] != matrix_b [row] [column]) {
return (false);
}
}
}
return (true);
}

438
xector.h Normal file
View File

@@ -0,0 +1,438 @@
/// _
/// __ _____ ___| |_ ___ _ __
/// \ \/ / _ \/ __| __/ _ \| '__|
/// > < __/ (__| || (_) | |
/// /_/\_\___|\___|\__\___/|_|
///
/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic
///
/// xolatile@chud.cyou - xector - Very slow and dumb vector library, mathematical vector, not that C++ cancer by the way...
///
/// This program is free software, free as in freedom and as in free beer, you can redistribute it and/or modify it under the terms of the GNU
/// General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version if you wish...
///
/// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied
/// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License
/// for more details, if you dare, it is a lot of text that nobody wants to read...
/// Description
///
/// Xector (Vector), my small vector library, not to be confused with my older project Xector (Sector) which was for procedurally generating 3D
/// models (based on boolean operations on 3D sectors). This library isn't optimized for performance or memory usage, instead it's for my own
/// preferred programming style. It's hard to explain linear algebra to people who don't already know it (for me at least), so I won't do that,
/// function names should provide you enough information. There'll be simple comments for the sake of consistency with my other libraries.
///
/// If you want to use "good" linear algebra library, prefer CGLM over this, and GLM if you're into C++ rather than objectively better language
/// called C. Again, reading comments in this file is useless. Include it, set the vectors, do the work.
/// 2D vector structure.
typedef struct {
real x, y; /// Two 32-bit floating point numbers.
} vector_2;
/// 3D vector structure.
typedef struct {
real x, y, z; /// Three 32-bit floating point numbers.
} vector_3;
/// 4D vector structure.
typedef struct {
real x, y, z, w; /// Why the hell did they choose to start from 'x', and end with 'z', it's so retarded.
} vector_4;
/// Assign values to 2D, 3D or 4D vector and return address of that vector.
static vector_2 * vector_2_assign (vector_2 * destination, real x, real y) {
destination->x = x;
destination->y = y;
return (destination);
}
static vector_3 * vector_3_assign (vector_3 * destination, real x, real y, real z) {
destination->x = x;
destination->y = y;
destination->z = z;
return (destination);
}
static vector_4 * vector_4_assign (vector_4 * destination, real x, real y, real z, real w) {
destination->x = x;
destination->y = y;
destination->z = z;
destination->w = w;
return (destination);
}
/// Nullify values of 2D, 3D or 4D vector and return address of that vector.
static vector_2 * vector_2_nullify (vector_2 * destination) {
destination->x = destination->y = 0.0f;
return (destination);
}
static vector_3 * vector_3_nullify (vector_3 * destination) {
destination->x = destination->y = destination->z = 0.0f;
return (destination);
}
static vector_4 * vector_4_nullify (vector_4 * destination) {
destination->x = destination->y = destination->z = destination->w = 0.0f;
return (destination);
}
/// Return length of 2D, 3D or 4D vector.
static real vector_2_length (vector_2 * vector) {
real x = vector->x;
real y = vector->y;
return (square_root (x * x + y * y));
}
static real vector_3_length (vector_3 * vector) {
real x = vector->x;
real y = vector->y;
real z = vector->z;
return (square_root (x * x + y * y + z * z));
}
static real vector_4_length (vector_4 * vector) {
real x = vector->x;
real y = vector->y;
real z = vector->z;
real w = vector->w;
return (square_root (x * x + y * y + z * z + w * w));
}
/// Normalize 2D, 3D or 4D vector and return address of that vector.
static vector_2 * vector_2_normalize (vector_2 * destination) {
real length = vector_2_length (destination);
destination->x /= length;
destination->y /= length;
return (destination);
}
static vector_3 * vector_3_normalize (vector_3 * destination) {
real length = vector_3_length (destination);
destination->x /= length;
destination->y /= length;
destination->z /= length;
return (destination);
}
static vector_4 * vector_4_normalize (vector_4 * destination) {
real length = vector_4_length (destination);
destination->x /= length;
destination->y /= length;
destination->z /= length;
destination->w /= length;
return (destination);
}
/// Normalize 2D, 3D or 4D source vector into destination vector and return its address.
static vector_2 * vector_2_normalize_to (vector_2 * destination, vector_2 * source) {
real length = vector_2_length (source);
destination->x = source->x / length;
destination->y = source->y / length;
return (destination);
}
static vector_3 * vector_3_normalize_to (vector_3 * destination, vector_3 * source) {
real length = vector_3_length (source);
destination->x = source->x / length;
destination->y = source->y / length;
destination->z = source->z / length;
return (destination);
}
static vector_4 * vector_4_normalize_to (vector_4 * destination, vector_4 * source) {
real length = vector_4_length (source);
destination->x = source->x / length;
destination->y = source->y / length;
destination->z = source->z / length;
destination->w = source->w / length;
return (destination);
}
/// Copy 2D, 3D or 4D source vector into destination vector.
static vector_2 * vector_2_copy (vector_2 * destination, vector_2 * source) {
destination->x = source->x;
destination->y = source->y;
return (destination);
}
static vector_3 * vector_3_copy (vector_3 * destination, vector_3 * source) {
destination->x = source->x;
destination->y = source->y;
destination->z = source->z;
return (destination);
}
static vector_4 * vector_4_copy (vector_4 * destination, vector_4 * source) {
destination->x = source->x;
destination->y = source->y;
destination->z = source->z;
destination->w = source->w;
return (destination);
}
/// Exchange values of two 2D, 3D or 4D vectors.
static procedure vector_2_exchange (vector_2 * vector_a, vector_2 * vector_b) {
exchange_real (& vector_a->x, & vector_b->x);
exchange_real (& vector_a->y, & vector_b->y);
}
static procedure vector_3_exchange (vector_3 * vector_a, vector_3 * vector_b) {
exchange_real (& vector_a->x, & vector_b->x);
exchange_real (& vector_a->y, & vector_b->y);
exchange_real (& vector_a->z, & vector_b->z);
}
static procedure vector_4_exchange (vector_4 * vector_a, vector_4 * vector_b) {
exchange_real (& vector_a->x, & vector_b->x);
exchange_real (& vector_a->y, & vector_b->y);
exchange_real (& vector_a->z, & vector_b->z);
exchange_real (& vector_a->w, & vector_b->w);
}
/// Scale 2D, 3D or 4D vector by scalar value and return address of that vector.
static vector_2 * vector_2_scale (vector_2 * destination, real scale) {
destination->x *= scale;
destination->y *= scale;
return (destination);
}
static vector_3 * vector_3_scale (vector_3 * destination, real scale) {
destination->x *= scale;
destination->y *= scale;
destination->z *= scale;
return (destination);
}
static vector_4 * vector_4_scale (vector_4 * destination, real scale) {
destination->x *= scale;
destination->y *= scale;
destination->z *= scale;
destination->w *= scale;
return (destination);
}
/// Scale 2D, 3D or 4D source vector by scalar value into destination vector and return its address.
static vector_2 * vector_2_scale_to (vector_2 * destination, vector_2 * source, real scale) {
destination->x = source->x * scale;
destination->y = source->y * scale;
return (destination);
}
static vector_3 * vector_3_scale_to (vector_3 * destination, vector_3 * source, real scale) {
destination->x = source->x * scale;
destination->y = source->y * scale;
destination->z = source->z * scale;
return (destination);
}
static vector_4 * vector_4_scale_to (vector_4 * destination, vector_4 * source, real scale) {
destination->x = source->x * scale;
destination->y = source->y * scale;
destination->z = source->z * scale;
destination->w = source->w * scale;
return (destination);
}
/// Add 2D, 3D or 4D source vector onto destination vector and return address of destination vector.
static vector_2 * vector_2_add (vector_2 * destination, vector_2 * source) {
destination->x += source->x;
destination->y += source->y;
return (destination);
}
static vector_3 * vector_3_add (vector_3 * destination, vector_3 * source) {
destination->x += source->x;
destination->y += source->y;
destination->z += source->z;
return (destination);
}
static vector_4 * vector_4_add (vector_4 * destination, vector_4 * source) {
destination->x += source->x;
destination->y += source->y;
destination->z += source->z;
destination->w += source->w;
return (destination);
}
/// Add two 2D, 3D or 4D vectors into destination vector and return address of destination vector.
static vector_2 * vector_2_add_to (vector_2 * destination, vector_2 * vector_a, vector_2 * vector_b) {
destination->x = vector_a->x + vector_b->x;
destination->y = vector_a->y + vector_b->y;
return (destination);
}
static vector_3 * vector_3_add_to (vector_3 * destination, vector_3 * vector_a, vector_3 * vector_b) {
destination->x = vector_a->x + vector_b->x;
destination->y = vector_a->y + vector_b->y;
destination->z = vector_a->z + vector_b->z;
return (destination);
}
static vector_4 * vector_4_add_to (vector_4 * destination, vector_4 * vector_a, vector_4 * vector_b) {
destination->x = vector_a->x + vector_b->x;
destination->y = vector_a->y + vector_b->y;
destination->z = vector_a->z + vector_b->z;
destination->w = vector_a->w + vector_b->w;
return (destination);
}
/// Subtract 2D, 3D or 4D source vector from destination vector and return address of destination vector.
static vector_2 * vector_2_subtract (vector_2 * destination, vector_2 * source) {
destination->x -= source->x;
destination->y -= source->y;
return (destination);
}
static vector_3 * vector_3_subtract (vector_3 * destination, vector_3 * source) {
destination->x -= source->x;
destination->y -= source->y;
destination->z -= source->z;
return (destination);
}
static vector_4 * vector_4_subtract (vector_4 * destination, vector_4 * source) {
destination->x -= source->x;
destination->y -= source->y;
destination->z -= source->z;
destination->w -= source->w;
return (destination);
}
/// Subtract two 2D, 3D or 4D vectors, save values into destination vector and return address of destination vector.
static vector_2 * vector_2_subtract_to (vector_2 * destination, vector_2 * vector_a, vector_2 * vector_b) {
destination->x = vector_a->x - vector_b->x;
destination->y = vector_a->y - vector_b->y;
return (destination);
}
static vector_3 * vector_3_subtract_to (vector_3 * destination, vector_3 * vector_a, vector_3 * vector_b) {
destination->x = vector_a->x - vector_b->x;
destination->y = vector_a->y - vector_b->y;
destination->z = vector_a->z - vector_b->z;
return (destination);
}
static vector_4 * vector_4_subtract_to (vector_4 * destination, vector_4 * vector_a, vector_4 * vector_b) {
destination->x = vector_a->x - vector_b->x;
destination->y = vector_a->y - vector_b->y;
destination->z = vector_a->z - vector_b->z;
destination->w = vector_a->w - vector_b->w;
return (destination);
}
/// Compare if two 2D, 3D or 4D vectors are identical and return boolean value of it.
static boolean vector_2_compare (vector_2 * vector_a, vector_2 * vector_b) {
if ((vector_a->x == vector_b->x) && (vector_a->y == vector_b->y)) {
return (true);
} else {
return (false);
}
}
static boolean vector_3_compare (vector_3 * vector_a, vector_3 * vector_b) {
if ((vector_a->x == vector_b->x) && (vector_a->y == vector_b->y) && (vector_a->z == vector_b->z)) {
return (true);
} else {
return (false);
}
}
static boolean vector_4_compare (vector_4 * vector_a, vector_4 * vector_b) {
if ((vector_a->x == vector_b->x) && (vector_a->y == vector_b->y) && (vector_a->z == vector_b->z) && (vector_a->w == vector_b->w)) {
return (true);
} else {
return (false);
}
}
/// Return dot product of two 2D, 3D or 4D vectors.
static real vector_2_dot_product (vector_2 * vector_a, vector_2 * vector_b) {
return (vector_a->x * vector_b->x + vector_a->y * vector_b->y);
}
static real vector_3_dot_product (vector_3 * vector_a, vector_3 * vector_b) {
return (vector_a->x * vector_b->x + vector_a->y * vector_b->y + vector_a->z * vector_b->z);
}
static real vector_4_dot_product (vector_4 * vector_a, vector_4 * vector_b) {
return (vector_a->x * vector_b->x + vector_a->y * vector_b->y + vector_a->z * vector_b->z + vector_a->w * vector_b->w);
}
/// Return cross product of two 2D vectors.
static real vector_2_cross_product (vector_2 * vector_a, vector_2 * vector_b) {
return (vector_a->x * vector_b->y - vector_a->y * vector_b->x);
}
/// Return cross product of two 3D vectors.
static vector_3 * vector_3_cross_product (vector_3 * destination, vector_3 * source) {
destination->x = destination->y * source->z - destination->z * source->y;
destination->y = destination->z * source->x - destination->x * source->z;
destination->z = destination->x * source->y - destination->y * source->x;
return (destination);
}

164
xrena.h Normal file
View File

@@ -0,0 +1,164 @@
/// __ ___ __ ___ _ __ __ _
/// \ \/ / '__/ _ \ '_ \ / _` |
/// > <| | | __/ | | | (_| |
/// /_/\_\_| \___|_| |_|\__,_|
///
/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic
///
/// xolatile@chud.cyou - xrena - Probably the most minimalistic arena allocator possible, and undoubtedly evil in implementation details.
///
/// This program is free software, free as in freedom and as in free beer, you can redistribute it and/or modify it under the terms of the GNU
/// General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version if you wish...
///
/// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied
/// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License
/// for more details, if you dare, it is a lot of text that nobody wants to read...
/// Description
///
/// Xrena, extremely small header only library serving as arena allocator, with one global variable.In order to use it, include this header file,
/// there's no macro for including implementation (like stb libraries), this is for projects that have only one C source file, and one or more C
/// header files. I'll provide minimal examples below.
/// Maximum size for single memory "allocation", if you're making a parser, you can use as low as 8 or 16, but as soon as you start working with
/// bigger structures, images or models, you need this to be higher value, for example 64 * 1024 * 1024 (loading 4k textures). If you don't
/// understand how to use this macro, turn off your machine and read some books, or alternatively, fuck around until you find out.
#ifndef arena_block_limit
#define arena_block_limit (1024 * 1024)
#endif
/// Structure and global variable definition, you shouldn't ever modify this, functions below cover that task.
static struct {
caliber block_count;
caliber block_limit;
struct {
caliber count;
caliber capacity;
character * buffer;
} * * block_array;
} * arena_memory = null;
/// Warning: Local function! You don't need to use this at all, it's covered by other functions, don't worry about it.
///
/// This function will initialize the state of variable 'arena_memory', or extend it's size once memory is filled.
static procedure arena_begin_or_widen (none) {
caliber current = ++arena_memory->block_count - 1;
arena_memory->block_limit = arena_block_limit;
arena_memory->block_array = reallocate (arena_memory->block_array, arena_memory->block_count * sizeof (* arena_memory->block_array));
arena_memory->block_array [current] = allocate (sizeof (* arena));
arena_memory->block_array [current]->buffer = allocate (arena_block_limit);
arena_memory->block_array [current]->count = 0;
arena_memory->block_array [current]->capacity = arena_block_limit;
}
/// Warning: Local function! You don't need to use this at all, it's covered by other functions, don't worry about it.
///
/// This function will clean all memory pools from variable 'arena_memory', freeing all memory used by the arena allocator.
static procedure arena_clean (none) {
for (caliber index = 0; index < arena_memory->block_count; ++index) {
arena_memory->block_array [index]->buffer = deallocate (arena_memory->block_array [index]->buffer);
arena_memory->block_array [index] = deallocate (arena_memory->block_array [index]);
}
arena_memory->block_array = deallocate (arena_memory->block_array);
arena_memory = deallocate (arena_memory);
}
/// Now, this is finally a function that you want to use. You want to allocate object of some size, just add that size in arena, it'll return
/// you a pointer to that memory location, the same way you'd use 'malloc', and that memory will be zero initialized (unlike 'malloc', just like
/// 'calloc'). You don't ever have to worry about freeing memory, if your program has definite exit routine. Internally, it checks if arena
/// allocator was initialized, if it was, it'll extend it if there's not enough memory and return that pointer, otherwise, it will initialize it
/// and set clean up call at exit.
///
/// Make an array of 60 integers, they'll all be zero.
///
/// integer * my_integers = arena_add (60 * sizeof (my_integers));
static generic * arena_add (caliber size) {
caliber current = arena_memory->block_count - 1;
if (arena == null) {
clean_up (arena_clean);
arena_memory = allocate (sizeof (* arena_memory));
arena_begin_or_widen ();
}
fatal_failure (size > arena_memory->block_limit, "arena_add: Block limit reached.");
if (arena_memory->block_array [current]->count + size > arena_memory->block_array [current]->capacity) {
arena_begin_or_widen ();
}
arena_memory->block_array [current]->count += size;
return ((generic *) & arena_memory->block_array [current]->buffer [arena_memory->block_array [current]->count - size]);
}
/// Add null terminated string to arena memory.
///
/// character * my_token = arena_add_string (parsed_token);
static character * arena_add_string (character * string) {
character * pointer = arena_add (string_length (string) * sizeof (pointer));
string_copy (pointer, string);
return (pointer);
}
/// Add raw memory of certain size to arena memory.
///
/// generic * my_model = arena_add_memory (raw_model_data, size_of_model_data);
static generic * arena_add_memory (generic * memory, caliber size) {
generic * pointer = arena_add (size);
memory_copy (pointer, memory, size);
return (pointer);
}
/// Add file data from certain path, specify file flags (similar to 'open' system call) and set if you want it to be null terminated.
///
/// generic * my_binary_file = arena_add_file ("foo.bin", file_flag_read, false);
/// character * my_text_file = arena_add_file ("foo.txt", file_flag_read, true);
static character * arena_add_file (character * path, integer flag, boolean null_terminate) {
integer file = -1;
caliber size = 0;
character * data = null;
file = file_open (path, flag);
size = file_size (path) + (caliber) null_terminate;
data = arena_add (size);
file_read (file, data, size - (caliber) null_terminate);
file = file_close (file);
return (data);
}
/// Simple utility function that returns how many bytes have been added to arena allocator.
///
/// print ("So far I used %l bytes of memory...\n", arena_usage ());
static caliber arena_usage (none) {
caliber usage = 0;
for (caliber block = 0; block < arena_memory->block_count; ++block) {
usage += arena_memory->block_array [block]->count;
}
return (usage);
}

238
xyntax.h Normal file
View File

@@ -0,0 +1,238 @@
/// _
/// __ ___ _ _ __ | |_ __ ___ __
/// \ \/ / | | | '_ \| __/ _` \ \/ /
/// > <| |_| | | | | || (_| |> <
/// /_/\_\\__, |_| |_|\__\__,_/_/\_\
/// |___/
///
/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic
///
/// xolatile@chud.cyou - xyntax - Tiny, unsafe and somewhat insane unity header for generic syntax definition.
///
/// This program is free software, free as in freedom and as in free beer, you can redistribute it and/or modify it under the terms of the GNU
/// General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version if you wish...
///
/// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied
/// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License
/// for more details, if you dare, it is a lot of text that nobody wants to read...
/// Description
///
/// Xyntax, the most minimal text parser that can deal with syntax highlighting that I could've come up with, and the most generic name for it
/// also, it's rather slow, but if you're creating heavy duty program, you'd use heavy duty library for it. This library has only one header, so
/// it's easy to incorporate it into existing projects. If you want to see how it is used, check out simple examples below, if you want more
/// robust example, check out my other programs, Xarbon and Xighlight.
///
/// For start, you want to include this header file, there's no macro for including implementation (like stb libraries), this is for projects
/// that have only one C source file, and one or more C header files. Then make global or local variable 'syntax_structure * whatever_syntax'
/// defined below, initialize it, define the rules, then in main loop select rule, do whatever you wanted, then deinitialize the structure. It's
/// simple, I'll provide minimal examples below.
/// Structure for single syntax definition (array of rules), if you want to parse multiple languages simultaneously, use an array.
///
/// syntax_structure * syntax = null;
typedef struct {
natural count; /// Count of syntax rules used, maximum is set with limit below, if limit is 0, it'll allocate it dynamically.
natural limit; /// Preallocation limit for syntax rules, hardcode it if you don't want this to allocate memory dynamically.
boolean * enrange; /// Enrange rule, set to true if you want to begin matching by any character from 'begin' string below.
boolean * derange; /// Derange rule, set to true if you want to end matching by any character from 'end' string below.
character * * begin; /// String containing set of characters or full string for start of matching, correlating to 'enrange' above.
character * * end; /// String containing set of characters or full string for end of matching, correlating to 'derange' above.
character * escape; /// Escape character, which will skip one cycle in selection loop, then continue matching for 'end' string.
natural * colour; /// Colour for matched array of characters, can be anything, enumerated, literal, hardcoded...
natural * effect; /// Effect for matched array of characters, can be anything, enumerated, literal, hardcoded...
} syntax_structure;
/// Initialize syntax structure before calling other functions that take it as an argument, set 'limit' to 0 if you want dynamic array of rules.
///
/// syntax = syntax_initialize (0);
static syntax_structure * syntax_initialize (natural limit) {
syntax_structure * syntax = allocate (sizeof (* syntax));
syntax->limit = limit;
if (limit != 0) {
syntax->enrange = allocate (syntax->limit * sizeof (* syntax->enrange));
syntax->derange = allocate (syntax->limit * sizeof (* syntax->derange));
syntax->begin = allocate (syntax->limit * sizeof (* syntax->begin));
syntax->end = allocate (syntax->limit * sizeof (* syntax->end));
syntax->escape = allocate (syntax->limit * sizeof (* syntax->escape));
syntax->colour = allocate (syntax->limit * sizeof (* syntax->colour));
syntax->effect = allocate (syntax->limit * sizeof (* syntax->effect));
}
return (syntax);
}
/// Deinitialize syntax structure after using it, in order to avoid memory leaks.
///
/// syntax = syntax_deinitialize (syntax);
static syntax_structure * syntax_deinitialize (syntax_structure * syntax) {
for (natural index = 0; index < syntax->count; ++index) {
syntax->begin [index] = deallocate (syntax->begin [index]);
syntax->end [index] = deallocate (syntax->end [index]);
}
syntax->enrange = deallocate (syntax->enrange);
syntax->derange = deallocate (syntax->derange);
syntax->begin = deallocate (syntax->begin);
syntax->end = deallocate (syntax->end);
syntax->escape = deallocate (syntax->escape);
syntax->colour = deallocate (syntax->colour);
syntax->effect = deallocate (syntax->effect);
return (deallocate (syntax));
}
/// Define single syntax rule, which will be added into array part of syntax structure, return value is index into that array.
///
/// Take a look into few simple examples of defining some simplified rules of C programming language.
/// Two examples below show how to define multiline comments and strings, since these have priority, both enrange and derange are false.
///
/// syntax_define (syntax, false, false, "/*", "*/", '\\', 1, 0);
/// syntax_define (syntax, false, false, "\"", "\"", '\\', 2, 0);
///
/// Now we're defining syntax rule for one keyword, static, notice that end string contaings separator characters because derange is true.
///
/// syntax_define (syntax, false, true, "static", "()[]{}.,:;<=>+*-/%!&~^?| \t\r\n", '\0', 3, 0);
///
/// You can define brackets and operator characters separately, or if you want to, you can define some of them separately again.
///
/// syntax_define (syntax, true, false, "()[]{}", "", '\0', 4, 0);
/// syntax_define (syntax, true, false, ".,:;<=>+*-/%!&~^?|", "", '\0', 5, 0);
///
/// And lastly, we can define number selection like this below, by setting both enrange and derange as false.
///
/// syntax_define (syntax, true, true, "0123456789", "()[]{}.,:;<=>+*-/%!&~^?| \t\r\n", '\0', 6, 0);
///
/// I hope this is pretty clear, if you want to select a number, you start by matching any of digits provided above, and you end matching that
/// number by any character from 'end' string, if you want to support floating point numbers, you'd exclude '.' character, or alternatively add
/// letters f, u, l and whatever else your language supports (like in C/C++). However, this approach is too weak for detecting syntax errors,
/// you shouldn't use this library for robust linter or parser.
static natural syntax_define (syntax_structure * syntax, boolean enrange, boolean derange, character * begin, character * end, character escape,
natural colour, natural effect) {
++syntax->count;
natural current = syntax->count - 1;
fatal_failure (begin == null, "syntax_define: Begin string is null pointer.");
fatal_failure (end == null, "syntax_define: End string is null pointer.");
fatal_failure (syntax->count >= syntax->limit, "syntax_define: Reached the hardcoded limit.");
if (syntax->limit == 0) {
syntax->enrange = reallocate (syntax->enrange, syntax->count * sizeof (* syntax->enrange));
syntax->derange = reallocate (syntax->derange, syntax->count * sizeof (* syntax->derange));
syntax->begin = reallocate (syntax->begin, syntax->count * sizeof (* syntax->begin));
syntax->end = reallocate (syntax->end, syntax->count * sizeof (* syntax->end));
syntax->escape = reallocate (syntax->escape, syntax->count * sizeof (* syntax->escape));
syntax->colour = reallocate (syntax->colour, syntax->count * sizeof (* syntax->colour));
syntax->effect = reallocate (syntax->effect, syntax->count * sizeof (* syntax->effect));
}
syntax->begin [current] = allocate ((string_length (begin) + 1) * sizeof (* * syntax->begin));
syntax->end [current] = allocate ((string_length (end) + 1) * sizeof (* * syntax->end));
syntax->enrange [current] = enrange;
syntax->derange [current] = derange;
syntax->escape [current] = escape;
syntax->colour [current] = colour;
syntax->effect [current] = effect;
string_copy (syntax->begin [current], begin);
string_copy (syntax->end [current], end);
return (current);
}
/// After all syntax definitions have been defined, call this function inside your main loop, return value is index of selected rule.
///
/// Now, imagine that 'buffer' is file you've loaded into memory, you have declared natural numbers 'offset', 'length' and 'select', and you've
/// properly initialized syntax structure 'syntax', defined its rules for wanted language(s), simple main loop would look like this:
///
/// for (offset = 0; buffer [offset] != '\0'; offset += length) {
/// /// Notice that we're not incrementing 'offset', we're increasing it by 'length'.
/// select = syntax_select (syntax, & buffer [offset], & length);
/// if (select >= syntax->count) {
/// /// Syntax definition is incomplete, unknown sequence has been detected, either print nothing, or print default.
/// } else {
/// /// Print string of 'length', at '& buffer [offset]', using 'syntax->colour [select]' and 'syntax->effect [select]'.
/// /// Strings here aren't null terminated, you want to print sized string.
/// }
/// }
static natural syntax_select (syntax_structure * syntax, character * string, natural * length) {
natural offset = 0;
natural subset = 0;
natural select = 0;
for (; select != syntax->count; ++select) {
caliber begin_length = string_length (syntax->begin [select]);
if (syntax->enrange [select] == false) {
if (syntax->derange [select] == false) {
if (string_compare_limit (string, syntax->begin [select], begin_length) == true) {
break;
}
} else {
if ((string_compare_limit (string, syntax->begin [select], begin_length) == true)
&& (character_compare_array (string [offset + begin_length], syntax->end [select]) == true)) {
break;
}
}
} else {
for (subset = 0; subset != begin_length; ++subset) {
if (string [offset] == syntax->begin [select] [subset]) {
goto selected;
}
}
}
}
selected:
if (select >= syntax->count) {
* length = 1;
return (syntax->count);
}
caliber end_length = string_length (syntax->end [select]);
for (offset = 1; string [offset - 1] != character_null; ++offset) {
if (string [offset] == syntax->escape [select]) {
++offset;
continue;
}
if (syntax->derange [select] == true) {
subset = 0;
if (end_length == 0) {
break;
} do {
if (string [offset] == syntax->end [select] [subset]) {
* length = offset;
goto finished;
}
} while (++subset != end_length);
} else {
if (end_length != 0) {
if (string_compare_limit (& string [offset], syntax->end [select], end_length)) {
* length = offset + end_length;
return (select);
}
} else {
* length = 1;
return (select);
}
}
}
finished:
return (select);
}