skeleton for the sterling runtime and base compiler
This commit is contained in:
commit
6aeb937a93
31
Makefile
Normal file
31
Makefile
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
NAME := Sterling
|
||||||
|
|
||||||
|
SRC := $(wildcard source/*.c)
|
||||||
|
|
||||||
|
OBJ := $(SRC:source/%.c=obj/%.o)
|
||||||
|
|
||||||
|
CC := gcc
|
||||||
|
CFLAG := -ggdb -Wall -Wextra -Werror -Wpedantic -I include -O0 -std=c99
|
||||||
|
LFLAG :=
|
||||||
|
|
||||||
|
all: $(NAME)
|
||||||
|
|
||||||
|
obj/%.o : source/%.c | makedir
|
||||||
|
$(CC) $(CFLAG) -c $< -o $@
|
||||||
|
|
||||||
|
$(NAME): $(OBJ)
|
||||||
|
$(CC) $(OBJ) $(LFLAG) -o build/$(NAME)
|
||||||
|
|
||||||
|
makedir:
|
||||||
|
mkdir -p obj
|
||||||
|
mkdir -p build
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf obj/
|
||||||
|
|
||||||
|
fclean: clean
|
||||||
|
rm -rf build/
|
||||||
|
|
||||||
|
re: fclean all
|
||||||
|
|
||||||
|
.PHONY: all $(NAME) clean fclean makedir
|
||||||
BIN
build/Sterling.exe
Normal file
BIN
build/Sterling.exe
Normal file
Binary file not shown.
941
include/stb_c_lexer.h
Normal file
941
include/stb_c_lexer.h
Normal file
@ -0,0 +1,941 @@
|
|||||||
|
// stb_c_lexer.h - v0.12 - public domain Sean Barrett 2013
|
||||||
|
// lexer for making little C-like languages with recursive-descent parsers
|
||||||
|
//
|
||||||
|
// This file provides both the interface and the implementation.
|
||||||
|
// To instantiate the implementation,
|
||||||
|
// #define STB_C_LEXER_IMPLEMENTATION
|
||||||
|
// in *ONE* source file, before #including this file.
|
||||||
|
//
|
||||||
|
// The default configuration is fairly close to a C lexer, although
|
||||||
|
// suffixes on integer constants are not handled (you can override this).
|
||||||
|
//
|
||||||
|
// History:
|
||||||
|
// 0.12 fix compilation bug for NUL support; better support separate inclusion
|
||||||
|
// 0.11 fix clang static analysis warning
|
||||||
|
// 0.10 fix warnings
|
||||||
|
// 0.09 hex floats, no-stdlib fixes
|
||||||
|
// 0.08 fix bad pointer comparison
|
||||||
|
// 0.07 fix mishandling of hexadecimal constants parsed by strtol
|
||||||
|
// 0.06 fix missing next character after ending quote mark (Andreas Fredriksson)
|
||||||
|
// 0.05 refixed get_location because github version had lost the fix
|
||||||
|
// 0.04 fix octal parsing bug
|
||||||
|
// 0.03 added STB_C_LEX_DISCARD_PREPROCESSOR option
|
||||||
|
// refactor API to simplify (only one struct instead of two)
|
||||||
|
// change literal enum names to have 'lit' at the end
|
||||||
|
// 0.02 first public release
|
||||||
|
//
|
||||||
|
// Status:
|
||||||
|
// - haven't tested compiling as C++
|
||||||
|
// - haven't tested the float parsing path
|
||||||
|
// - haven't tested the non-default-config paths (e.g. non-stdlib)
|
||||||
|
// - only tested default-config paths by eyeballing output of self-parse
|
||||||
|
//
|
||||||
|
// - haven't implemented multiline strings
|
||||||
|
// - haven't implemented octal/hex character constants
|
||||||
|
// - haven't implemented support for unicode CLEX_char
|
||||||
|
// - need to expand error reporting so you don't just get "CLEX_parse_error"
|
||||||
|
//
|
||||||
|
// Contributors:
|
||||||
|
// Arpad Goretity (bugfix)
|
||||||
|
// Alan Hickman (hex floats)
|
||||||
|
// github:mundusnine (bugfix)
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
//
|
||||||
|
// See end of file for license information.
|
||||||
|
|
||||||
|
#ifdef STB_C_LEXER_IMPLEMENTATION
|
||||||
|
#ifndef STB_C_LEXER_DEFINITIONS
|
||||||
|
// to change the default parsing rules, copy the following lines
|
||||||
|
// into your C/C++ file *before* including this, and then replace
|
||||||
|
// the Y's with N's for the ones you don't want. This needs to be
|
||||||
|
// set to the same values for every place in your program where
|
||||||
|
// stb_c_lexer.h is included.
|
||||||
|
// --BEGIN--
|
||||||
|
|
||||||
|
#if defined(Y) || defined(N)
|
||||||
|
#error "Can only use stb_c_lexer in contexts where the preprocessor symbols 'Y' and 'N' are not defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STB_C_LEX_C_DECIMAL_INTS Y // "0|[1-9][0-9]*" CLEX_intlit
|
||||||
|
#define STB_C_LEX_C_HEX_INTS Y // "0x[0-9a-fA-F]+" CLEX_intlit
|
||||||
|
#define STB_C_LEX_C_OCTAL_INTS Y // "[0-7]+" CLEX_intlit
|
||||||
|
#define STB_C_LEX_C_DECIMAL_FLOATS Y // "[0-9]*(.[0-9]*([eE][-+]?[0-9]+)?) CLEX_floatlit
|
||||||
|
#define STB_C_LEX_C99_HEX_FLOATS N // "0x{hex}+(.{hex}*)?[pP][-+]?{hex}+ CLEX_floatlit
|
||||||
|
#define STB_C_LEX_C_IDENTIFIERS Y // "[_a-zA-Z][_a-zA-Z0-9]*" CLEX_id
|
||||||
|
#define STB_C_LEX_C_DQ_STRINGS Y // double-quote-delimited strings with escapes CLEX_dqstring
|
||||||
|
#define STB_C_LEX_C_SQ_STRINGS N // single-quote-delimited strings with escapes CLEX_ssstring
|
||||||
|
#define STB_C_LEX_C_CHARS Y // single-quote-delimited character with escape CLEX_charlits
|
||||||
|
#define STB_C_LEX_C_COMMENTS Y // "/* comment */"
|
||||||
|
#define STB_C_LEX_CPP_COMMENTS Y // "// comment to end of line\n"
|
||||||
|
#define STB_C_LEX_C_COMPARISONS Y // "==" CLEX_eq "!=" CLEX_noteq "<=" CLEX_lesseq ">=" CLEX_greatereq
|
||||||
|
#define STB_C_LEX_C_LOGICAL Y // "&&" CLEX_andand "||" CLEX_oror
|
||||||
|
#define STB_C_LEX_C_SHIFTS Y // "<<" CLEX_shl ">>" CLEX_shr
|
||||||
|
#define STB_C_LEX_C_INCREMENTS Y // "++" CLEX_plusplus "--" CLEX_minusminus
|
||||||
|
#define STB_C_LEX_C_ARROW Y // "->" CLEX_arrow
|
||||||
|
#define STB_C_LEX_EQUAL_ARROW N // "=>" CLEX_eqarrow
|
||||||
|
#define STB_C_LEX_C_BITWISEEQ Y // "&=" CLEX_andeq "|=" CLEX_oreq "^=" CLEX_xoreq
|
||||||
|
#define STB_C_LEX_C_ARITHEQ Y // "+=" CLEX_pluseq "-=" CLEX_minuseq
|
||||||
|
// "*=" CLEX_muleq "/=" CLEX_diveq "%=" CLEX_modeq
|
||||||
|
// if both STB_C_LEX_SHIFTS & STB_C_LEX_ARITHEQ:
|
||||||
|
// "<<=" CLEX_shleq ">>=" CLEX_shreq
|
||||||
|
|
||||||
|
#define STB_C_LEX_PARSE_SUFFIXES N // letters after numbers are parsed as part of those numbers, and must be in suffix list below
|
||||||
|
#define STB_C_LEX_DECIMAL_SUFFIXES "" // decimal integer suffixes e.g. "uUlL" -- these are returned as-is in string storage
|
||||||
|
#define STB_C_LEX_HEX_SUFFIXES "" // e.g. "uUlL"
|
||||||
|
#define STB_C_LEX_OCTAL_SUFFIXES "" // e.g. "uUlL"
|
||||||
|
#define STB_C_LEX_FLOAT_SUFFIXES "" //
|
||||||
|
|
||||||
|
#define STB_C_LEX_0_IS_EOF N // if Y, ends parsing at '\0'; if N, returns '\0' as token
|
||||||
|
#define STB_C_LEX_INTEGERS_AS_DOUBLES N // parses integers as doubles so they can be larger than 'int', but only if STB_C_LEX_STDLIB==N
|
||||||
|
#define STB_C_LEX_MULTILINE_DSTRINGS N // allow newlines in double-quoted strings
|
||||||
|
#define STB_C_LEX_MULTILINE_SSTRINGS N // allow newlines in single-quoted strings
|
||||||
|
#define STB_C_LEX_USE_STDLIB Y // use strtod,strtol for parsing #s; otherwise inaccurate hack
|
||||||
|
#define STB_C_LEX_DOLLAR_IDENTIFIER Y // allow $ as an identifier character
|
||||||
|
#define STB_C_LEX_FLOAT_NO_DECIMAL Y // allow floats that have no decimal point if they have an exponent
|
||||||
|
|
||||||
|
#define STB_C_LEX_DEFINE_ALL_TOKEN_NAMES N // if Y, all CLEX_ token names are defined, even if never returned
|
||||||
|
// leaving it as N should help you catch config bugs
|
||||||
|
|
||||||
|
#define STB_C_LEX_DISCARD_PREPROCESSOR Y // discard C-preprocessor directives (e.g. after prepocess
|
||||||
|
// still have #line, #pragma, etc)
|
||||||
|
|
||||||
|
//#define STB_C_LEX_ISWHITE(str) ... // return length in bytes of whitespace characters if first char is whitespace
|
||||||
|
|
||||||
|
#define STB_C_LEXER_DEFINITIONS // This line prevents the header file from replacing your definitions
|
||||||
|
// --END--
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef INCLUDE_STB_C_LEXER_H
|
||||||
|
#define INCLUDE_STB_C_LEXER_H
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
// lexer variables
|
||||||
|
char *input_stream;
|
||||||
|
char *eof;
|
||||||
|
char *parse_point;
|
||||||
|
char *string_storage;
|
||||||
|
int string_storage_len;
|
||||||
|
|
||||||
|
// lexer parse location for error messages
|
||||||
|
char *where_firstchar;
|
||||||
|
char *where_lastchar;
|
||||||
|
|
||||||
|
// lexer token variables
|
||||||
|
long token;
|
||||||
|
double real_number;
|
||||||
|
long int_number;
|
||||||
|
char *string;
|
||||||
|
int string_len;
|
||||||
|
} stb_lexer;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int line_number;
|
||||||
|
int line_offset;
|
||||||
|
} stb_lex_location;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern void stb_c_lexer_init(stb_lexer *lexer, const char *input_stream, const char *input_stream_end, char *string_store, int store_length);
|
||||||
|
// this function initialize the 'lexer' structure
|
||||||
|
// Input:
|
||||||
|
// - input_stream points to the file to parse, loaded into memory
|
||||||
|
// - input_stream_end points to the end of the file, or NULL if you use 0-for-EOF
|
||||||
|
// - string_store is storage the lexer can use for storing parsed strings and identifiers
|
||||||
|
// - store_length is the length of that storage
|
||||||
|
|
||||||
|
extern int stb_c_lexer_get_token(stb_lexer *lexer);
|
||||||
|
// this function returns non-zero if a token is parsed, or 0 if at EOF
|
||||||
|
// Output:
|
||||||
|
// - lexer->token is the token ID, which is unicode code point for a single-char token, < 0 for a multichar or eof or error
|
||||||
|
// - lexer->real_number is a double constant value for CLEX_floatlit, or CLEX_intlit if STB_C_LEX_INTEGERS_AS_DOUBLES
|
||||||
|
// - lexer->int_number is an integer constant for CLEX_intlit if !STB_C_LEX_INTEGERS_AS_DOUBLES, or character for CLEX_charlit
|
||||||
|
// - lexer->string is a 0-terminated string for CLEX_dqstring or CLEX_sqstring or CLEX_identifier
|
||||||
|
// - lexer->string_len is the byte length of lexer->string
|
||||||
|
|
||||||
|
extern void stb_c_lexer_get_location(const stb_lexer *lexer, const char *where, stb_lex_location *loc);
|
||||||
|
// this inefficient function returns the line number and character offset of a
|
||||||
|
// given location in the file as returned by stb_lex_token. Because it's inefficient,
|
||||||
|
// you should only call it for errors, not for every token.
|
||||||
|
// For error messages of invalid tokens, you typically want the location of the start
|
||||||
|
// of the token (which caused the token to be invalid). For bugs involving legit
|
||||||
|
// tokens, you can report the first or the range.
|
||||||
|
// Output:
|
||||||
|
// - loc->line_number is the line number in the file, counting from 1, of the location
|
||||||
|
// - loc->line_offset is the char-offset in the line, counting from 0, of the location
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CLEX_eof = 256,
|
||||||
|
CLEX_parse_error,
|
||||||
|
CLEX_intlit ,
|
||||||
|
CLEX_floatlit ,
|
||||||
|
CLEX_id ,
|
||||||
|
CLEX_dqstring ,
|
||||||
|
CLEX_sqstring ,
|
||||||
|
CLEX_charlit ,
|
||||||
|
CLEX_eq ,
|
||||||
|
CLEX_noteq ,
|
||||||
|
CLEX_lesseq ,
|
||||||
|
CLEX_greatereq ,
|
||||||
|
CLEX_andand ,
|
||||||
|
CLEX_oror ,
|
||||||
|
CLEX_shl ,
|
||||||
|
CLEX_shr ,
|
||||||
|
CLEX_plusplus ,
|
||||||
|
CLEX_minusminus ,
|
||||||
|
CLEX_pluseq ,
|
||||||
|
CLEX_minuseq ,
|
||||||
|
CLEX_muleq ,
|
||||||
|
CLEX_diveq ,
|
||||||
|
CLEX_modeq ,
|
||||||
|
CLEX_andeq ,
|
||||||
|
CLEX_oreq ,
|
||||||
|
CLEX_xoreq ,
|
||||||
|
CLEX_arrow ,
|
||||||
|
CLEX_eqarrow ,
|
||||||
|
CLEX_shleq, CLEX_shreq,
|
||||||
|
|
||||||
|
CLEX_first_unused_token
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif // INCLUDE_STB_C_LEXER_H
|
||||||
|
|
||||||
|
#ifdef STB_C_LEXER_IMPLEMENTATION
|
||||||
|
|
||||||
|
// Hacky definitions so we can easily #if on them
|
||||||
|
#define Y(x) 1
|
||||||
|
#define N(x) 0
|
||||||
|
|
||||||
|
#if STB_C_LEX_INTEGERS_AS_DOUBLES(x)
|
||||||
|
typedef double stb__clex_int;
|
||||||
|
#define intfield real_number
|
||||||
|
#define STB__clex_int_as_double
|
||||||
|
#else
|
||||||
|
typedef long stb__clex_int;
|
||||||
|
#define intfield int_number
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Convert these config options to simple conditional #defines so we can more
|
||||||
|
// easily test them once we've change the meaning of Y/N
|
||||||
|
|
||||||
|
#if STB_C_LEX_PARSE_SUFFIXES(x)
|
||||||
|
#define STB__clex_parse_suffixes
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if STB_C_LEX_C99_HEX_FLOATS(x)
|
||||||
|
#define STB__clex_hex_floats
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if STB_C_LEX_C_HEX_INTS(x)
|
||||||
|
#define STB__clex_hex_ints
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if STB_C_LEX_C_DECIMAL_INTS(x)
|
||||||
|
#define STB__clex_decimal_ints
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if STB_C_LEX_C_OCTAL_INTS(x)
|
||||||
|
#define STB__clex_octal_ints
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if STB_C_LEX_C_DECIMAL_FLOATS(x)
|
||||||
|
#define STB__clex_decimal_floats
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if STB_C_LEX_DISCARD_PREPROCESSOR(x)
|
||||||
|
#define STB__clex_discard_preprocessor
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if STB_C_LEX_USE_STDLIB(x) && (!defined(STB__clex_hex_floats) || __STDC_VERSION__ >= 199901L)
|
||||||
|
#define STB__CLEX_use_stdlib
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Now for the rest of the file we'll use the basic definition where
|
||||||
|
// where Y expands to its contents and N expands to nothing
|
||||||
|
#undef Y
|
||||||
|
#define Y(a) a
|
||||||
|
#undef N
|
||||||
|
#define N(a)
|
||||||
|
|
||||||
|
// API function
|
||||||
|
void stb_c_lexer_init(stb_lexer *lexer, const char *input_stream, const char *input_stream_end, char *string_store, int store_length)
|
||||||
|
{
|
||||||
|
lexer->input_stream = (char *) input_stream;
|
||||||
|
lexer->eof = (char *) input_stream_end;
|
||||||
|
lexer->parse_point = (char *) input_stream;
|
||||||
|
lexer->string_storage = string_store;
|
||||||
|
lexer->string_storage_len = store_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// API function
|
||||||
|
void stb_c_lexer_get_location(const stb_lexer *lexer, const char *where, stb_lex_location *loc)
|
||||||
|
{
|
||||||
|
char *p = lexer->input_stream;
|
||||||
|
int line_number = 1;
|
||||||
|
int char_offset = 0;
|
||||||
|
while (*p && p < where) {
|
||||||
|
if (*p == '\n' || *p == '\r') {
|
||||||
|
p += (p[0]+p[1] == '\r'+'\n' ? 2 : 1); // skip newline
|
||||||
|
line_number += 1;
|
||||||
|
char_offset = 0;
|
||||||
|
} else {
|
||||||
|
++p;
|
||||||
|
++char_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loc->line_number = line_number;
|
||||||
|
loc->line_offset = char_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// main helper function for returning a parsed token
|
||||||
|
static int stb__clex_token(stb_lexer *lexer, int token, char *start, char *end)
|
||||||
|
{
|
||||||
|
lexer->token = token;
|
||||||
|
lexer->where_firstchar = start;
|
||||||
|
lexer->where_lastchar = end;
|
||||||
|
lexer->parse_point = end+1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function for returning eof
|
||||||
|
static int stb__clex_eof(stb_lexer *lexer)
|
||||||
|
{
|
||||||
|
lexer->token = CLEX_eof;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stb__clex_iswhite(int x)
|
||||||
|
{
|
||||||
|
return x == ' ' || x == '\t' || x == '\r' || x == '\n' || x == '\f';
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *stb__strchr(const char *str, int ch)
|
||||||
|
{
|
||||||
|
for (; *str; ++str)
|
||||||
|
if (*str == ch)
|
||||||
|
return str;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse suffixes at the end of a number
|
||||||
|
static int stb__clex_parse_suffixes(stb_lexer *lexer, long tokenid, char *start, char *cur, const char *suffixes)
|
||||||
|
{
|
||||||
|
#ifdef STB__clex_parse_suffixes
|
||||||
|
lexer->string = lexer->string_storage;
|
||||||
|
lexer->string_len = 0;
|
||||||
|
|
||||||
|
while ((*cur >= 'a' && *cur <= 'z') || (*cur >= 'A' && *cur <= 'Z')) {
|
||||||
|
if (stb__strchr(suffixes, *cur) == 0)
|
||||||
|
return stb__clex_token(lexer, CLEX_parse_error, start, cur);
|
||||||
|
if (lexer->string_len+1 >= lexer->string_storage_len)
|
||||||
|
return stb__clex_token(lexer, CLEX_parse_error, start, cur);
|
||||||
|
lexer->string[lexer->string_len++] = *cur++;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
suffixes = suffixes; // attempt to suppress warnings
|
||||||
|
#endif
|
||||||
|
return stb__clex_token(lexer, tokenid, start, cur-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef STB__CLEX_use_stdlib
|
||||||
|
static double stb__clex_pow(double base, unsigned int exponent)
|
||||||
|
{
|
||||||
|
double value=1;
|
||||||
|
for ( ; exponent; exponent >>= 1) {
|
||||||
|
if (exponent & 1)
|
||||||
|
value *= base;
|
||||||
|
base *= base;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double stb__clex_parse_float(char *p, char **q)
|
||||||
|
{
|
||||||
|
char *s = p;
|
||||||
|
double value=0;
|
||||||
|
int base=10;
|
||||||
|
int exponent=0;
|
||||||
|
|
||||||
|
#ifdef STB__clex_hex_floats
|
||||||
|
if (*p == '0') {
|
||||||
|
if (p[1] == 'x' || p[1] == 'X') {
|
||||||
|
base=16;
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (*p >= '0' && *p <= '9')
|
||||||
|
value = value*base + (*p++ - '0');
|
||||||
|
#ifdef STB__clex_hex_floats
|
||||||
|
else if (base == 16 && *p >= 'a' && *p <= 'f')
|
||||||
|
value = value*base + 10 + (*p++ - 'a');
|
||||||
|
else if (base == 16 && *p >= 'A' && *p <= 'F')
|
||||||
|
value = value*base + 10 + (*p++ - 'A');
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*p == '.') {
|
||||||
|
double pow, addend = 0;
|
||||||
|
++p;
|
||||||
|
for (pow=1; ; pow*=base) {
|
||||||
|
if (*p >= '0' && *p <= '9')
|
||||||
|
addend = addend*base + (*p++ - '0');
|
||||||
|
#ifdef STB__clex_hex_floats
|
||||||
|
else if (base == 16 && *p >= 'a' && *p <= 'f')
|
||||||
|
addend = addend*base + 10 + (*p++ - 'a');
|
||||||
|
else if (base == 16 && *p >= 'A' && *p <= 'F')
|
||||||
|
addend = addend*base + 10 + (*p++ - 'A');
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value += addend / pow;
|
||||||
|
}
|
||||||
|
#ifdef STB__clex_hex_floats
|
||||||
|
if (base == 16) {
|
||||||
|
// exponent required for hex float literal
|
||||||
|
if (*p != 'p' && *p != 'P') {
|
||||||
|
*q = s;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
exponent = 1;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
exponent = (*p == 'e' || *p == 'E');
|
||||||
|
|
||||||
|
if (exponent) {
|
||||||
|
int sign = p[1] == '-';
|
||||||
|
unsigned int exponent=0;
|
||||||
|
double power=1;
|
||||||
|
++p;
|
||||||
|
if (*p == '-' || *p == '+')
|
||||||
|
++p;
|
||||||
|
while (*p >= '0' && *p <= '9')
|
||||||
|
exponent = exponent*10 + (*p++ - '0');
|
||||||
|
|
||||||
|
#ifdef STB__clex_hex_floats
|
||||||
|
if (base == 16)
|
||||||
|
power = stb__clex_pow(2, exponent);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
power = stb__clex_pow(10, exponent);
|
||||||
|
if (sign)
|
||||||
|
value /= power;
|
||||||
|
else
|
||||||
|
value *= power;
|
||||||
|
}
|
||||||
|
*q = p;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int stb__clex_parse_char(char *p, char **q)
|
||||||
|
{
|
||||||
|
if (*p == '\\') {
|
||||||
|
*q = p+2; // tentatively guess we'll parse two characters
|
||||||
|
switch(p[1]) {
|
||||||
|
case '\\': return '\\';
|
||||||
|
case '\'': return '\'';
|
||||||
|
case '"': return '"';
|
||||||
|
case 't': return '\t';
|
||||||
|
case 'f': return '\f';
|
||||||
|
case 'n': return '\n';
|
||||||
|
case 'r': return '\r';
|
||||||
|
case '0': return '\0'; // @TODO ocatal constants
|
||||||
|
case 'x': case 'X': return -1; // @TODO hex constants
|
||||||
|
case 'u': return -1; // @TODO unicode constants
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*q = p+1;
|
||||||
|
return (unsigned char) *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stb__clex_parse_string(stb_lexer *lexer, char *p, int type)
|
||||||
|
{
|
||||||
|
char *start = p;
|
||||||
|
char delim = *p++; // grab the " or ' for later matching
|
||||||
|
char *out = lexer->string_storage;
|
||||||
|
char *outend = lexer->string_storage + lexer->string_storage_len;
|
||||||
|
while (*p != delim) {
|
||||||
|
int n;
|
||||||
|
if (*p == '\\') {
|
||||||
|
char *q;
|
||||||
|
n = stb__clex_parse_char(p, &q);
|
||||||
|
if (n < 0)
|
||||||
|
return stb__clex_token(lexer, CLEX_parse_error, start, q);
|
||||||
|
p = q;
|
||||||
|
} else {
|
||||||
|
// @OPTIMIZE: could speed this up by looping-while-not-backslash
|
||||||
|
n = (unsigned char) *p++;
|
||||||
|
}
|
||||||
|
if (out+1 > outend)
|
||||||
|
return stb__clex_token(lexer, CLEX_parse_error, start, p);
|
||||||
|
// @TODO expand unicode escapes to UTF8
|
||||||
|
*out++ = (char) n;
|
||||||
|
}
|
||||||
|
*out = 0;
|
||||||
|
lexer->string = lexer->string_storage;
|
||||||
|
lexer->string_len = (int) (out - lexer->string_storage);
|
||||||
|
return stb__clex_token(lexer, type, start, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
int stb_c_lexer_get_token(stb_lexer *lexer)
|
||||||
|
{
|
||||||
|
char *p = lexer->parse_point;
|
||||||
|
|
||||||
|
// skip whitespace and comments
|
||||||
|
for (;;) {
|
||||||
|
#ifdef STB_C_LEX_ISWHITE
|
||||||
|
while (p != lexer->stream_end) {
|
||||||
|
int n;
|
||||||
|
n = STB_C_LEX_ISWHITE(p);
|
||||||
|
if (n == 0) break;
|
||||||
|
if (lexer->eof && lexer->eof - lexer->parse_point < n)
|
||||||
|
return stb__clex_token(tok, CLEX_parse_error, p,lexer->eof-1);
|
||||||
|
p += n;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
while (p != lexer->eof && stb__clex_iswhite(*p))
|
||||||
|
++p;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STB_C_LEX_CPP_COMMENTS(
|
||||||
|
if (p != lexer->eof && p[0] == '/' && p[1] == '/') {
|
||||||
|
while (p != lexer->eof && *p != '\r' && *p != '\n')
|
||||||
|
++p;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
STB_C_LEX_C_COMMENTS(
|
||||||
|
if (p != lexer->eof && p[0] == '/' && p[1] == '*') {
|
||||||
|
char *start = p;
|
||||||
|
p += 2;
|
||||||
|
while (p != lexer->eof && (p[0] != '*' || p[1] != '/'))
|
||||||
|
++p;
|
||||||
|
if (p == lexer->eof)
|
||||||
|
return stb__clex_token(lexer, CLEX_parse_error, start, p-1);
|
||||||
|
p += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
#ifdef STB__clex_discard_preprocessor
|
||||||
|
// @TODO this discards everything after a '#', regardless
|
||||||
|
// of where in the line the # is, rather than requiring it
|
||||||
|
// be at the start. (because this parser doesn't otherwise
|
||||||
|
// check for line breaks!)
|
||||||
|
if (p != lexer->eof && p[0] == '#') {
|
||||||
|
while (p != lexer->eof && *p != '\r' && *p != '\n')
|
||||||
|
++p;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p == lexer->eof)
|
||||||
|
return stb__clex_eof(lexer);
|
||||||
|
|
||||||
|
switch (*p) {
|
||||||
|
default:
|
||||||
|
if ( (*p >= 'a' && *p <= 'z')
|
||||||
|
|| (*p >= 'A' && *p <= 'Z')
|
||||||
|
|| *p == '_' || (unsigned char) *p >= 128 // >= 128 is UTF8 char
|
||||||
|
STB_C_LEX_DOLLAR_IDENTIFIER( || *p == '$' ) )
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
lexer->string = lexer->string_storage;
|
||||||
|
do {
|
||||||
|
if (n+1 >= lexer->string_storage_len)
|
||||||
|
return stb__clex_token(lexer, CLEX_parse_error, p, p+n);
|
||||||
|
lexer->string[n] = p[n];
|
||||||
|
++n;
|
||||||
|
} while (
|
||||||
|
(p[n] >= 'a' && p[n] <= 'z')
|
||||||
|
|| (p[n] >= 'A' && p[n] <= 'Z')
|
||||||
|
|| (p[n] >= '0' && p[n] <= '9') // allow digits in middle of identifier
|
||||||
|
|| p[n] == '_' || (unsigned char) p[n] >= 128
|
||||||
|
STB_C_LEX_DOLLAR_IDENTIFIER( || p[n] == '$' )
|
||||||
|
);
|
||||||
|
lexer->string[n] = 0;
|
||||||
|
lexer->string_len = n;
|
||||||
|
return stb__clex_token(lexer, CLEX_id, p, p+n-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for EOF
|
||||||
|
STB_C_LEX_0_IS_EOF(
|
||||||
|
if (*p == 0)
|
||||||
|
return stb__clex_eof(lexer);
|
||||||
|
)
|
||||||
|
|
||||||
|
single_char:
|
||||||
|
// not an identifier, return the character as itself
|
||||||
|
return stb__clex_token(lexer, *p, p, p);
|
||||||
|
|
||||||
|
case '+':
|
||||||
|
if (p+1 != lexer->eof) {
|
||||||
|
STB_C_LEX_C_INCREMENTS(if (p[1] == '+') return stb__clex_token(lexer, CLEX_plusplus, p,p+1);)
|
||||||
|
STB_C_LEX_C_ARITHEQ( if (p[1] == '=') return stb__clex_token(lexer, CLEX_pluseq , p,p+1);)
|
||||||
|
}
|
||||||
|
goto single_char;
|
||||||
|
case '-':
|
||||||
|
if (p+1 != lexer->eof) {
|
||||||
|
STB_C_LEX_C_INCREMENTS(if (p[1] == '-') return stb__clex_token(lexer, CLEX_minusminus, p,p+1);)
|
||||||
|
STB_C_LEX_C_ARITHEQ( if (p[1] == '=') return stb__clex_token(lexer, CLEX_minuseq , p,p+1);)
|
||||||
|
STB_C_LEX_C_ARROW( if (p[1] == '>') return stb__clex_token(lexer, CLEX_arrow , p,p+1);)
|
||||||
|
}
|
||||||
|
goto single_char;
|
||||||
|
case '&':
|
||||||
|
if (p+1 != lexer->eof) {
|
||||||
|
STB_C_LEX_C_LOGICAL( if (p[1] == '&') return stb__clex_token(lexer, CLEX_andand, p,p+1);)
|
||||||
|
STB_C_LEX_C_BITWISEEQ(if (p[1] == '=') return stb__clex_token(lexer, CLEX_andeq , p,p+1);)
|
||||||
|
}
|
||||||
|
goto single_char;
|
||||||
|
case '|':
|
||||||
|
if (p+1 != lexer->eof) {
|
||||||
|
STB_C_LEX_C_LOGICAL( if (p[1] == '|') return stb__clex_token(lexer, CLEX_oror, p,p+1);)
|
||||||
|
STB_C_LEX_C_BITWISEEQ(if (p[1] == '=') return stb__clex_token(lexer, CLEX_oreq, p,p+1);)
|
||||||
|
}
|
||||||
|
goto single_char;
|
||||||
|
case '=':
|
||||||
|
if (p+1 != lexer->eof) {
|
||||||
|
STB_C_LEX_C_COMPARISONS(if (p[1] == '=') return stb__clex_token(lexer, CLEX_eq, p,p+1);)
|
||||||
|
STB_C_LEX_EQUAL_ARROW( if (p[1] == '>') return stb__clex_token(lexer, CLEX_eqarrow, p,p+1);)
|
||||||
|
}
|
||||||
|
goto single_char;
|
||||||
|
case '!':
|
||||||
|
STB_C_LEX_C_COMPARISONS(if (p+1 != lexer->eof && p[1] == '=') return stb__clex_token(lexer, CLEX_noteq, p,p+1);)
|
||||||
|
goto single_char;
|
||||||
|
case '^':
|
||||||
|
STB_C_LEX_C_BITWISEEQ(if (p+1 != lexer->eof && p[1] == '=') return stb__clex_token(lexer, CLEX_xoreq, p,p+1));
|
||||||
|
goto single_char;
|
||||||
|
case '%':
|
||||||
|
STB_C_LEX_C_ARITHEQ(if (p+1 != lexer->eof && p[1] == '=') return stb__clex_token(lexer, CLEX_modeq, p,p+1));
|
||||||
|
goto single_char;
|
||||||
|
case '*':
|
||||||
|
STB_C_LEX_C_ARITHEQ(if (p+1 != lexer->eof && p[1] == '=') return stb__clex_token(lexer, CLEX_muleq, p,p+1));
|
||||||
|
goto single_char;
|
||||||
|
case '/':
|
||||||
|
STB_C_LEX_C_ARITHEQ(if (p+1 != lexer->eof && p[1] == '=') return stb__clex_token(lexer, CLEX_diveq, p,p+1));
|
||||||
|
goto single_char;
|
||||||
|
case '<':
|
||||||
|
if (p+1 != lexer->eof) {
|
||||||
|
STB_C_LEX_C_COMPARISONS(if (p[1] == '=') return stb__clex_token(lexer, CLEX_lesseq, p,p+1);)
|
||||||
|
STB_C_LEX_C_SHIFTS( if (p[1] == '<') {
|
||||||
|
STB_C_LEX_C_ARITHEQ(if (p+2 != lexer->eof && p[2] == '=')
|
||||||
|
return stb__clex_token(lexer, CLEX_shleq, p,p+2);)
|
||||||
|
return stb__clex_token(lexer, CLEX_shl, p,p+1);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
goto single_char;
|
||||||
|
case '>':
|
||||||
|
if (p+1 != lexer->eof) {
|
||||||
|
STB_C_LEX_C_COMPARISONS(if (p[1] == '=') return stb__clex_token(lexer, CLEX_greatereq, p,p+1);)
|
||||||
|
STB_C_LEX_C_SHIFTS( if (p[1] == '>') {
|
||||||
|
STB_C_LEX_C_ARITHEQ(if (p+2 != lexer->eof && p[2] == '=')
|
||||||
|
return stb__clex_token(lexer, CLEX_shreq, p,p+2);)
|
||||||
|
return stb__clex_token(lexer, CLEX_shr, p,p+1);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
goto single_char;
|
||||||
|
|
||||||
|
case '"':
|
||||||
|
STB_C_LEX_C_DQ_STRINGS(return stb__clex_parse_string(lexer, p, CLEX_dqstring);)
|
||||||
|
goto single_char;
|
||||||
|
case '\'':
|
||||||
|
STB_C_LEX_C_SQ_STRINGS(return stb__clex_parse_string(lexer, p, CLEX_sqstring);)
|
||||||
|
STB_C_LEX_C_CHARS(
|
||||||
|
{
|
||||||
|
char *start = p;
|
||||||
|
lexer->int_number = stb__clex_parse_char(p+1, &p);
|
||||||
|
if (lexer->int_number < 0)
|
||||||
|
return stb__clex_token(lexer, CLEX_parse_error, start,start);
|
||||||
|
if (p == lexer->eof || *p != '\'')
|
||||||
|
return stb__clex_token(lexer, CLEX_parse_error, start,p);
|
||||||
|
return stb__clex_token(lexer, CLEX_charlit, start, p+1);
|
||||||
|
})
|
||||||
|
goto single_char;
|
||||||
|
|
||||||
|
case '0':
|
||||||
|
#if defined(STB__clex_hex_ints) || defined(STB__clex_hex_floats)
|
||||||
|
if (p+1 != lexer->eof) {
|
||||||
|
if (p[1] == 'x' || p[1] == 'X') {
|
||||||
|
char *q;
|
||||||
|
|
||||||
|
#ifdef STB__clex_hex_floats
|
||||||
|
for (q=p+2;
|
||||||
|
q != lexer->eof && ((*q >= '0' && *q <= '9') || (*q >= 'a' && *q <= 'f') || (*q >= 'A' && *q <= 'F'));
|
||||||
|
++q);
|
||||||
|
if (q != lexer->eof) {
|
||||||
|
if (*q == '.' STB_C_LEX_FLOAT_NO_DECIMAL(|| *q == 'p' || *q == 'P')) {
|
||||||
|
#ifdef STB__CLEX_use_stdlib
|
||||||
|
lexer->real_number = strtod((char *) p, (char**) &q);
|
||||||
|
#else
|
||||||
|
lexer->real_number = stb__clex_parse_float(p, &q);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (p == q)
|
||||||
|
return stb__clex_token(lexer, CLEX_parse_error, p,q);
|
||||||
|
return stb__clex_parse_suffixes(lexer, CLEX_floatlit, p,q, STB_C_LEX_FLOAT_SUFFIXES);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // STB__CLEX_hex_floats
|
||||||
|
|
||||||
|
#ifdef STB__clex_hex_ints
|
||||||
|
#ifdef STB__CLEX_use_stdlib
|
||||||
|
lexer->int_number = strtol((char *) p, (char **) &q, 16);
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
stb__clex_int n=0;
|
||||||
|
for (q=p+2; q != lexer->eof; ++q) {
|
||||||
|
if (*q >= '0' && *q <= '9')
|
||||||
|
n = n*16 + (*q - '0');
|
||||||
|
else if (*q >= 'a' && *q <= 'f')
|
||||||
|
n = n*16 + (*q - 'a') + 10;
|
||||||
|
else if (*q >= 'A' && *q <= 'F')
|
||||||
|
n = n*16 + (*q - 'A') + 10;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lexer->int_number = n;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (q == p+2)
|
||||||
|
return stb__clex_token(lexer, CLEX_parse_error, p-2,p-1);
|
||||||
|
return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_HEX_SUFFIXES);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // defined(STB__clex_hex_ints) || defined(STB__clex_hex_floats)
|
||||||
|
// can't test for octal because we might parse '0.0' as float or as '0' '.' '0',
|
||||||
|
// so have to do float first
|
||||||
|
|
||||||
|
/* FALL THROUGH */
|
||||||
|
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
|
||||||
|
|
||||||
|
#ifdef STB__clex_decimal_floats
|
||||||
|
{
|
||||||
|
char *q = p;
|
||||||
|
while (q != lexer->eof && (*q >= '0' && *q <= '9'))
|
||||||
|
++q;
|
||||||
|
if (q != lexer->eof) {
|
||||||
|
if (*q == '.' STB_C_LEX_FLOAT_NO_DECIMAL(|| *q == 'e' || *q == 'E')) {
|
||||||
|
#ifdef STB__CLEX_use_stdlib
|
||||||
|
lexer->real_number = strtod((char *) p, (char**) &q);
|
||||||
|
#else
|
||||||
|
lexer->real_number = stb__clex_parse_float(p, &q);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return stb__clex_parse_suffixes(lexer, CLEX_floatlit, p,q, STB_C_LEX_FLOAT_SUFFIXES);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // STB__clex_decimal_floats
|
||||||
|
|
||||||
|
#ifdef STB__clex_octal_ints
|
||||||
|
if (p[0] == '0') {
|
||||||
|
char *q = p;
|
||||||
|
#ifdef STB__CLEX_use_stdlib
|
||||||
|
lexer->int_number = strtol((char *) p, (char **) &q, 8);
|
||||||
|
#else
|
||||||
|
stb__clex_int n=0;
|
||||||
|
while (q != lexer->eof) {
|
||||||
|
if (*q >= '0' && *q <= '7')
|
||||||
|
n = n*8 + (*q - '0');
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
++q;
|
||||||
|
}
|
||||||
|
if (q != lexer->eof && (*q == '8' || *q=='9'))
|
||||||
|
return stb__clex_token(lexer, CLEX_parse_error, p, q);
|
||||||
|
lexer->int_number = n;
|
||||||
|
#endif
|
||||||
|
return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_OCTAL_SUFFIXES);
|
||||||
|
}
|
||||||
|
#endif // STB__clex_octal_ints
|
||||||
|
|
||||||
|
#ifdef STB__clex_decimal_ints
|
||||||
|
{
|
||||||
|
char *q = p;
|
||||||
|
#ifdef STB__CLEX_use_stdlib
|
||||||
|
lexer->int_number = strtol((char *) p, (char **) &q, 10);
|
||||||
|
#else
|
||||||
|
stb__clex_int n=0;
|
||||||
|
while (q != lexer->eof) {
|
||||||
|
if (*q >= '0' && *q <= '9')
|
||||||
|
n = n*10 + (*q - '0');
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
++q;
|
||||||
|
}
|
||||||
|
lexer->int_number = n;
|
||||||
|
#endif
|
||||||
|
return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_OCTAL_SUFFIXES);
|
||||||
|
}
|
||||||
|
#endif // STB__clex_decimal_ints
|
||||||
|
goto single_char;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // STB_C_LEXER_IMPLEMENTATION
|
||||||
|
|
||||||
|
#ifdef STB_C_LEXER_SELF_TEST
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static void print_token(stb_lexer *lexer)
|
||||||
|
{
|
||||||
|
switch (lexer->token) {
|
||||||
|
case CLEX_id : printf("_%s", lexer->string); break;
|
||||||
|
case CLEX_eq : printf("=="); break;
|
||||||
|
case CLEX_noteq : printf("!="); break;
|
||||||
|
case CLEX_lesseq : printf("<="); break;
|
||||||
|
case CLEX_greatereq : printf(">="); break;
|
||||||
|
case CLEX_andand : printf("&&"); break;
|
||||||
|
case CLEX_oror : printf("||"); break;
|
||||||
|
case CLEX_shl : printf("<<"); break;
|
||||||
|
case CLEX_shr : printf(">>"); break;
|
||||||
|
case CLEX_plusplus : printf("++"); break;
|
||||||
|
case CLEX_minusminus: printf("--"); break;
|
||||||
|
case CLEX_arrow : printf("->"); break;
|
||||||
|
case CLEX_andeq : printf("&="); break;
|
||||||
|
case CLEX_oreq : printf("|="); break;
|
||||||
|
case CLEX_xoreq : printf("^="); break;
|
||||||
|
case CLEX_pluseq : printf("+="); break;
|
||||||
|
case CLEX_minuseq : printf("-="); break;
|
||||||
|
case CLEX_muleq : printf("*="); break;
|
||||||
|
case CLEX_diveq : printf("/="); break;
|
||||||
|
case CLEX_modeq : printf("%%="); break;
|
||||||
|
case CLEX_shleq : printf("<<="); break;
|
||||||
|
case CLEX_shreq : printf(">>="); break;
|
||||||
|
case CLEX_eqarrow : printf("=>"); break;
|
||||||
|
case CLEX_dqstring : printf("\"%s\"", lexer->string); break;
|
||||||
|
case CLEX_sqstring : printf("'\"%s\"'", lexer->string); break;
|
||||||
|
case CLEX_charlit : printf("'%s'", lexer->string); break;
|
||||||
|
#if defined(STB__clex_int_as_double) && !defined(STB__CLEX_use_stdlib)
|
||||||
|
case CLEX_intlit : printf("#%g", lexer->real_number); break;
|
||||||
|
#else
|
||||||
|
case CLEX_intlit : printf("#%ld", lexer->int_number); break;
|
||||||
|
#endif
|
||||||
|
case CLEX_floatlit : printf("%g", lexer->real_number); break;
|
||||||
|
default:
|
||||||
|
if (lexer->token >= 0 && lexer->token < 256)
|
||||||
|
printf("%c", (int) lexer->token);
|
||||||
|
else {
|
||||||
|
printf("<<<UNKNOWN TOKEN %ld >>>\n", lexer->token);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force a test
|
||||||
|
of parsing
|
||||||
|
multiline comments */
|
||||||
|
|
||||||
|
/*/ comment /*/
|
||||||
|
/**/ extern /**/
|
||||||
|
|
||||||
|
void dummy(void)
|
||||||
|
{
|
||||||
|
double some_floats[] = {
|
||||||
|
1.0501, -10.4e12, 5E+10,
|
||||||
|
#if 0 // not supported in C++ or C-pre-99, so don't try to compile it, but let our parser test it
|
||||||
|
0x1.0p+24, 0xff.FP-8, 0x1p-23,
|
||||||
|
#endif
|
||||||
|
4.
|
||||||
|
};
|
||||||
|
(void) sizeof(some_floats);
|
||||||
|
(void) some_floats[1];
|
||||||
|
|
||||||
|
printf("test %d",1); // https://github.com/nothings/stb/issues/13
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
FILE *f = fopen("stb_c_lexer.h","rb");
|
||||||
|
char *text = (char *) malloc(1 << 20);
|
||||||
|
int len = f ? (int) fread(text, 1, 1<<20, f) : -1;
|
||||||
|
stb_lexer lex;
|
||||||
|
if (len < 0) {
|
||||||
|
fprintf(stderr, "Error opening file\n");
|
||||||
|
free(text);
|
||||||
|
fclose(f);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
stb_c_lexer_init(&lex, text, text+len, (char *) malloc(0x10000), 0x10000);
|
||||||
|
while (stb_c_lexer_get_token(&lex)) {
|
||||||
|
if (lex.token == CLEX_parse_error) {
|
||||||
|
printf("\n<<<PARSE ERROR>>>\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
print_token(&lex);
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
This software is available under 2 licenses -- choose whichever you prefer.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE A - MIT License
|
||||||
|
Copyright (c) 2017 Sean Barrett
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||||
|
software, either in source code form or as a compiled binary, for any purpose,
|
||||||
|
commercial or non-commercial, and by any means.
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||||
|
software dedicate any and all copyright interest in the software to the public
|
||||||
|
domain. We make this dedication for the benefit of the public at large and to
|
||||||
|
the detriment of our heirs and successors. We intend this dedication to be an
|
||||||
|
overt act of relinquishment in perpetuity of all present and future rights to
|
||||||
|
this software under copyright law.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
1049
include/stb_connected_components.h
Normal file
1049
include/stb_connected_components.h
Normal file
File diff suppressed because it is too large
Load Diff
433
include/stb_divide.h
Normal file
433
include/stb_divide.h
Normal file
@ -0,0 +1,433 @@
|
|||||||
|
// stb_divide.h - v0.94 - public domain - Sean Barrett, Feb 2010
|
||||||
|
// Three kinds of divide/modulus of signed integers.
|
||||||
|
//
|
||||||
|
// HISTORY
|
||||||
|
//
|
||||||
|
// v0.94 Fix integer overflow issues
|
||||||
|
// v0.93 2020-02-02 Write useful exit() value from main()
|
||||||
|
// v0.92 2019-02-25 Fix warning
|
||||||
|
// v0.91 2010-02-27 Fix euclidean division by INT_MIN for non-truncating C
|
||||||
|
// Check result with 64-bit math to catch such cases
|
||||||
|
// v0.90 2010-02-24 First public release
|
||||||
|
//
|
||||||
|
// USAGE
|
||||||
|
//
|
||||||
|
// In *ONE* source file, put:
|
||||||
|
//
|
||||||
|
// #define STB_DIVIDE_IMPLEMENTATION
|
||||||
|
// // #define C_INTEGER_DIVISION_TRUNCATES // see Note 1
|
||||||
|
// // #define C_INTEGER_DIVISION_FLOORS // see Note 2
|
||||||
|
// #include "stb_divide.h"
|
||||||
|
//
|
||||||
|
// Other source files should just include stb_divide.h
|
||||||
|
//
|
||||||
|
// Note 1: On platforms/compilers that you know signed C division
|
||||||
|
// truncates, you can #define C_INTEGER_DIVISION_TRUNCATES.
|
||||||
|
//
|
||||||
|
// Note 2: On platforms/compilers that you know signed C division
|
||||||
|
// floors (rounds to negative infinity), you can #define
|
||||||
|
// C_INTEGER_DIVISION_FLOORS.
|
||||||
|
//
|
||||||
|
// You can #define STB_DIVIDE_TEST in which case the implementation
|
||||||
|
// will generate a main() and compiling the result will create a
|
||||||
|
// program that tests the implementation. Run it with no arguments
|
||||||
|
// and any output indicates an error; run it with any argument and
|
||||||
|
// it will also print the test results. Define STB_DIVIDE_TEST_64
|
||||||
|
// to a 64-bit integer type to avoid overflows in the result-checking
|
||||||
|
// which give false negatives.
|
||||||
|
//
|
||||||
|
// ABOUT
|
||||||
|
//
|
||||||
|
// This file provides three different consistent divide/mod pairs
|
||||||
|
// implemented on top of arbitrary C/C++ division, including correct
|
||||||
|
// handling of overflow of intermediate calculations:
|
||||||
|
//
|
||||||
|
// trunc: a/b truncates to 0, a%b has same sign as a
|
||||||
|
// floor: a/b truncates to -inf, a%b has same sign as b
|
||||||
|
// eucl: a/b truncates to sign(b)*inf, a%b is non-negative
|
||||||
|
//
|
||||||
|
// Not necessarily optimal; I tried to keep it generally efficient,
|
||||||
|
// but there may be better ways.
|
||||||
|
//
|
||||||
|
// Briefly, for those who are not familiar with the problem, we note
|
||||||
|
// the reason these divides exist and are interesting:
|
||||||
|
//
|
||||||
|
// 'trunc' is easy to implement in hardware (strip the signs,
|
||||||
|
// compute, reapply the signs), thus is commonly defined
|
||||||
|
// by many languages (including C99)
|
||||||
|
//
|
||||||
|
// 'floor' is simple to define and better behaved than trunc;
|
||||||
|
// for example it divides integers into fixed-size buckets
|
||||||
|
// without an extra-wide bucket at 0, and for a fixed
|
||||||
|
// divisor N there are only |N| possible moduli.
|
||||||
|
//
|
||||||
|
// 'eucl' guarantees fixed-sized buckets *and* a non-negative
|
||||||
|
// modulus and defines division to be whatever is needed
|
||||||
|
// to achieve that result.
|
||||||
|
//
|
||||||
|
// See "The Euclidean definition of the functions div and mod"
|
||||||
|
// by Raymond Boute (1992), or "Division and Modulus for Computer
|
||||||
|
// Scientists" by Daan Leijen (2001)
|
||||||
|
//
|
||||||
|
// We assume of the built-in C division:
|
||||||
|
// (a) modulus is the remainder for the corresponding division
|
||||||
|
// (b) a/b truncates if a and b are the same sign
|
||||||
|
//
|
||||||
|
// Property (a) requires (a/b)*b + (a%b)==a, and is required by C.
|
||||||
|
// Property (b) seems to be true of all hardware but is *not* satisfied
|
||||||
|
// by the euclidean division operator we define, so it's possibly not
|
||||||
|
// always true. If any such platform turns up, we can add more cases.
|
||||||
|
// (Possibly only stb_div_trunc currently relies on property (b).)
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
//
|
||||||
|
// See end of file for license information.
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef INCLUDE_STB_DIVIDE_H
|
||||||
|
#define INCLUDE_STB_DIVIDE_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern int stb_div_trunc(int value_to_be_divided, int value_to_divide_by);
|
||||||
|
extern int stb_div_floor(int value_to_be_divided, int value_to_divide_by);
|
||||||
|
extern int stb_div_eucl (int value_to_be_divided, int value_to_divide_by);
|
||||||
|
extern int stb_mod_trunc(int value_to_be_divided, int value_to_divide_by);
|
||||||
|
extern int stb_mod_floor(int value_to_be_divided, int value_to_divide_by);
|
||||||
|
extern int stb_mod_eucl (int value_to_be_divided, int value_to_divide_by);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef STB_DIVIDE_IMPLEMENTATION
|
||||||
|
|
||||||
|
#if defined(__STDC_VERSION) && __STDC_VERSION__ >= 19901
|
||||||
|
#ifndef C_INTEGER_DIVISION_TRUNCATES
|
||||||
|
#define C_INTEGER_DIVISION_TRUNCATES
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef INT_MIN
|
||||||
|
#include <limits.h> // if you have no limits.h, #define INT_MIN yourself
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// the following macros are designed to allow testing
|
||||||
|
// other platforms by simulating them
|
||||||
|
#ifndef STB_DIVIDE_TEST_FLOOR
|
||||||
|
#define stb__div(a,b) ((a)/(b))
|
||||||
|
#define stb__mod(a,b) ((a)%(b))
|
||||||
|
#else
|
||||||
|
// implement floor-style divide on trunc platform
|
||||||
|
#ifndef C_INTEGER_DIVISION_TRUNCATES
|
||||||
|
#error "floor test requires truncating division"
|
||||||
|
#endif
|
||||||
|
#undef C_INTEGER_DIVISION_TRUNCATES
|
||||||
|
int stb__div(int v1, int v2)
|
||||||
|
{
|
||||||
|
int q = v1/v2, r = v1%v2;
|
||||||
|
if ((r > 0 && v2 < 0) || (r < 0 && v2 > 0))
|
||||||
|
return q-1;
|
||||||
|
else
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
int stb__mod(int v1, int v2)
|
||||||
|
{
|
||||||
|
int r = v1%v2;
|
||||||
|
if ((r > 0 && v2 < 0) || (r < 0 && v2 > 0))
|
||||||
|
return r+v2;
|
||||||
|
else
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int stb_div_trunc(int v1, int v2)
|
||||||
|
{
|
||||||
|
#ifdef C_INTEGER_DIVISION_TRUNCATES
|
||||||
|
return v1/v2;
|
||||||
|
#else
|
||||||
|
if (v1 >= 0 && v2 <= 0)
|
||||||
|
return -stb__div(-v1,v2); // both negative to avoid overflow
|
||||||
|
if (v1 <= 0 && v2 >= 0)
|
||||||
|
if (v1 != INT_MIN)
|
||||||
|
return -stb__div(v1,-v2); // both negative to avoid overflow
|
||||||
|
else
|
||||||
|
return -stb__div(v1+v2,-v2)-1; // push v1 away from wrap point
|
||||||
|
else
|
||||||
|
return v1/v2; // same sign, so expect truncation
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int stb_div_floor(int v1, int v2)
|
||||||
|
{
|
||||||
|
#ifdef C_INTEGER_DIVISION_FLOORS
|
||||||
|
return v1/v2;
|
||||||
|
#else
|
||||||
|
if (v1 >= 0 && v2 < 0) {
|
||||||
|
if (v2 + 1 >= INT_MIN + v1) // check if increasing v1's magnitude overflows
|
||||||
|
return -stb__div((v2+1)-v1,v2); // nope, so just compute it
|
||||||
|
else
|
||||||
|
return -stb__div(-v1,v2) + ((-v1)%v2 ? -1 : 0);
|
||||||
|
}
|
||||||
|
if (v1 < 0 && v2 >= 0) {
|
||||||
|
if (v1 != INT_MIN) {
|
||||||
|
if (v1 + 1 >= INT_MIN + v2) // check if increasing v1's magnitude overflows
|
||||||
|
return -stb__div((v1+1)-v2,-v2); // nope, so just compute it
|
||||||
|
else
|
||||||
|
return -stb__div(-v1,v2) + (stb__mod(v1,-v2) ? -1 : 0);
|
||||||
|
} else // it must be possible to compute -(v1+v2) without overflowing
|
||||||
|
return -stb__div(-(v1+v2),v2) + (stb__mod(-(v1+v2),v2) ? -2 : -1);
|
||||||
|
} else
|
||||||
|
return v1/v2; // same sign, so expect truncation
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int stb_div_eucl(int v1, int v2)
|
||||||
|
{
|
||||||
|
int q,r;
|
||||||
|
#ifdef C_INTEGER_DIVISION_TRUNCATES
|
||||||
|
q = v1/v2;
|
||||||
|
r = v1%v2;
|
||||||
|
#else
|
||||||
|
// handle every quadrant separately, since we can't rely on q and r flor
|
||||||
|
if (v1 >= 0)
|
||||||
|
if (v2 >= 0)
|
||||||
|
return stb__div(v1,v2);
|
||||||
|
else if (v2 != INT_MIN)
|
||||||
|
q = -stb__div(v1,-v2), r = stb__mod(v1,-v2);
|
||||||
|
else
|
||||||
|
q = 0, r = v1;
|
||||||
|
else if (v1 != INT_MIN)
|
||||||
|
if (v2 >= 0)
|
||||||
|
q = -stb__div(-v1,v2), r = -stb__mod(-v1,v2);
|
||||||
|
else if (v2 != INT_MIN)
|
||||||
|
q = stb__div(-v1,-v2), r = -stb__mod(-v1,-v2);
|
||||||
|
else // if v2 is INT_MIN, then we can't use -v2, but we can't divide by v2
|
||||||
|
q = 1, r = v1-q*v2;
|
||||||
|
else // if v1 is INT_MIN, we have to move away from overflow place
|
||||||
|
if (v2 >= 0)
|
||||||
|
q = -stb__div(-(v1+v2),v2)-1, r = -stb__mod(-(v1+v2),v2);
|
||||||
|
else if (v2 != INT_MIN)
|
||||||
|
q = stb__div(-(v1-v2),-v2)+1, r = -stb__mod(-(v1-v2),-v2);
|
||||||
|
else // for INT_MIN / INT_MIN, we need to be extra-careful to avoid overflow
|
||||||
|
q = 1, r = 0;
|
||||||
|
#endif
|
||||||
|
if (r >= 0)
|
||||||
|
return q;
|
||||||
|
else
|
||||||
|
return q + (v2 > 0 ? -1 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int stb_mod_trunc(int v1, int v2)
|
||||||
|
{
|
||||||
|
#ifdef C_INTEGER_DIVISION_TRUNCATES
|
||||||
|
return v1%v2;
|
||||||
|
#else
|
||||||
|
if (v1 >= 0) { // modulus result should always be positive
|
||||||
|
int r = stb__mod(v1,v2);
|
||||||
|
if (r >= 0)
|
||||||
|
return r;
|
||||||
|
else
|
||||||
|
return r - (v2 < 0 ? v2 : -v2);
|
||||||
|
} else { // modulus result should always be negative
|
||||||
|
int r = stb__mod(v1,v2);
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
else
|
||||||
|
return r + (v2 < 0 ? v2 : -v2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int stb_mod_floor(int v1, int v2)
|
||||||
|
{
|
||||||
|
#ifdef C_INTEGER_DIVISION_FLOORS
|
||||||
|
return v1%v2;
|
||||||
|
#else
|
||||||
|
if (v2 >= 0) { // result should always be positive
|
||||||
|
int r = stb__mod(v1,v2);
|
||||||
|
if (r >= 0)
|
||||||
|
return r;
|
||||||
|
else
|
||||||
|
return r + v2;
|
||||||
|
} else { // result should always be negative
|
||||||
|
int r = stb__mod(v1,v2);
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
else
|
||||||
|
return r + v2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int stb_mod_eucl(int v1, int v2)
|
||||||
|
{
|
||||||
|
int r = stb__mod(v1,v2);
|
||||||
|
|
||||||
|
if (r >= 0)
|
||||||
|
return r;
|
||||||
|
else
|
||||||
|
return r - (v2 < 0 ? v2 : -v2); // negative abs() [to avoid overflow]
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef STB_DIVIDE_TEST
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
int show=0;
|
||||||
|
int err=0;
|
||||||
|
|
||||||
|
void stbdiv_check(int q, int r, int a, int b, char *type, int dir)
|
||||||
|
{
|
||||||
|
if ((dir > 0 && r < 0) || (dir < 0 && r > 0)) {
|
||||||
|
fprintf(stderr, "FAILED: %s(%d,%d) remainder %d in wrong direction\n", type,a,b,r);
|
||||||
|
err++;
|
||||||
|
} else
|
||||||
|
if (b != INT_MIN) // can't compute abs(), but if b==INT_MIN all remainders are valid
|
||||||
|
if (r <= -abs(b) || r >= abs(b)) {
|
||||||
|
fprintf(stderr, "FAILED: %s(%d,%d) remainder %d out of range\n", type,a,b,r);
|
||||||
|
err++;
|
||||||
|
}
|
||||||
|
#ifdef STB_DIVIDE_TEST_64
|
||||||
|
{
|
||||||
|
STB_DIVIDE_TEST_64 q64 = q, r64=r, a64=a, b64=b;
|
||||||
|
if (q64*b64+r64 != a64) {
|
||||||
|
fprintf(stderr, "FAILED: %s(%d,%d) remainder %d doesn't match quotient %d\n", type,a,b,r,q);
|
||||||
|
err++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (q*b+r != a) {
|
||||||
|
fprintf(stderr, "FAILED: %s(%d,%d) remainder %d doesn't match quotient %d\n", type,a,b,r,q);
|
||||||
|
err++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void test(int a, int b)
|
||||||
|
{
|
||||||
|
int q,r;
|
||||||
|
if (show) printf("(%+11d,%+d) | ", a,b);
|
||||||
|
q = stb_div_trunc(a,b), r = stb_mod_trunc(a,b);
|
||||||
|
if (show) printf("(%+11d,%+2d) ", q,r); stbdiv_check(q,r,a,b, "trunc",a);
|
||||||
|
q = stb_div_floor(a,b), r = stb_mod_floor(a,b);
|
||||||
|
if (show) printf("(%+11d,%+2d) ", q,r); stbdiv_check(q,r,a,b, "floor",b);
|
||||||
|
q = stb_div_eucl (a,b), r = stb_mod_eucl (a,b);
|
||||||
|
if (show) printf("(%+11d,%+2d)\n", q,r); stbdiv_check(q,r,a,b, "euclidean",1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testh(int a, int b)
|
||||||
|
{
|
||||||
|
int q,r;
|
||||||
|
if (show) printf("(%08x,%08x) |\n", a,b);
|
||||||
|
q = stb_div_trunc(a,b), r = stb_mod_trunc(a,b); stbdiv_check(q,r,a,b, "trunc",a);
|
||||||
|
if (show) printf(" (%08x,%08x)", q,r);
|
||||||
|
q = stb_div_floor(a,b), r = stb_mod_floor(a,b); stbdiv_check(q,r,a,b, "floor",b);
|
||||||
|
if (show) printf(" (%08x,%08x)", q,r);
|
||||||
|
q = stb_div_eucl (a,b), r = stb_mod_eucl (a,b); stbdiv_check(q,r,a,b, "euclidean",1);
|
||||||
|
if (show) printf(" (%08x,%08x)\n ", q,r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc > 1) show=1;
|
||||||
|
|
||||||
|
test(8,3);
|
||||||
|
test(8,-3);
|
||||||
|
test(-8,3);
|
||||||
|
test(-8,-3);
|
||||||
|
test(1,2);
|
||||||
|
test(1,-2);
|
||||||
|
test(-1,2);
|
||||||
|
test(-1,-2);
|
||||||
|
test(8,4);
|
||||||
|
test(8,-4);
|
||||||
|
test(-8,4);
|
||||||
|
test(-8,-4);
|
||||||
|
|
||||||
|
test(INT_MAX,1);
|
||||||
|
test(INT_MIN,1);
|
||||||
|
test(INT_MIN+1,1);
|
||||||
|
test(INT_MAX,-1);
|
||||||
|
//test(INT_MIN,-1); // this traps in MSVC, so we leave it untested
|
||||||
|
test(INT_MIN+1,-1);
|
||||||
|
test(INT_MIN,-2);
|
||||||
|
test(INT_MIN+1,2);
|
||||||
|
test(INT_MIN+1,-2);
|
||||||
|
test(INT_MAX,2);
|
||||||
|
test(INT_MAX,-2);
|
||||||
|
test(INT_MIN+1,2);
|
||||||
|
test(INT_MIN+1,-2);
|
||||||
|
test(INT_MIN,2);
|
||||||
|
test(INT_MIN,-2);
|
||||||
|
test(INT_MIN,7);
|
||||||
|
test(INT_MIN,-7);
|
||||||
|
test(INT_MIN+1,4);
|
||||||
|
test(INT_MIN+1,-4);
|
||||||
|
|
||||||
|
testh(-7, INT_MIN);
|
||||||
|
testh(-1, INT_MIN);
|
||||||
|
testh(1, INT_MIN);
|
||||||
|
testh(7, INT_MIN);
|
||||||
|
|
||||||
|
testh(INT_MAX-1, INT_MIN);
|
||||||
|
testh(INT_MAX, INT_MIN);
|
||||||
|
testh(INT_MIN, INT_MIN);
|
||||||
|
testh(INT_MIN+1, INT_MIN);
|
||||||
|
|
||||||
|
testh(INT_MAX-1, INT_MAX);
|
||||||
|
testh(INT_MAX , INT_MAX);
|
||||||
|
testh(INT_MIN , INT_MAX);
|
||||||
|
testh(INT_MIN+1, INT_MAX);
|
||||||
|
|
||||||
|
return err > 0 ? 1 : 0;
|
||||||
|
}
|
||||||
|
#endif // STB_DIVIDE_TEST
|
||||||
|
#endif // STB_DIVIDE_IMPLEMENTATION
|
||||||
|
#endif // INCLUDE_STB_DIVIDE_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
This software is available under 2 licenses -- choose whichever you prefer.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE A - MIT License
|
||||||
|
Copyright (c) 2017 Sean Barrett
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||||
|
software, either in source code form or as a compiled binary, for any purpose,
|
||||||
|
commercial or non-commercial, and by any means.
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||||
|
software dedicate any and all copyright interest in the software to the public
|
||||||
|
domain. We make this dedication for the benefit of the public at large and to
|
||||||
|
the detriment of our heirs and successors. We intend this dedication to be an
|
||||||
|
overt act of relinquishment in perpetuity of all present and future rights to
|
||||||
|
this software under copyright law.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
1895
include/stb_ds.h
Normal file
1895
include/stb_ds.h
Normal file
File diff suppressed because it is too large
Load Diff
7988
include/stb_image.h
Normal file
7988
include/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
1724
include/stb_image_write.h
Normal file
1724
include/stb_image_write.h
Normal file
File diff suppressed because it is too large
Load Diff
295
include/stb_include.h
Normal file
295
include/stb_include.h
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
// stb_include.h - v0.02 - parse and process #include directives - public domain
|
||||||
|
//
|
||||||
|
// To build this, in one source file that includes this file do
|
||||||
|
// #define STB_INCLUDE_IMPLEMENTATION
|
||||||
|
//
|
||||||
|
// This program parses a string and replaces lines of the form
|
||||||
|
// #include "foo"
|
||||||
|
// with the contents of a file named "foo". It also embeds the
|
||||||
|
// appropriate #line directives. Note that all include files must
|
||||||
|
// reside in the location specified in the path passed to the API;
|
||||||
|
// it does not check multiple directories.
|
||||||
|
//
|
||||||
|
// If the string contains a line of the form
|
||||||
|
// #inject
|
||||||
|
// then it will be replaced with the contents of the string 'inject' passed to the API.
|
||||||
|
//
|
||||||
|
// Options:
|
||||||
|
//
|
||||||
|
// Define STB_INCLUDE_LINE_GLSL to get GLSL-style #line directives
|
||||||
|
// which use numbers instead of filenames.
|
||||||
|
//
|
||||||
|
// Define STB_INCLUDE_LINE_NONE to disable output of #line directives.
|
||||||
|
//
|
||||||
|
// Standard libraries:
|
||||||
|
//
|
||||||
|
// stdio.h FILE, fopen, fclose, fseek, ftell
|
||||||
|
// stdlib.h malloc, realloc, free
|
||||||
|
// string.h strcpy, strncmp, memcpy
|
||||||
|
//
|
||||||
|
// Credits:
|
||||||
|
//
|
||||||
|
// Written by Sean Barrett.
|
||||||
|
//
|
||||||
|
// Fixes:
|
||||||
|
// Michal Klos
|
||||||
|
|
||||||
|
#ifndef STB_INCLUDE_STB_INCLUDE_H
|
||||||
|
#define STB_INCLUDE_STB_INCLUDE_H
|
||||||
|
|
||||||
|
// Do include-processing on the string 'str'. To free the return value, pass it to free()
|
||||||
|
char *stb_include_string(char *str, char *inject, char *path_to_includes, char *filename_for_line_directive, char error[256]);
|
||||||
|
|
||||||
|
// Concatenate the strings 'strs' and do include-processing on the result. To free the return value, pass it to free()
|
||||||
|
char *stb_include_strings(char **strs, int count, char *inject, char *path_to_includes, char *filename_for_line_directive, char error[256]);
|
||||||
|
|
||||||
|
// Load the file 'filename' and do include-processing on the string therein. note that
|
||||||
|
// 'filename' is opened directly; 'path_to_includes' is not used. To free the return value, pass it to free()
|
||||||
|
char *stb_include_file(char *filename, char *inject, char *path_to_includes, char error[256]);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef STB_INCLUDE_IMPLEMENTATION
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static char *stb_include_load_file(char *filename, size_t *plen)
|
||||||
|
{
|
||||||
|
char *text;
|
||||||
|
size_t len;
|
||||||
|
FILE *f = fopen(filename, "rb");
|
||||||
|
if (f == 0) return 0;
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
len = (size_t) ftell(f);
|
||||||
|
if (plen) *plen = len;
|
||||||
|
text = (char *) malloc(len+1);
|
||||||
|
if (text == 0) return 0;
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
fread(text, 1, len, f);
|
||||||
|
fclose(f);
|
||||||
|
text[len] = 0;
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int offset;
|
||||||
|
int end;
|
||||||
|
char *filename;
|
||||||
|
int next_line_after;
|
||||||
|
} include_info;
|
||||||
|
|
||||||
|
static include_info *stb_include_append_include(include_info *array, int len, int offset, int end, char *filename, int next_line)
|
||||||
|
{
|
||||||
|
include_info *z = (include_info *) realloc(array, sizeof(*z) * (len+1));
|
||||||
|
z[len].offset = offset;
|
||||||
|
z[len].end = end;
|
||||||
|
z[len].filename = filename;
|
||||||
|
z[len].next_line_after = next_line;
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stb_include_free_includes(include_info *array, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0; i < len; ++i)
|
||||||
|
free(array[i].filename);
|
||||||
|
free(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stb_include_isspace(int ch)
|
||||||
|
{
|
||||||
|
return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
// find location of all #include and #inject
|
||||||
|
static int stb_include_find_includes(char *text, include_info **plist)
|
||||||
|
{
|
||||||
|
int line_count = 1;
|
||||||
|
int inc_count = 0;
|
||||||
|
char *s = text, *start;
|
||||||
|
include_info *list = NULL;
|
||||||
|
while (*s) {
|
||||||
|
// parse is always at start of line when we reach here
|
||||||
|
start = s;
|
||||||
|
while (*s == ' ' || *s == '\t')
|
||||||
|
++s;
|
||||||
|
if (*s == '#') {
|
||||||
|
++s;
|
||||||
|
while (*s == ' ' || *s == '\t')
|
||||||
|
++s;
|
||||||
|
if (0==strncmp(s, "include", 7) && stb_include_isspace(s[7])) {
|
||||||
|
s += 7;
|
||||||
|
while (*s == ' ' || *s == '\t')
|
||||||
|
++s;
|
||||||
|
if (*s == '"') {
|
||||||
|
char *t = ++s;
|
||||||
|
while (*t != '"' && *t != '\n' && *t != '\r' && *t != 0)
|
||||||
|
++t;
|
||||||
|
if (*t == '"') {
|
||||||
|
char *filename = (char *) malloc(t-s+1);
|
||||||
|
memcpy(filename, s, t-s);
|
||||||
|
filename[t-s] = 0;
|
||||||
|
s=t;
|
||||||
|
while (*s != '\r' && *s != '\n' && *s != 0)
|
||||||
|
++s;
|
||||||
|
// s points to the newline, so s-start is everything except the newline
|
||||||
|
list = stb_include_append_include(list, inc_count++, start-text, s-text, filename, line_count+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (0==strncmp(s, "inject", 6) && (stb_include_isspace(s[6]) || s[6]==0)) {
|
||||||
|
while (*s != '\r' && *s != '\n' && *s != 0)
|
||||||
|
++s;
|
||||||
|
list = stb_include_append_include(list, inc_count++, start-text, s-text, NULL, line_count+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (*s != '\r' && *s != '\n' && *s != 0)
|
||||||
|
++s;
|
||||||
|
if (*s == '\r' || *s == '\n') {
|
||||||
|
s = s + (s[0] + s[1] == '\r' + '\n' ? 2 : 1);
|
||||||
|
}
|
||||||
|
++line_count;
|
||||||
|
}
|
||||||
|
*plist = list;
|
||||||
|
return inc_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid dependency on sprintf()
|
||||||
|
static void stb_include_itoa(char str[9], int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0; i < 8; ++i)
|
||||||
|
str[i] = ' ';
|
||||||
|
str[i] = 0;
|
||||||
|
|
||||||
|
for (i=1; i < 8; ++i) {
|
||||||
|
str[7-i] = '0' + (n % 10);
|
||||||
|
n /= 10;
|
||||||
|
if (n == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *stb_include_append(char *str, size_t *curlen, char *addstr, size_t addlen)
|
||||||
|
{
|
||||||
|
str = (char *) realloc(str, *curlen + addlen);
|
||||||
|
memcpy(str + *curlen, addstr, addlen);
|
||||||
|
*curlen += addlen;
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *stb_include_string(char *str, char *inject, char *path_to_includes, char *filename, char error[256])
|
||||||
|
{
|
||||||
|
char temp[4096];
|
||||||
|
include_info *inc_list;
|
||||||
|
int i, num = stb_include_find_includes(str, &inc_list);
|
||||||
|
size_t source_len = strlen(str);
|
||||||
|
char *text=0;
|
||||||
|
size_t textlen=0, last=0;
|
||||||
|
for (i=0; i < num; ++i) {
|
||||||
|
text = stb_include_append(text, &textlen, str+last, inc_list[i].offset - last);
|
||||||
|
// write out line directive for the include
|
||||||
|
#ifndef STB_INCLUDE_LINE_NONE
|
||||||
|
#ifdef STB_INCLUDE_LINE_GLSL
|
||||||
|
if (textlen != 0) // GLSL #version must appear first, so don't put a #line at the top
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
strcpy(temp, "#line ");
|
||||||
|
stb_include_itoa(temp+6, 1);
|
||||||
|
strcat(temp, " ");
|
||||||
|
#ifdef STB_INCLUDE_LINE_GLSL
|
||||||
|
stb_include_itoa(temp+15, i+1);
|
||||||
|
#else
|
||||||
|
strcat(temp, "\"");
|
||||||
|
if (inc_list[i].filename == 0)
|
||||||
|
strcmp(temp, "INJECT");
|
||||||
|
else
|
||||||
|
strcat(temp, inc_list[i].filename);
|
||||||
|
strcat(temp, "\"");
|
||||||
|
#endif
|
||||||
|
strcat(temp, "\n");
|
||||||
|
text = stb_include_append(text, &textlen, temp, strlen(temp));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (inc_list[i].filename == 0) {
|
||||||
|
if (inject != 0)
|
||||||
|
text = stb_include_append(text, &textlen, inject, strlen(inject));
|
||||||
|
} else {
|
||||||
|
char *inc;
|
||||||
|
strcpy(temp, path_to_includes);
|
||||||
|
strcat(temp, "/");
|
||||||
|
strcat(temp, inc_list[i].filename);
|
||||||
|
inc = stb_include_file(temp, inject, path_to_includes, error);
|
||||||
|
if (inc == NULL) {
|
||||||
|
stb_include_free_includes(inc_list, num);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
text = stb_include_append(text, &textlen, inc, strlen(inc));
|
||||||
|
free(inc);
|
||||||
|
}
|
||||||
|
// write out line directive
|
||||||
|
#ifndef STB_INCLUDE_LINE_NONE
|
||||||
|
strcpy(temp, "\n#line ");
|
||||||
|
stb_include_itoa(temp+6, inc_list[i].next_line_after);
|
||||||
|
strcat(temp, " ");
|
||||||
|
#ifdef STB_INCLUDE_LINE_GLSL
|
||||||
|
stb_include_itoa(temp+15, 0);
|
||||||
|
#else
|
||||||
|
strcat(temp, filename != 0 ? filename : "source-file");
|
||||||
|
#endif
|
||||||
|
text = stb_include_append(text, &textlen, temp, strlen(temp));
|
||||||
|
// no newlines, because we kept the #include newlines, which will get appended next
|
||||||
|
#endif
|
||||||
|
last = inc_list[i].end;
|
||||||
|
}
|
||||||
|
text = stb_include_append(text, &textlen, str+last, source_len - last + 1); // append '\0'
|
||||||
|
stb_include_free_includes(inc_list, num);
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *stb_include_strings(char **strs, int count, char *inject, char *path_to_includes, char *filename, char error[256])
|
||||||
|
{
|
||||||
|
char *text;
|
||||||
|
char *result;
|
||||||
|
int i;
|
||||||
|
size_t length=0;
|
||||||
|
for (i=0; i < count; ++i)
|
||||||
|
length += strlen(strs[i]);
|
||||||
|
text = (char *) malloc(length+1);
|
||||||
|
length = 0;
|
||||||
|
for (i=0; i < count; ++i) {
|
||||||
|
strcpy(text + length, strs[i]);
|
||||||
|
length += strlen(strs[i]);
|
||||||
|
}
|
||||||
|
result = stb_include_string(text, inject, path_to_includes, filename, error);
|
||||||
|
free(text);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *stb_include_file(char *filename, char *inject, char *path_to_includes, char error[256])
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
char *result;
|
||||||
|
char *text = stb_include_load_file(filename, &len);
|
||||||
|
if (text == NULL) {
|
||||||
|
strcpy(error, "Error: couldn't load '");
|
||||||
|
strcat(error, filename);
|
||||||
|
strcat(error, "'");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
result = stb_include_string(text, inject, path_to_includes, filename, error);
|
||||||
|
free(text);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 // @TODO, GL_ARB_shader_language_include-style system that doesn't touch filesystem
|
||||||
|
char *stb_include_preloaded(char *str, char *inject, char *includes[][2], char error[256])
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // STB_INCLUDE_IMPLEMENTATION
|
||||||
194
include/stb_leakcheck.h
Normal file
194
include/stb_leakcheck.h
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
// stb_leakcheck.h - v0.6 - quick & dirty malloc leak-checking - public domain
|
||||||
|
// LICENSE
|
||||||
|
//
|
||||||
|
// See end of file.
|
||||||
|
|
||||||
|
#ifdef STB_LEAKCHECK_IMPLEMENTATION
|
||||||
|
#undef STB_LEAKCHECK_IMPLEMENTATION // don't implement more than once
|
||||||
|
|
||||||
|
// if we've already included leakcheck before, undefine the macros
|
||||||
|
#ifdef malloc
|
||||||
|
#undef malloc
|
||||||
|
#undef free
|
||||||
|
#undef realloc
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STB_LEAKCHECK_OUTPUT_PIPE
|
||||||
|
#define STB_LEAKCHECK_OUTPUT_PIPE stdout
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
typedef struct malloc_info stb_leakcheck_malloc_info;
|
||||||
|
|
||||||
|
struct malloc_info
|
||||||
|
{
|
||||||
|
const char *file;
|
||||||
|
int line;
|
||||||
|
size_t size;
|
||||||
|
stb_leakcheck_malloc_info *next,*prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
static stb_leakcheck_malloc_info *mi_head;
|
||||||
|
|
||||||
|
void *stb_leakcheck_malloc(size_t sz, const char *file, int line)
|
||||||
|
{
|
||||||
|
stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) malloc(sz + sizeof(*mi));
|
||||||
|
if (mi == NULL) return mi;
|
||||||
|
mi->file = file;
|
||||||
|
mi->line = line;
|
||||||
|
mi->next = mi_head;
|
||||||
|
if (mi_head)
|
||||||
|
mi->next->prev = mi;
|
||||||
|
mi->prev = NULL;
|
||||||
|
mi->size = (int) sz;
|
||||||
|
mi_head = mi;
|
||||||
|
return mi+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stb_leakcheck_free(void *ptr)
|
||||||
|
{
|
||||||
|
if (ptr != NULL) {
|
||||||
|
stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) ptr - 1;
|
||||||
|
mi->size = ~mi->size;
|
||||||
|
#ifndef STB_LEAKCHECK_SHOWALL
|
||||||
|
if (mi->prev == NULL) {
|
||||||
|
assert(mi_head == mi);
|
||||||
|
mi_head = mi->next;
|
||||||
|
} else
|
||||||
|
mi->prev->next = mi->next;
|
||||||
|
if (mi->next)
|
||||||
|
mi->next->prev = mi->prev;
|
||||||
|
free(mi);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *stb_leakcheck_realloc(void *ptr, size_t sz, const char *file, int line)
|
||||||
|
{
|
||||||
|
if (ptr == NULL) {
|
||||||
|
return stb_leakcheck_malloc(sz, file, line);
|
||||||
|
} else if (sz == 0) {
|
||||||
|
stb_leakcheck_free(ptr);
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) ptr - 1;
|
||||||
|
if (sz <= mi->size)
|
||||||
|
return ptr;
|
||||||
|
else {
|
||||||
|
#ifdef STB_LEAKCHECK_REALLOC_PRESERVE_MALLOC_FILELINE
|
||||||
|
void *q = stb_leakcheck_malloc(sz, mi->file, mi->line);
|
||||||
|
#else
|
||||||
|
void *q = stb_leakcheck_malloc(sz, file, line);
|
||||||
|
#endif
|
||||||
|
if (q) {
|
||||||
|
memcpy(q, ptr, mi->size);
|
||||||
|
stb_leakcheck_free(ptr);
|
||||||
|
}
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stblkck_internal_print(const char *reason, stb_leakcheck_malloc_info *mi)
|
||||||
|
{
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER < 1900 // 1900=VS 2015
|
||||||
|
// Compilers that use the old MS C runtime library don't have %zd
|
||||||
|
// and the older ones don't even have %lld either... however, the old compilers
|
||||||
|
// without "long long" don't support 64-bit targets either, so here's the
|
||||||
|
// compromise:
|
||||||
|
#if _MSC_VER < 1400 // before VS 2005
|
||||||
|
fprintf(STB_LEAKCHECK_OUTPUT_PIPE, "%s: %s (%4d): %8d bytes at %p\n", reason, mi->file, mi->line, (int)mi->size, (void*)(mi+1));
|
||||||
|
#else
|
||||||
|
fprintf(STB_LEAKCHECK_OUTPUT_PIPE, "%s: %s (%4d): %16lld bytes at %p\n", reason, mi->file, mi->line, (long long)mi->size, (void*)(mi+1));
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// Assume we have %zd on other targets.
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
__mingw_fprintf(STB_LEAKCHECK_OUTPUT_PIPE, "%s: %s (%4d): %zd bytes at %p\n", reason, mi->file, mi->line, mi->size, (void*)(mi+1));
|
||||||
|
#else
|
||||||
|
fprintf(STB_LEAKCHECK_OUTPUT_PIPE, "%s: %s (%4d): %zd bytes at %p\n", reason, mi->file, mi->line, mi->size, (void*)(mi+1));
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void stb_leakcheck_dumpmem(void)
|
||||||
|
{
|
||||||
|
stb_leakcheck_malloc_info *mi = mi_head;
|
||||||
|
while (mi) {
|
||||||
|
if ((ptrdiff_t) mi->size >= 0)
|
||||||
|
stblkck_internal_print("LEAKED", mi);
|
||||||
|
mi = mi->next;
|
||||||
|
}
|
||||||
|
#ifdef STB_LEAKCHECK_SHOWALL
|
||||||
|
mi = mi_head;
|
||||||
|
while (mi) {
|
||||||
|
if ((ptrdiff_t) mi->size < 0)
|
||||||
|
stblkck_internal_print("FREED ", mi);
|
||||||
|
mi = mi->next;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif // STB_LEAKCHECK_IMPLEMENTATION
|
||||||
|
|
||||||
|
#if !defined(INCLUDE_STB_LEAKCHECK_H) || !defined(malloc)
|
||||||
|
#define INCLUDE_STB_LEAKCHECK_H
|
||||||
|
|
||||||
|
#include <stdlib.h> // we want to define the macros *after* stdlib to avoid a slew of errors
|
||||||
|
|
||||||
|
#define malloc(sz) stb_leakcheck_malloc(sz, __FILE__, __LINE__)
|
||||||
|
#define free(p) stb_leakcheck_free(p)
|
||||||
|
#define realloc(p,sz) stb_leakcheck_realloc(p,sz, __FILE__, __LINE__)
|
||||||
|
|
||||||
|
extern void * stb_leakcheck_malloc(size_t sz, const char *file, int line);
|
||||||
|
extern void * stb_leakcheck_realloc(void *ptr, size_t sz, const char *file, int line);
|
||||||
|
extern void stb_leakcheck_free(void *ptr);
|
||||||
|
extern void stb_leakcheck_dumpmem(void);
|
||||||
|
|
||||||
|
#endif // INCLUDE_STB_LEAKCHECK_H
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
This software is available under 2 licenses -- choose whichever you prefer.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE A - MIT License
|
||||||
|
Copyright (c) 2017 Sean Barrett
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||||
|
software, either in source code form or as a compiled binary, for any purpose,
|
||||||
|
commercial or non-commercial, and by any means.
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||||
|
software dedicate any and all copyright interest in the software to the public
|
||||||
|
domain. We make this dedication for the benefit of the public at large and to
|
||||||
|
the detriment of our heirs and successors. We intend this dedication to be an
|
||||||
|
overt act of relinquishment in perpetuity of all present and future rights to
|
||||||
|
this software under copyright law.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
1906
include/stb_sprintf.h
Normal file
1906
include/stb_sprintf.h
Normal file
File diff suppressed because it is too large
Load Diff
BIN
obj/main.o
Normal file
BIN
obj/main.o
Normal file
Binary file not shown.
66
source/array.h
Normal file
66
source/array.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#ifndef ARRAY_H
|
||||||
|
# define ARRAY_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
typedef struct Header_s{
|
||||||
|
int size;
|
||||||
|
int capacity;
|
||||||
|
int type;
|
||||||
|
} Header;
|
||||||
|
|
||||||
|
#ifndef memset
|
||||||
|
|
||||||
|
void *memset(void *src, char c, size_t size) {
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
*(char *)(src + i) = c;
|
||||||
|
}
|
||||||
|
return (src);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef void *Array;
|
||||||
|
|
||||||
|
#define ARRAY_BASE_CAPACITY 64
|
||||||
|
|
||||||
|
#define ArraySize(arr) ((Header*)(arr) - 1)->size
|
||||||
|
|
||||||
|
#define ArrayFree(arr) free(((Header*)(arr) - 1))
|
||||||
|
|
||||||
|
#define ArrayPush(arr, x)\
|
||||||
|
do {\
|
||||||
|
Header *head = NULL;\
|
||||||
|
if (!arr) { \
|
||||||
|
head = malloc(sizeof(x) * ARRAY_BASE_CAPACITY + sizeof(Header));\
|
||||||
|
head->size = 0;\
|
||||||
|
head->type = sizeof(x);\
|
||||||
|
head->capacity = ARRAY_BASE_CAPACITY;\
|
||||||
|
arr = (void *)(head + 1);\
|
||||||
|
}\
|
||||||
|
head = (Header*)(arr)-1;\
|
||||||
|
assert(sizeof(x) == head->type);\
|
||||||
|
if (head->size >= head->capacity) {\
|
||||||
|
head->capacity *= 2;\
|
||||||
|
head = realloc(head, head->type *head->capacity + sizeof(Header));\
|
||||||
|
arr = (void *)(head + 1);\
|
||||||
|
}\
|
||||||
|
(arr)[head->size++] = x;\
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define ArrayClear(arr)\
|
||||||
|
do {\
|
||||||
|
assert(arr);\
|
||||||
|
Header * head = (Header*)(arr)-1;\
|
||||||
|
memset(arr, 0, head->size * head->type);\
|
||||||
|
} while(0)\
|
||||||
|
|
||||||
|
|
||||||
|
# ifdef ARRAY_IMPL
|
||||||
|
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif
|
||||||
7
source/graphic.h
Normal file
7
source/graphic.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef GRAPHIC_H
|
||||||
|
# define GRAPHIC_H
|
||||||
|
|
||||||
|
//software renderer allowing for system agnostic rendering (other then drawing the frame on the screen)
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
94
source/main.c
Normal file
94
source/main.c
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
char *LoadFile(const char *filename) {
|
||||||
|
char *data = NULL;
|
||||||
|
FILE *file = NULL;
|
||||||
|
const int buff_size = 2048;
|
||||||
|
char buffer[buff_size];
|
||||||
|
int count = 0;
|
||||||
|
file = fopen(filename, "r");
|
||||||
|
count = fread(buffer, 1, buff_size, file);
|
||||||
|
data = calloc(count + 1, sizeof(char));
|
||||||
|
memcpy(data, buffer, count);
|
||||||
|
fclose(file);
|
||||||
|
return (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TOK_NONE,
|
||||||
|
TOK_STRING,
|
||||||
|
TOK_TOKEN,
|
||||||
|
TOK_PREPROCESSOR,
|
||||||
|
} TKN_CTX;
|
||||||
|
|
||||||
|
typedef struct Token_s {
|
||||||
|
int size;
|
||||||
|
char *data;
|
||||||
|
TKN_CTX ctx;
|
||||||
|
} Token_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int size;
|
||||||
|
Token_t *data;
|
||||||
|
} TokenList;
|
||||||
|
|
||||||
|
TokenList SeparateString(char *data) {
|
||||||
|
char* span = NULL;
|
||||||
|
char* tok = NULL;
|
||||||
|
char* tmp = NULL;
|
||||||
|
Token_t buffer[256];
|
||||||
|
tok = strtok_r(data, "\"\'", &span);
|
||||||
|
int i = 0;
|
||||||
|
buffer[i].ctx = TOK_NONE;
|
||||||
|
while (tok) {
|
||||||
|
size_t size = (span - tok);
|
||||||
|
tmp = calloc(size + 1, sizeof(char));
|
||||||
|
memcpy_s(tmp, size, tok, size);
|
||||||
|
tmp[size] = 0x00;
|
||||||
|
buffer[i].data = tmp;
|
||||||
|
buffer[i].size = size;
|
||||||
|
|
||||||
|
//printf("|%s|\n", tmp);
|
||||||
|
//free(tmp);
|
||||||
|
tok = strtok_r(NULL, "\"\'", &span);
|
||||||
|
i++;
|
||||||
|
buffer[i].ctx = TOK_STRING;
|
||||||
|
}
|
||||||
|
TokenList token_list;
|
||||||
|
token_list.data = calloc(i, sizeof(Token_t));
|
||||||
|
token_list.size = i;
|
||||||
|
return (token_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int ac, char **av) {
|
||||||
|
if (ac <= 1) {
|
||||||
|
printf("no file specified");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
char* data = LoadFile(av[1]);
|
||||||
|
TokenList tkn_lst;
|
||||||
|
//first pass on string
|
||||||
|
tkn_lst = SeparateString(data);
|
||||||
|
//second pass on ; and \n
|
||||||
|
//third pass on \t and space
|
||||||
|
|
||||||
|
char* span = NULL;
|
||||||
|
char* tmp = NULL;
|
||||||
|
char* delim = " \t\n";
|
||||||
|
char* special = ";#";
|
||||||
|
size_t size = 0;
|
||||||
|
char* tok = strtok_r(data, delim, &span);
|
||||||
|
while (tok) {
|
||||||
|
size = (span - tok);
|
||||||
|
tmp = malloc(size + 1);
|
||||||
|
memcpy_s(tmp, size, tok, size);
|
||||||
|
tmp[size] = 0x00;
|
||||||
|
printf("|%s|\n", tmp);
|
||||||
|
free(tmp);
|
||||||
|
tok = strtok_r(NULL, " \t\n", &span);
|
||||||
|
}
|
||||||
|
free(data);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
34
source/sterling_runtime_x86_64elf.nasm
Normal file
34
source/sterling_runtime_x86_64elf.nasm
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
BITS 64
|
||||||
|
CPU X64
|
||||||
|
|
||||||
|
section .text
|
||||||
|
global _start
|
||||||
|
|
||||||
|
extern sterling_runtime_init;runtime setup
|
||||||
|
extern sterling_main;user entrypoint
|
||||||
|
|
||||||
|
_start:
|
||||||
|
;Clear RBP (Recommended by the ABI to mark the outermost frame)
|
||||||
|
xor rbp, rbp
|
||||||
|
|
||||||
|
;Extract argc and argv from the stack
|
||||||
|
;[rsp] is argc, [rsp + 8] is argv[0] on 64bit
|
||||||
|
pop rdi ; rdi = argc
|
||||||
|
mov rsi, rsp ; rsi = argv (pointer to the current top of stack)
|
||||||
|
|
||||||
|
;The System V ABI requires the stack to be 16-byte aligned before a 'call'.
|
||||||
|
;The kernel starts us aligned, but our 'pop' just moved rsp by 8 bytes.
|
||||||
|
and rsp, -16
|
||||||
|
|
||||||
|
call sterling_runtime_init ;elf loader hook for the exokernel ?
|
||||||
|
|
||||||
|
;Call to the 'main' function
|
||||||
|
;Assuming signature like C: int sterling_main(int argc, char **argv)
|
||||||
|
;May change it to reflect the object file implementation
|
||||||
|
call sterling_main
|
||||||
|
|
||||||
|
; 5. Exit System Call
|
||||||
|
; sterling_main return its status in RAX. Move it to RDI for exit.
|
||||||
|
mov rdi, rax ; exit status
|
||||||
|
mov rax, 60 ; sys_exit (60 for x86_64)
|
||||||
|
syscall
|
||||||
Loading…
x
Reference in New Issue
Block a user