Merge remote-tracking branch 'origin/main' into 6-add-mechanism-to-read-and-globally-save-options

# Conflicts:
#	CMakeLists.txt
#	src/main.c
This commit is contained in:
Sven Vogel 2024-05-31 16:21:25 +02:00
commit 0c722f3635
28 changed files with 1152 additions and 301 deletions

1
.env Normal file
View File

@ -0,0 +1 @@
SDK=0.2.4-alpine-3.19.1

View File

@ -1,14 +1,14 @@
name: "Build check gemstone in SDK"
run-name: SDK build check to ${{ inputs.deploy_target }} by @${{ github.actor }}
on: [push, pull_request]
env:
SDK: 0.2.3-alpine-3.19.1
jobs:
build-check-sdk:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup repository
run: git submodule init && git submodule update
- name: Setup SDK
run: docker pull servostar/gemstone:sdk-"$SDK" && docker build --tag gemstone:devkit-"$SDK" .
run: source ./.env && docker pull servostar/gemstone:sdk-"$SDK"
- name: Compile
run: docker run gemstone:devkit-"$SDK" sh run-check-test.sh
run: set -a && source ./.env && sh run-docker-build.sh

View File

@ -61,11 +61,18 @@ set(YACC_SOURCE_FILE ${PROJECT_SOURCE_DIR}/src/yacc/parser.y)
set(YACC_GENERATED_SOURCE_FILE ${PROJECT_SOURCE_DIR}/src/yacc/parser.tab.c)
add_custom_command(OUTPUT ${YACC_GENERATED_SOURCE_FILE}
COMMAND yacc
COMMAND bison
ARGS -Wno-yacc -Wcounterexamples -d -o ${YACC_GENERATED_SOURCE_FILE} ${YACC_SOURCE_FILE}
COMMENT "generate C source file for parser"
VERBATIM)
# ------------------------------------------------ #
# Setup Glib 2.0 #
# ------------------------------------------------ #
find_package(PkgConfig REQUIRED)
pkg_search_module(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
# ------------------------------------------------ #
# TOML-C99 #
# ------------------------------------------------ #
@ -84,17 +91,21 @@ set_target_properties(tomlc99
include_directories(${PROJECT_SOURCE_DIR}/dep/tomlc99)
# ------------------------------------------------ #
# Source #
# ------------------------------------------------ #
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(PRIVATE ${GLIB_INCLUDE_DIRS})
file(GLOB_RECURSE SOURCE_FILES src/*.c)
# define default compile flags
if (MSVC)
set(FLAGS /Wall /W3 /permissive)
else()
set(FLAGS -Wall -Wextra -Wconversion -Wpedantic)
set(FLAGS -Wall -Wextra -Wpedantic)
endif()
# ------------------------------------------------ #
@ -111,6 +122,8 @@ set_target_properties(release
OUTPUT_NAME "gsc"
RUNTIME_OUTPUT_DIRECTORY ${GEMSTONE_BINARY_DIR}/release)
target_link_libraries(release PkgConfig::GLIB)
target_link_libraries(release tomlc99)
# FIXME: cannot compile with /O2 because of /RTC1 flag
@ -145,6 +158,8 @@ set_target_properties(debug
OUTPUT_NAME "gsc"
RUNTIME_OUTPUT_DIRECTORY ${GEMSTONE_BINARY_DIR}/debug)
target_link_libraries(debug PkgConfig::GLIB)
target_link_libraries(debug tomlc99)
if (MSVC)
@ -176,6 +191,8 @@ set_target_properties(check
OUTPUT_NAME "gsc"
RUNTIME_OUTPUT_DIRECTORY ${GEMSTONE_BINARY_DIR}/check)
target_link_libraries(check PkgConfig::GLIB)
target_link_libraries(check tomlc99)
if (MSVC)

View File

@ -1,6 +1,6 @@
FROM servostar/gemstone:sdk-0.2.3-alpine-3.19.1
FROM servostar/gemstone:sdk-0.2.4-alpine-3.19.1
LABEL authors="servostar"
LABEL version="0.2.3"
LABEL version="0.2.4"
LABEL description="docker image for setting up the build pipeline on SDK"
LABEL website="https://github.com/Servostar/gemstone"
@ -8,5 +8,7 @@ COPY --chown=lorang src /home/lorang/src
COPY --chown=lorang tests /home/lorang/tests
COPY --chown=lorang CMakeLists.txt /home/lorang/
COPY --chown=lorang run-check-test.sh /home/lorang/
COPY --chown=lorang .env /home/lorang/
COPY --chown=lorang run-docker-build.sh /home/lorang/
RUN cmake .

View File

@ -9,6 +9,8 @@ echo "+--------------------------------------+"
echo "| BUILDING all TARGETS |"
echo "+--------------------------------------+"
cmake .
make -B
if [ ! $? -eq 0 ]; then
echo "===> failed to build targets"

58
run-docker-build.sh Executable file
View File

@ -0,0 +1,58 @@
#!/usr/bin/env sh
# Author: Sven Vogel
# Created: 17.05.2024
# Description: Builds the Dockerfile for SDK and DEVKIT
echo "+--------------------------------------+"
echo "| CHECKING prelude |"
echo "+--------------------------------------+"
if [ -z "$SDK" ]; then
echo "no SDK specified, sourcing .env"
source ./.env
if [ -z "$SDK" ]; then
echo "no SDK specified"
exit 1
else
echo "using SDK $SDK"
fi
else
echo "using SDK $SDK"
fi
echo "+--------------------------------------+"
echo "| BUILDING SDK |"
echo "+--------------------------------------+"
docker build --tag servostar/gemstone:sdk-"$SDK" sdk/.
if [ ! $? -eq 0 ]; then
echo "===> failed to build sdk"
exit 1
fi
echo "+--------------------------------------+"
echo "| BUILDING DEVKIT |"
echo "+--------------------------------------+"
docker build --tag servostar/gemstone:devkit-"$SDK" .
if [ ! $? -eq 0 ]; then
echo "===> failed to build devkit"
exit 1
fi
echo "+--------------------------------------+"
echo "| RUNNING check test |"
echo "+--------------------------------------+"
docker run servostar/gemstone:devkit-"$SDK" sh run-check-test.sh
if [ ! $? -eq 0 ]; then
echo "===> failed to run build or checks"
exit 1
fi
echo "+--------------------------------------+"
echo "| DONE |"
echo "+--------------------------------------+"

View File

@ -1,11 +1,11 @@
FROM alpine:3.19.1
LABEL authors="servostar"
LABEL version="0.2.3"
LABEL version="0.2.4"
LABEL description="base image for building the gemstone programming language compiler"
LABEL website="https://github.com/Servostar/gemstone"
# install dependencies
RUN apk add build-base gcc make cmake bison flex git python3 graphviz
RUN apk add build-base gcc make cmake bison flex git python3 graphviz glib glib-dev
# create user for build
RUN adduser --disabled-password lorang

View File

@ -5,7 +5,7 @@
#include <sys/log.h>
#include <assert.h>
struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value) {
struct AST_Node_t *AST_new_node(TokenLocation location, enum AST_SyntaxElement_t kind, const char* value) {
DEBUG("creating new AST node: %d \"%s\"", kind, value);
assert(kind < AST_ELEMENT_COUNT);
@ -23,6 +23,7 @@ struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value
node->child_count = 0;
node->kind = kind;
node->value = value;
node->location = location;
return node;
}
@ -33,8 +34,8 @@ void AST_init() {
DEBUG("initializing global syntax tree...");
INFO("filling lookup table...");
lookup_table[AST_Stmt] = "stmt";
lookup_table[AST_Module] = "module";
lookup_table[AST_Expr] = "expr";
lookup_table[AST_Add] = "+";
@ -69,9 +70,20 @@ void AST_init() {
lookup_table[AST_Box] = "box";
lookup_table[AST_Fun] = "fun";
lookup_table[AST_Typecast] = "cast";
lookup_table[AST_Transmute] = "as";
lookup_table[AST_Call] = "funcall";
lookup_table[AST_Typecast] = "typecast";
lookup_table[AST_Transmute] = "transmute";
lookup_table[AST_Condition] = "condition";
lookup_table[AST_List] = "list";
lookup_table[AST_ExprList] = "expr list";
lookup_table[AST_ArgList] = "arg list";
lookup_table[AST_ParamList] = "param list";
lookup_table[AST_StmtList] = "stmt list";
lookup_table[AST_IdentList] = "ident list";
lookup_table[AST_Type] = "type";
lookup_table[AST_Negate] = "-";
lookup_table[AST_Parameter] = "parameter";
lookup_table[AST_ParamDecl] = "parameter-declaration";
}
const char* AST_node_to_string(const struct AST_Node_t* node) {
@ -87,7 +99,11 @@ const char* AST_node_to_string(const struct AST_Node_t* node) {
case AST_Ident:
case AST_Macro:
case AST_Import:
case AST_Call:
case AST_Storage:
case AST_Typekind:
case AST_Sign:
case AST_Scale:
case AST_Qualifyier:
string = node->value;
break;
default:
@ -99,6 +115,14 @@ const char* AST_node_to_string(const struct AST_Node_t* node) {
return string;
}
static inline unsigned long int min(unsigned long int a, unsigned long int b) {
return a > b ? b : a;
}
static inline unsigned long int max(unsigned long int a, unsigned long int b) {
return a > b ? a : b;
}
void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child) {
DEBUG("Adding new node %p to %p", child, owner);
assert(owner != NULL);
@ -119,6 +143,12 @@ void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child) {
PANIC("failed to allocate children array of AST node");
}
owner->location.col_end = max(owner->location.col_end, child->location.col_end);
owner->location.line_end = max(owner->location.line_end, child->location.line_end);
owner->location.col_start = min(owner->location.col_start, child->location.col_start);
owner->location.line_start = min(owner->location.line_start, child->location.line_start);
assert(owner->children != NULL);
owner->children[owner->child_count++] = child;

View File

@ -3,6 +3,7 @@
#define _AST_H_
#include <stdio.h>
#include <io/files.h>
/**
* @brief The type of a AST node
@ -12,6 +13,7 @@
*/
enum AST_SyntaxElement_t {
AST_Stmt = 0,
AST_Module,
AST_Expr,
// Literals
AST_Int,
@ -58,7 +60,22 @@ enum AST_SyntaxElement_t {
AST_Fun,
AST_Import,
// amount of variants
// in this enum
// in this enums
AST_List,
AST_ExprList,
AST_ArgList,
AST_ParamList,
AST_StmtList,
AST_IdentList,
AST_Storage,
AST_Type,
AST_Typekind,
AST_Sign,
AST_Scale,
AST_Negate,
AST_Parameter,
AST_Qualifyier,
AST_ParamDecl,
AST_ELEMENT_COUNT
};
@ -78,6 +95,8 @@ struct AST_Node_t {
// optional value: integer literal, string literal, ...
const char* value;
TokenLocation location;
// number of child nodes ownd by this node
// length of children array
size_t child_count;
@ -117,7 +136,7 @@ const char* AST_node_to_string(const struct AST_Node_t* node);
[[maybe_unused]]
[[nodiscard("pointer must be freed")]]
[[gnu::returns_nonnull]]
struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value);
struct AST_Node_t *AST_new_node(TokenLocation location, enum AST_SyntaxElement_t kind, const char* value);
/**
* @brief Deallocate this node and all of its children.

235
src/io/files.c Normal file
View File

@ -0,0 +1,235 @@
//
// Created by servostar on 5/30/24.
//
#include <io/files.h>
#include <sys/log.h>
#include <assert.h>
#include <sys/col.h>
ModuleFile *push_file(ModuleFileStack *stack, const char *path) {
assert(stack != NULL);
// lazy init of heap stack
if (stack->files == NULL) {
stack->files = g_array_new(FALSE, FALSE, sizeof(ModuleFile));
}
ModuleFile new_file = {
.path = path,
.handle = NULL
};
g_array_append_val(stack->files, new_file);
return ((ModuleFile *) stack->files->data) + stack->files->len - 1;
}
void delete_files(ModuleFileStack *stack) {
for (size_t i = 0; i < stack->files->len; i++) {
ModuleFile *file = ((ModuleFile *) stack->files->data) + i;
if (file->handle != NULL) {
DEBUG("closing file: %s", file->path);
fclose(file->handle);
}
}
g_array_free(stack->files, TRUE);
DEBUG("deleted module file stack");
}
#define SEEK_BUF_BYTES 256
static inline unsigned long int min(unsigned long int a, unsigned long int b) {
return a > b ? b : a;
}
// behaves like fgets except that it has defined behavior when n == 1
static void custom_fgets(char *buffer, size_t n, FILE *stream) {
if (n == 1) {
buffer[0] = (char) fgetc(stream);
buffer[1] = 0;
} else {
fgets(buffer, (int) n, stream);
}
}
void print_diagnostic(ModuleFile *file, TokenLocation *location, Message kind, const char *message) {
assert(file->handle != NULL);
assert(location != NULL);
assert(message != NULL);
// reset to start
rewind(file->handle);
char *buffer = alloca(SEEK_BUF_BYTES);
unsigned long int line_count = 1;
// seek to first line
while (line_count < location->line_start && fgets(buffer, SEEK_BUF_BYTES, file->handle) != NULL) {
line_count += strchr(buffer, '\n') != NULL;
}
const char *accent_color = RESET;
const char *kind_text = "unknown";
switch (kind) {
case Info:
kind_text = "info";
accent_color = CYAN;
file->statistics.info_count++;
break;
case Warning:
kind_text = "warning";
accent_color = YELLOW;
file->statistics.warning_count++;
break;
case Error:
kind_text = "error";
accent_color = RED;
file->statistics.error_count++;
break;
}
char absolute_path[PATH_MAX];
realpath(file->path, absolute_path);
printf("%s%s:%ld:%s %s%s:%s %s\n", BOLD, absolute_path, location->line_start, RESET, accent_color, kind_text, RESET,
message);
size_t lines = location->line_end - location->line_start + 1;
for (size_t l = 0; l < lines; l++) {
printf(" %4ld | ", location->line_start + l);
size_t limit;
size_t chars = 0;
// print line before token group start
limit = min(location->col_start, SEEK_BUF_BYTES);
while (limit > 1) {
custom_fgets(buffer, (int) limit, file->handle);
chars += printf("%s", buffer);
limit = min(location->col_start - chars, SEEK_BUF_BYTES);
if (strchr(buffer, '\n') != NULL) {
goto cont;
}
}
printf("%s", accent_color);
chars = 0;
limit = min(location->col_end - location->col_start + 1, SEEK_BUF_BYTES);
while (limit > 0) {
custom_fgets(buffer, (int) limit, file->handle);
chars += printf("%s", buffer);
limit = min(location->col_end - location->col_start + 1 - chars, SEEK_BUF_BYTES);
if (strchr(buffer, '\n') != NULL) {
goto cont;
}
}
printf("%s", RESET);
// print rest of the line
do {
custom_fgets(buffer, SEEK_BUF_BYTES, file->handle);
printf("%s", buffer);
} while (strchr(buffer, '\n') == NULL);
cont:
printf("%s", RESET);
}
printf(" | ");
for (size_t i = 1; i < location->col_start; i++) {
printf(" ");
}
printf("%s", accent_color);
printf("^");
for (size_t i = 0; i < location->col_end - location->col_start; i++) {
printf("~");
}
printf("%s\n\n", RESET);
}
TokenLocation new_location(unsigned long int line_start, unsigned long int col_start, unsigned long int line_end,
unsigned long int col_end) {
TokenLocation location;
location.line_start = line_start;
location.line_end = line_end;
location.col_start = col_start;
location.col_end = col_end;
return location;
}
TokenLocation empty_location(void) {
TokenLocation location;
location.line_start = 0;
location.line_end = 0;
location.col_start = 0;
location.col_end = 0;
return location;
}
void print_file_statistics(ModuleFile *file) {
if (file->statistics.info_count + file->statistics.warning_count + file->statistics.error_count < 1) {
return;
}
printf("File %s generated ", file->path);
if (file->statistics.info_count > 0) {
printf("%ld notice(s) ", file->statistics.info_count);
}
if (file->statistics.warning_count > 0) {
printf("%ld warning(s) ", file->statistics.warning_count);
}
if (file->statistics.error_count > 0) {
printf("%ld error(s) ", file->statistics.error_count);
}
printf("\n\n");
}
void print_unit_statistics(ModuleFileStack *file_stack) {
FileDiagnosticStatistics stats;
stats.info_count = 0;
stats.warning_count = 0;
stats.error_count = 0;
for (size_t i = 0; i < file_stack->files->len; i++) {
ModuleFile *file = (ModuleFile *) file_stack->files->data;
stats.info_count += file->statistics.warning_count;
stats.warning_count += file->statistics.warning_count;
stats.error_count += file->statistics.error_count;
}
printf("%d files generated ", file_stack->files->len);
if (stats.info_count > 0) {
printf("%ld notice(s) ", stats.info_count);
}
if (stats.warning_count > 0) {
printf("%ld warning(s) ", stats.warning_count);
}
if (stats.error_count > 0) {
printf("%ld error(s) ", stats.error_count);
}
printf("\n\n");
}

79
src/io/files.h Normal file
View File

@ -0,0 +1,79 @@
//
// Created by servostar on 5/30/24.
//
#ifndef GEMSTONE_FILES_H
#define GEMSTONE_FILES_H
#include <stdio.h>
#include <glib.h>
typedef struct FileDiagnosticStatistics_t {
size_t error_count;
size_t warning_count;
size_t info_count;
} FileDiagnosticStatistics;
typedef struct ModuleFile_t {
const char *path;
FILE *handle;
FileDiagnosticStatistics statistics;
} ModuleFile;
typedef struct ModuleFileStack_t {
GArray *files;
} ModuleFileStack;
typedef enum Message_t {
Info,
Warning,
Error
} Message;
typedef struct TokenLocation_t {
unsigned long int line_start;
unsigned long int col_start;
unsigned long int line_end;
unsigned long int col_end;
} TokenLocation;
/**
* @brief Add a new file to the file stack.
* @attention The file handle returned will be invalid
* @param stack
* @param path
* @return A new file module
*/
[[gnu::nonnull(1), gnu::nonnull(2)]]
ModuleFile *push_file(ModuleFileStack *stack, const char *path);
/**
* @brief Delete all files in the stack and the stack itself
* @param stack
*/
[[gnu::nonnull(1)]]
void delete_files(ModuleFileStack *stack);
/**
* Create a new token location
* @param line_start
* @param col_start
* @param line_end
* @param col_end
* @return
*/
TokenLocation new_location(unsigned long int line_start, unsigned long int col_start, unsigned long int line_end,
unsigned long int col_end);
TokenLocation empty_location(void);
[[gnu::nonnull(1), gnu::nonnull(2)]]
void print_diagnostic(ModuleFile *file, TokenLocation *location, Message kind, const char *message);
[[gnu::nonnull(1)]]
void print_file_statistics(ModuleFile *file);
[[gnu::nonnull(1)]]
void print_unit_statistics(ModuleFileStack *file_stack);
#endif //GEMSTONE_FILES_H

View File

@ -52,6 +52,7 @@
"float" {DEBUG("\"%s\" tokenized with \'KeyFloat\'", yytext); return(KeyFloat);};
"self" {DEBUG("\"%s\" tokenized with \'KeySelf\'", yytext); return(KeySelf);};
"as" {DEBUG("\"%s\" tokenized with \'KeyAs'", yytext); return (KeyAs);};
"to" {DEBUG("\"%s\" tokenized with \'KeyTo'", yytext); return (KeyTo);};
"short" {DEBUG("\"%s\" tokenized with \'KeyShort\'", yytext); return(KeyShort);};
"long" {DEBUG("\"%s\" tokenized with \'KeyLong\'", yytext); return(KeyLong);};
"half" {DEBUG("\"%s\" tokenized with \'KeyHalf\'", yytext); return(KeyHalf);};
@ -91,8 +92,17 @@
[0-9]+ {DEBUG("\"%s\" tokenized with \'ValInt\'", yytext); yylval.string = strdup(yytext); return(ValInt); };
[0-9]*\.[0-9]+ {DEBUG("\"%s\" tokenized with \'ValFloat\'", yytext); yylval.string = strdup(yytext); return(ValFloat);};
[a-zA-Z_0-9]+ {DEBUG("\"%s\" tokenized with \'Ident\'", yytext); yylval.string = strdup(yytext); return(Ident); };
\"([^\"\n])*\" {DEBUG("\"%s\" tokenized with \'ValStr\'", yytext); yylval.string = strdup(yytext); return(ValStr);};
\"\"\"([^\"\n]|\\\n)*\"\"\" {DEBUG("\"%s\" tokenized with \'ValMultistr\'", yytext); yylval.string = strdup(yytext); return(ValMultistr);};
\"([^\"\n])*\" {
yytext = yytext +1;
yytext[yyleng - 2] = 0;
DEBUG("\"%s\" tokenized with \'ValStr\'", yytext); yylval.string = strdup(yytext); return(ValStr);};
\"\"\"([^\"\n]|\\\n)*\"\"\" {
yytext = yytext +3;
yytext[yyleng - 4] = 0;
DEBUG("\"%s\" tokenized with \'ValMultistr\'", yytext); yylval.string = strdup(yytext); return(ValMultistr);};
[ \r\t] { /* ignore whitespace */ };
. { return yytext[0]; /* passthrough unknown token, let parser handle the error */ };
%%

View File

@ -25,6 +25,16 @@ void lex_init(void) {
atexit(lex_deinit);
}
void lex_reset(void) {
eof = 0;
nRow = 0;
nBuffer = 0;
lBuffer = 0;
nTokenStart = 0;
nTokenLength = 0;
nTokenNextStart = 0;
}
void beginToken(char *t) {
nTokenStart = nTokenNextStart;
nTokenLength = (int) strlen(t);

View File

@ -16,6 +16,8 @@ extern char* buffer;
*/
void lex_init(void);
void lex_reset(void);
/**
* @brief Begin counting a new token. This will fill the global struct yylloc.
* @param t the text of the token. Must be null terminated

View File

@ -4,10 +4,52 @@
#include <yacc/parser.tab.h>
#include <sys/col.h>
#include <lex/util.h>
#include <io/files.h>
#include <assert.h>
#define LOG_LEVEL LOG_LEVEL_DEBUG
extern void yyrestart(FILE *);
extern FILE *yyin;
[[maybe_unused]]
AST_NODE_PTR root;
[[maybe_unused]]
ModuleFile *current_file;
/**
* @brief Compile the specified file into AST
* @param ast
* @param file
* @return EXIT_SUCCESS in case the parsing was success full anything lese if not
*/
[[nodiscard("AST may be in invalid state")]]
[[gnu::nonnull(1), gnu::nonnull(1)]]
static size_t compile_file_to_ast(AST_NODE_PTR ast, ModuleFile *file) {
assert(file->path != NULL);
assert(ast != NULL);
file->handle = fopen(file->path, "r");
if (file->handle == NULL) {
INFO("unable to open file: %s", file->path);
return 1;
}
DEBUG("parsing file: %s", file->path);
// setup global state
root = ast;
current_file = file;
yyin = file->handle;
yyrestart(yyin);
lex_reset();
yyparse();
// clean up global state
// current_file = NULL;
root = NULL;
yyin = NULL;
return 0;
}
/**
* @brief Log a debug message to inform about beginning exit procedures
@ -15,16 +57,15 @@ extern FILE *yyin;
*/
void notify_exit(void) { DEBUG("Exiting gemstone..."); }
/**
* @brief Closes File after compiling.
*
*/
void close_file(void) {
if (NULL != yyin) {
fclose(yyin);
}
if (NULL != yyin) {
fclose(yyin);
}
}
/**
@ -32,46 +73,62 @@ void close_file(void) {
*
*/
void setup(void) {
// setup preample
log_init();
DEBUG("starting gemstone...");
// setup preample
log_init();
DEBUG("starting gemstone...");
#if LOG_LEVEL <= LOG_LEVEL_DEBUG
atexit(&notify_exit);
atexit(&notify_exit);
#endif
// actual setup
AST_init();
// actual setup
AST_init();
col_init();
col_init();
lex_init();
lex_init();
DEBUG("finished starting up gemstone...");
DEBUG("finished starting up gemstone...");
}
int main(int argc, char *argv[]) {
setup();
atexit(close_file);
setup();
atexit(close_file);
// Check for file input as argument
if (2 != argc) {
INFO("Usage: %s <filename>\n", argv[0]);
PANIC("No File could be found");
}
ModuleFileStack files;
files.files = NULL;
// filename as first argument
char *filename = argv[1];
for (int i = 1; i < argc; i++) {
printf("Compiling file: %s\n\n", argv[i]);
FILE *file = fopen(filename, "r");
TokenLocation location = {
.line_start = 0,
.line_end = 0,
.col_start = 0,
.col_end = 0
};
AST_NODE_PTR ast = AST_new_node(location, AST_Module, NULL);
ModuleFile *file = push_file(&files, argv[i]);
if (NULL == file) {
PANIC("File couldn't be opened!");
}
yyin = file;
if (compile_file_to_ast(ast, file) == EXIT_SUCCESS) {
// TODO: parse AST to semantic values
// TODO: backend codegen
}
yyparse();
AST_delete_node(ast);
return 0;
print_file_statistics(file);
}
if (files.files == NULL) {
printf("No input files, nothing to do.\n\n");
exit(1);
}
print_unit_statistics(&files);
delete_files(&files);
return 0;
}

View File

@ -1,9 +1,13 @@
%locations
%define parse.error verbose
%{
%code requires {
#include <sys/log.h>
#include <ast/ast.h>
#include <sys/col.h>
#include <io/files.h>
extern int yylineno;
extern ModuleFile* current_file;
int yyerror(const char*);
@ -11,16 +15,66 @@
extern int yylineno;
extern int yylex();
%}
extern AST_NODE_PTR root;
#define new_loc() new_location(yylloc.first_line, yylloc.first_column, yylloc.last_line, yylloc.last_column)
}
%union {
char *string;
AST_NODE_PTR node_ptr;
}
%type <node_ptr> operation
%type <node_ptr> boxaccess
%type <node_ptr> boxselfaccess
%type <node_ptr> statement
%type <node_ptr> statementlist
%type <node_ptr> assign
%type <node_ptr> oparith
%type <node_ptr> decl
%type <node_ptr> definition
%type <node_ptr> while
%type <node_ptr> funcall
%type <node_ptr> boxcall
%type <node_ptr> branchhalf
%type <node_ptr> branchfull
%type <node_ptr> branchelse
%type <node_ptr> branchelseif
%type <node_ptr> branchif
%type <node_ptr> type
%type <node_ptr> identlist
%type <node_ptr> storagequalifier
%type <node_ptr> typekind
%type <node_ptr> scale
%type <node_ptr> sign
%type <node_ptr> expr
%type <node_ptr> oplogic
%type <node_ptr> opbool
%type <node_ptr> opbit
%type <node_ptr> moduleimport
%type <node_ptr> programbody
%type <node_ptr> fundef
%type <node_ptr> box
%type <node_ptr> typedef
%type <node_ptr> exprlist
%type <node_ptr> argumentlist
%type <node_ptr> paramlist
%type <node_ptr> params
%type <node_ptr> IOqualifyier
%type <node_ptr> paramdecl
%type <node_ptr> boxbody
%type <node_ptr> boxcontent
%type <node_ptr> typecast
%type <node_ptr> reinterpretcast
%type <node_ptr> program
%token KeyInt
%token KeyFloat
%token KeySelf
%token KeyAs
%token KeyTo
%token <string> ValInt
%token <string> Ident
%token <string> ValFloat
@ -64,235 +118,412 @@
%token Invalid
/* Operator associativity */
/* Operators at lower line number have lower precedence */
/* Operators in same line have same precedence */
%right '='
%left '+' '-' '*' '/'
%left OpEquals OpNot '<' '>'
%left OpAnd OpOr OpXor
%left OpBitand OpBitor OpBitxor OpBitnot
%left OpOr
%left OpXor
%left OpAnd
%left OpBitor
%left OpBitxor
%left OpBitand
%left OpEquals '<' '>'
%left '+' '-'
%left '*' '/'
%left OpNot OpBitnot
%left KeyAs KeyTo
%left '(' ')'
%%
program: program programbody
| programbody;
program: program programbody {AST_push_node(root, $2);}
| programbody {AST_push_node(root, $1);};
programbody: moduleimport
| fundef
| box
| definition
| decl
| typedef;
programbody: moduleimport {$$ = $1;}
| fundef{$$ = $1;}
| box{$$ = $1;}
| definition{$$ = $1;}
| decl{$$ = $1;}
| typedef{$$ = $1;};
expr: ValFloat
| ValInt
| ValMultistr
| ValStr
| Ident
| operation
| boxaccess
| boxselfaccess;
expr: ValFloat {$$ = AST_new_node(new_loc(), AST_Float, $1);}
| ValInt {$$ = AST_new_node(new_loc(), AST_Int, $1);}
| ValMultistr {$$ = AST_new_node(new_loc(), AST_String, $1);}
| ValStr {$$ = AST_new_node(new_loc(), AST_String, $1);}
| Ident {$$ = AST_new_node(new_loc(), AST_Ident, $1);}
| operation {$$ = $1;}
| boxaccess {$$ = $1;}
| boxselfaccess{$$ = $1;}
| typecast{$$ = $1;}
| reinterpretcast{$$ = $1;}
| '(' expr ')' {$$=$2;}
exprlist: expr ',' exprlist
| expr;
exprlist: expr ',' exprlist {AST_push_node($3, $1);
$$ = $3;}
| expr {AST_NODE_PTR list = AST_new_node(new_loc(), AST_ExprList, NULL);
AST_push_node(list, $1);
$$ = list;};
argumentlist: argumentlist '(' exprlist ')'
| ;
argumentlist: argumentlist '(' exprlist ')' {AST_push_node($1, $3);
$$ = $1;}
| '(' exprlist ')'{AST_NODE_PTR list = AST_new_node(new_loc(), AST_ArgList, NULL);
AST_push_node(list, $2);
$$ = list;}
| argumentlist '(' ')'
| '(' ')'{AST_NODE_PTR list = AST_new_node(new_loc(), AST_ArgList, NULL);
$$ = list;};
fundef: KeyFun Ident paramlist '{' statementlist'}' { DEBUG("Function");};
fundef: KeyFun Ident paramlist '{' statementlist'}' {AST_NODE_PTR fun = AST_new_node(new_loc(), AST_Fun, NULL);
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $2);
AST_push_node(fun, ident);
AST_push_node(fun, $3);
AST_push_node(fun, $5);
$$ = fun;
DEBUG("Function");};
paramlist: paramlist '(' params ')'
| paramlist '(' ')'
| '(' params ')'
| '(' ')';
paramlist: paramlist '(' params ')' {AST_push_node($1, $3);
$$ = $1;}
| paramlist '(' ')'{$$ = $1;}
| '(' params ')' {AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL);
AST_push_node(list, $2);
$$ = list;}
| '(' ')' {$$ = AST_new_node(new_loc(), AST_List, NULL);};
params: IOqualifyier paramdecl ',' params
| IOqualifyier paramdecl;
params: IOqualifyier paramdecl ',' params {AST_NODE_PTR parameter = AST_new_node(new_loc(), AST_Parameter, NULL);
AST_push_node(parameter, $1);
AST_push_node(parameter, $2);
AST_push_node($4, parameter);
$$ = $4;}
| IOqualifyier paramdecl {AST_NODE_PTR list = AST_new_node(new_loc(), AST_ParamList, NULL);
AST_NODE_PTR parameter = AST_new_node(new_loc(), AST_Parameter, NULL);
AST_push_node(parameter, $1);
AST_push_node(parameter, $2);
AST_push_node(list, parameter);
$$ = list;};
IOqualifyier: KeyIn
| KeyOut
| KeyIn KeyOut
| KeyOut KeyIn
| ;
IOqualifyier: KeyIn { AST_NODE_PTR in = AST_new_node(new_loc(), AST_Qualifyier, "in");
AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL);
AST_push_node(list, in);
$$ = list;}
| KeyOut{ AST_NODE_PTR out = AST_new_node(new_loc(), AST_Qualifyier, "out");
AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL);
AST_push_node(list, out);
$$ = list;}
| KeyIn KeyOut{ AST_NODE_PTR in = AST_new_node(new_loc(), AST_Qualifyier, "in");
AST_NODE_PTR out = AST_new_node(new_loc(), AST_Qualifyier, "out");
AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL);
AST_push_node(list, in);
AST_push_node(list, out);
$$ = list;}
| KeyOut KeyIn{ AST_NODE_PTR in = AST_new_node(new_loc(), AST_Qualifyier, "in");
AST_NODE_PTR out = AST_new_node(new_loc(), AST_Qualifyier, "out");
AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL);
AST_push_node(list, in);
AST_push_node(list, out);
$$ = list;}
| {$$ = AST_new_node(new_loc(), AST_List, NULL);};
paramdecl: type ':' Ident { DEBUG("Param-Declaration"); };
paramdecl: type ':' Ident { AST_NODE_PTR paramdecl = AST_new_node(new_loc(), AST_ParamDecl, NULL);
AST_push_node(paramdecl, $1);
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $3);
AST_push_node(paramdecl, ident);
$$ = paramdecl;
DEBUG("Param-Declaration"); };
box: KeyType KeyBox ':' Ident '{' boxbody '}' { DEBUG("Box"); }
| KeyType KeyBox ':' Ident '{' '}';
box: KeyType KeyBox ':' Ident '{' boxbody '}' {AST_NODE_PTR box = AST_new_node(new_loc(), AST_Box, NULL);
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $4);
AST_push_node(box, ident);
AST_push_node(box, $6);
$$ = box;
DEBUG("Box"); }
| KeyType KeyBox ':' Ident '{' '}' {AST_NODE_PTR box = AST_new_node(new_loc(), AST_Box, NULL);
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $4);
AST_push_node(box, ident);
$$ = box;};
boxbody: boxbody boxcontent
| boxcontent;
boxbody: boxbody boxcontent {AST_push_node($1, $2);
$$ = $1;}
| boxcontent {AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL);
AST_push_node(list, $1);
$$ = list;};
boxcontent: decl { DEBUG("Box decl Content"); }
| definition { DEBUG("Box def Content"); }
| fundef { DEBUG("Box fun Content"); };
boxcontent: decl { $$ = $1;DEBUG("Box decl Content"); }
| definition { $$ = $1;DEBUG("Box def Content"); }
| fundef { $$ = $1;DEBUG("Box fun Content"); };
boxselfaccess: KeySelf '.' Ident
| KeySelf '.' boxaccess;
boxselfaccess: KeySelf '.' Ident {AST_NODE_PTR boxselfaccess = AST_new_node(new_loc(), AST_List, NULL);
AST_NODE_PTR self = AST_new_node(new_loc(), AST_Ident, "self");
AST_push_node(boxselfaccess, self);
AST_NODE_PTR identlist = AST_new_node(new_loc(), AST_IdentList, NULL);
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $3);
AST_push_node(identlist,ident);
AST_push_node(boxselfaccess, identlist);
$$ = boxselfaccess;}
| KeySelf '.' boxaccess {AST_NODE_PTR boxselfaccess = AST_new_node(new_loc(), AST_List, NULL);
AST_NODE_PTR self = AST_new_node(new_loc(), AST_Ident, "self");
AST_push_node(boxselfaccess, self);
AST_push_node(boxselfaccess, $3);
$$ = boxselfaccess;};
boxaccess: Ident '.' Ident
| Ident '.' boxaccess;
boxaccess: Ident '.' Ident {AST_NODE_PTR identlist = AST_new_node(new_loc(), AST_IdentList, NULL);
AST_NODE_PTR ident1 = AST_new_node(new_loc(), AST_Ident, $1);
AST_NODE_PTR ident2 = AST_new_node(new_loc(), AST_Ident, $3);
AST_push_node(identlist,ident1);
AST_push_node(identlist,ident2);
$$ = identlist;}
| Ident '.' boxaccess {AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $1);
AST_push_node($3,ident);
$$ = $3;};
boxcall: boxaccess argumentlist
| boxselfaccess argumentlist;
funcall: Ident argumentlist { DEBUG("Function call"); };
moduleimport: KeyImport ValStr { DEBUG("Module-Import"); };
statementlist: statement statementlist
| statement;
statement: assign
| decl
| definition
| while
| branch
| funcall
| boxcall;
branchif: KeyIf expr '{' statementlist '}' { DEBUG("if"); };
branchelse: KeyElse '{' statementlist '}' { DEBUG("if-else"); };
branchelseif: KeyElse KeyIf expr '{' statementlist '}' { DEBUG("else-if"); };
branchelseifs: branchelseifs branchelseif
| branchelseif;
branch: branchif branchelseifs
| branchif branchelseifs branchelse;
while: KeyWhile expr '{' statementlist '}' { DEBUG("while"); };
identlist: Ident ',' identlist
| Ident;
decl: type ':' identlist
| storagequalifier type ':' identlist
boxcall: boxaccess argumentlist {AST_NODE_PTR boxcall = AST_new_node(new_loc(), AST_Call, NULL);
AST_push_node(boxcall, $1);
AST_push_node(boxcall, $2);
$$ = boxcall;}
| boxselfaccess argumentlist {AST_NODE_PTR boxcall = AST_new_node(new_loc(), AST_Call, NULL);
AST_push_node(boxcall, $1);
AST_push_node(boxcall, $2);
$$ = boxcall;};
definition: decl '=' expr { DEBUG("Definition"); };
typecast: expr KeyAs type %prec KeyAs {AST_NODE_PTR cast = AST_new_node(new_loc(), AST_Typecast, NULL);
AST_push_node(cast, $1);
AST_push_node(cast, $3);
$$ = cast;
DEBUG("Type-Cast"); };
storagequalifier: KeyGlobal
| KeyStatic
| KeyLocal;
reinterpretcast: expr KeyTo type %prec KeyTo { AST_NODE_PTR cast = AST_new_node(new_loc(), AST_Transmute, NULL);
AST_push_node(cast, $1);
AST_push_node(cast, $3);
$$ = cast;
DEBUG("Reinterpret-Cast"); };
funcall: Ident argumentlist {AST_NODE_PTR funcall = AST_new_node(new_loc(), AST_Call, NULL);
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $1);
AST_push_node(funcall, ident);
AST_push_node(funcall, $2);
$$ = funcall;
DEBUG("Function call"); };
moduleimport: KeyImport ValStr {$$ = AST_new_node(new_loc(), AST_Import, $2);
DEBUG("Module-Import"); };
statementlist: statementlist statement {AST_push_node($1, $2);
$$ = $1;}
| statement {AST_NODE_PTR list = AST_new_node(new_loc(), AST_StmtList, NULL);
AST_push_node(list, $1);
$$ = list;};
statement: assign {$$ = $1;}
| decl {$$ = $1;}
| definition {$$ = $1;}
| while {$$ = $1;}
| branchfull {$$ = $1;}
| funcall {$$ = $1;}
| boxcall{$$ = $1;};
branchif: KeyIf expr '{' statementlist '}' { AST_NODE_PTR branch = AST_new_node(new_loc(), AST_If, NULL);
AST_push_node(branch, $2);
AST_push_node(branch, $4);
$$ = branch; };
branchelse: KeyElse '{' statementlist '}' { AST_NODE_PTR branch = AST_new_node(new_loc(), AST_Else, NULL);
AST_push_node(branch, $3);
$$ = branch; };
branchelseif: KeyElse KeyIf expr '{' statementlist '}' { AST_NODE_PTR branch = AST_new_node(new_loc(), AST_IfElse, NULL);
AST_push_node(branch, $3);
AST_push_node(branch, $5);
$$ = branch; };
branchfull: branchhalf { $$ = $1;};
|branchhalf branchelse { AST_push_node($1 , $2);
$$ = $1; }
branchhalf: branchif { AST_NODE_PTR branch = AST_new_node(new_loc(), AST_Stmt, NULL);
AST_push_node(branch, $1);
$$ = branch; }
| branchhalf branchelseif { AST_push_node($1 , $2);
$$ = $1; };
while: KeyWhile expr '{' statementlist '}' {AST_NODE_PTR whilenode = AST_new_node(new_loc(), AST_While, NULL);
AST_push_node(whilenode, $2);
AST_push_node(whilenode, $4);
$$ = whilenode;};
identlist: Ident ',' identlist {AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $1);
AST_push_node($3, ident);
$$ = $3;}
| Ident {AST_NODE_PTR list = AST_new_node(new_loc(), AST_IdentList, NULL);
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $1);
AST_push_node(list, ident);
$$ = list;};
decl: type ':' identlist {AST_NODE_PTR decl = AST_new_node(new_loc(), AST_Decl, NULL);
AST_push_node(decl, $1);
AST_push_node(decl, $3);
$$ = decl;}
| storagequalifier type ':' identlist {AST_NODE_PTR decl = AST_new_node(new_loc(), AST_Decl, NULL);
AST_push_node(decl, $1);
AST_push_node(decl, $2);
AST_push_node(decl, $4);
$$ = decl;}
definition: decl '=' expr { AST_NODE_PTR def = AST_new_node(new_loc(), AST_Def, NULL);
AST_push_node(def, $1);
AST_push_node(def, $3);
$$ = def;
DEBUG("Definition"); };
storagequalifier: KeyGlobal {$$ = AST_new_node(new_loc(), AST_Storage, "global");}
| KeyStatic {$$ = AST_new_node(new_loc(), AST_Storage, "static");}
| KeyLocal {$$ = AST_new_node(new_loc(), AST_Storage, "local");};
assign: Ident '=' expr { AST_NODE_PTR assign = AST_new_node(new_loc(), AST_Assign, NULL);
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $1);
AST_push_node(assign, ident);
AST_push_node(assign, $3);
$$ = assign;
DEBUG("Assignment"); }
assign: Ident '=' expr { DEBUG("Assignment"); }
| boxaccess '=' expr
| boxselfaccess '=' expr ;
sign: KeySigned
| KeyUnsigned;
sign: KeySigned {$$ = AST_new_node(new_loc(), AST_Sign, "signed");}
| KeyUnsigned{$$ = AST_new_node(new_loc(), AST_Sign, "unsigned");};
typedef: KeyType type':' Ident;
typedef: KeyType type':' Ident {AST_NODE_PTR typeDef = AST_new_node(new_loc(), AST_Typedef, NULL);
AST_push_node(typeDef, $2);
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $4);
AST_push_node(typeDef, ident);
$$ = typeDef;};
scale: scale KeyShort
| scale KeyHalf
| scale KeyLong
| scale KeyDouble
| KeyShort
| KeyHalf
| KeyLong
| KeyDouble;
scale: scale KeyShort {AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "short");
AST_push_node($1, shortnode);
$$ = $1;}
| scale KeyHalf {AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "half");
AST_push_node($1, shortnode);
$$ = $1;}
| scale KeyLong {AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "long");
AST_push_node($1, shortnode);
$$ = $1;}
| scale KeyDouble {AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "double");
AST_push_node($1, shortnode);
$$ = $1;}
| KeyShort {AST_NODE_PTR scale = AST_new_node(new_loc(), AST_List, NULL);
AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "short");
AST_push_node(scale, shortnode);
$$ = scale;}
| KeyHalf {AST_NODE_PTR scale = AST_new_node(new_loc(), AST_List, NULL);
AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "half");
AST_push_node(scale, shortnode);
$$ = scale;}
| KeyLong {AST_NODE_PTR scale = AST_new_node(new_loc(), AST_List, NULL);
AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "long");
AST_push_node(scale, shortnode);
$$ = scale;}
| KeyDouble {AST_NODE_PTR scale = AST_new_node(new_loc(), AST_List, NULL);
AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "double");
AST_push_node(scale, shortnode);
$$ = scale;};
typekind: Ident
| KeyInt
| KeyFloat;
typekind: Ident {$$ = AST_new_node(new_loc(), AST_Typekind, $1);}
| KeyInt {$$ = AST_new_node(new_loc(), AST_Typekind, "int");}
| KeyFloat {$$ = AST_new_node(new_loc(), AST_Typekind, "float");};
type: typekind
| scale typekind
| sign typekind
| sign scale typekind;
type: typekind {AST_NODE_PTR type = AST_new_node(new_loc(), AST_Type, NULL);
AST_push_node(type, $1);
$$ = type;}
| scale typekind {AST_NODE_PTR type = AST_new_node(new_loc(), AST_Type, NULL);
AST_push_node(type, $1);
AST_push_node(type, $2);
$$ = type;}
| sign typekind {AST_NODE_PTR type = AST_new_node(new_loc(), AST_Type, NULL);
AST_push_node(type, $1);
AST_push_node(type, $2);
$$ = type;}
| sign scale typekind {AST_NODE_PTR type = AST_new_node(new_loc(), AST_Type, NULL);
AST_push_node(type, $1);
AST_push_node(type, $2);
AST_push_node(type, $3);
$$ = type;};
operation: oparith
| oplogic
| opbool
| opbit;
operation: oparith {$$ = $1;}
| oplogic {$$ = $1;}
| opbool {$$ = $1;}
| opbit {$$ = $1;};
oparith: expr '+' expr
| expr '-' expr
| expr '*' expr
| expr '/' expr
| '-' expr %prec '*';
oparith: expr '+' expr {AST_NODE_PTR add = AST_new_node(new_loc(), AST_Add, NULL);
AST_push_node(add, $1);
AST_push_node(add, $3);
$$ = add;}
| expr '-' expr {AST_NODE_PTR subtract = AST_new_node(new_loc(), AST_Sub, NULL);
AST_push_node(subtract, $1);
AST_push_node(subtract, $3);
$$ = subtract;}
| expr '*' expr {AST_NODE_PTR mul = AST_new_node(new_loc(), AST_Mul, NULL);
AST_push_node(mul, $1);
AST_push_node(mul, $3);
$$ = mul;}
| expr '/' expr {AST_NODE_PTR div = AST_new_node(new_loc(), AST_Div, NULL);
AST_push_node(div, $1);
AST_push_node(div, $3);
$$ = div;}
| '-' expr %prec '*'{AST_NODE_PTR negator = AST_new_node(new_loc(), AST_Negate, NULL);
AST_push_node(negator, $2);
$$ = negator;};
oplogic: expr OpEquals expr
| expr '<' expr
| expr '>' expr;
oplogic: expr OpEquals expr {AST_NODE_PTR equals = AST_new_node(new_loc(), AST_Eq, NULL);
AST_push_node(equals, $1);
AST_push_node(equals, $3);
$$ = equals;}
| expr '<' expr {AST_NODE_PTR less = AST_new_node(new_loc(), AST_Less, NULL);
AST_push_node(less, $1);
AST_push_node(less, $3);
$$ = less;}
| expr '>' expr{AST_NODE_PTR greater = AST_new_node(new_loc(), AST_Greater, NULL);
AST_push_node(greater, $1);
AST_push_node(greater, $3);
$$ = greater;};
opbool: expr OpAnd expr
| expr OpOr expr
| expr OpXor expr
| OpNot expr %prec OpAnd;
opbool: expr OpAnd expr {AST_NODE_PTR and = AST_new_node(new_loc(), AST_BoolAnd, NULL);
AST_push_node(and, $1);
AST_push_node(and, $3);
$$ = and;}
| expr OpOr expr{AST_NODE_PTR or = AST_new_node(new_loc(), AST_BoolOr, NULL);
AST_push_node(or, $1);
AST_push_node(or, $3);
$$ = or;}
| expr OpXor expr{AST_NODE_PTR xor = AST_new_node(new_loc(), AST_BoolXor, NULL);
AST_push_node(xor, $1);
AST_push_node(xor, $3);
$$ = xor;}
| OpNot expr %prec OpAnd{AST_NODE_PTR not = AST_new_node(new_loc(), AST_BoolNot, NULL);
AST_push_node(not, $2);
$$ = not;};
opbit: expr OpBitand expr
| expr OpBitor expr
| expr OpBitxor expr
| OpBitnot expr %prec OpBitand;
opbit: expr OpBitand expr {AST_NODE_PTR and = AST_new_node(new_loc(), AST_BitAnd, NULL);
AST_push_node(and, $1);
AST_push_node(and, $3);
$$ = and;}
| expr OpBitor expr{AST_NODE_PTR or = AST_new_node(new_loc(), AST_BitOr, NULL);
AST_push_node(or, $1);
AST_push_node(or, $3);
$$ = or;}
| expr OpBitxor expr{AST_NODE_PTR xor = AST_new_node(new_loc(), AST_BitXor, NULL);
AST_push_node(xor, $1);
AST_push_node(xor, $3);
$$ = xor;}
| OpBitnot expr %prec OpBitand{AST_NODE_PTR not = AST_new_node(new_loc(), AST_BitNot, NULL);
AST_push_node(not, $2);
$$ = not;};
%%
const char* ERROR = "error";
const char* WARNING = "warning";
const char* NOTE = "note";
int print_message(const char* kind, const char* message) {
// number of characters written
int char_count = 0;
// highlight to use
char* HIGHLIGHT = CYAN;
// convert message kind into color
if (kind == ERROR) {
HIGHLIGHT = RED;
} else if (kind == WARNING) {
HIGHLIGHT = YELLOW;
}
// print message
char_count += printf("%sfilename:%d:%d%s:%s%s %s: %s%s\n", BOLD, yylloc.first_line, yylloc.first_column, RESET, HIGHLIGHT, BOLD, kind, RESET, message);
// print line in which error occurred
char_count += printf(" %4d | ", yylloc.first_line);
for (int i = 0; i < yylloc.first_column - 1; i++) {
if (buffer[i] == '\n') {
break;
}
printf("%c", buffer[i]);
}
char_count += printf("%s%s", BOLD, HIGHLIGHT);
for (int i = yylloc.first_column - 1; i < yylloc.last_column; i++) {
if (buffer[i] == '\n') {
break;
}
char_count += printf("%c", buffer[i]);
}
char_count += printf("%s", RESET);
for (int i = yylloc.last_column; buffer[i] != '\0' && buffer[i] != '\n'; i++) {
printf("%c", buffer[i]);
}
char_count += printf("\n | ");
for (int i = 0; i < yylloc.first_column - 1; i++) {
char_count += printf(" ");
}
char_count += printf("%s^", HIGHLIGHT);
for (int i = 0; i < yylloc.last_column - yylloc.first_column; i++) {
printf("~");
}
char_count += printf("%s\n\n", RESET);
return char_count;
}
int yyerror(const char *s) {
return print_message(ERROR, s);
TokenLocation location = new_loc();
print_diagnostic(current_file, &location, Error, s);
return 0;
}

View File

@ -9,3 +9,4 @@ set(CTEST_BINARY_DIRECTORY ${PROJECT_BINARY_DIR}/tests)
add_subdirectory(logging)
add_subdirectory(input_file)
add_subdirectory(ast)
add_subdirectory(glib)

View File

@ -2,6 +2,14 @@ include(CTest)
include_directories(${PROJECT_SOURCE_DIR}/src)
# ------------------------------------------------ #
# Setup Glib 2.0 #
# ------------------------------------------------ #
find_package(PkgConfig REQUIRED)
pkg_search_module(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
include_directories(PRIVATE ${GLIB_INCLUDE_DIRS})
# ------------------------------------------------------- #
# CTEST 1
# test building the syntax tree
@ -9,11 +17,14 @@ include_directories(${PROJECT_SOURCE_DIR}/src)
add_executable(ast_build_tree
${PROJECT_SOURCE_DIR}/src/ast/ast.c
${PROJECT_SOURCE_DIR}/src/sys/log.c
${PROJECT_SOURCE_DIR}/src/io/files.c
${PROJECT_SOURCE_DIR}/src/sys/col.c
build_tree.c)
set_target_properties(ast_build_tree
PROPERTIES
OUTPUT_NAME "build_tree"
RUNTIME_OUTPUT_DIRECTORY ${GEMSTONE_BINARY_DIR}/tests/ast)
target_link_libraries(ast_build_tree PkgConfig::GLIB)
add_test(NAME ast_build_tree
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMAND python ${GEMSTONE_TEST_DIR}/ast/test_ast.py check_build_tree)
@ -25,11 +36,14 @@ add_test(NAME ast_build_tree
add_executable(ast_print_node
${PROJECT_SOURCE_DIR}/src/ast/ast.c
${PROJECT_SOURCE_DIR}/src/sys/log.c
${PROJECT_SOURCE_DIR}/src/io/files.c
${PROJECT_SOURCE_DIR}/src/sys/col.c
print_node.c)
set_target_properties(ast_print_node
PROPERTIES
OUTPUT_NAME "print_node"
RUNTIME_OUTPUT_DIRECTORY ${GEMSTONE_BINARY_DIR}/tests/ast)
target_link_libraries(ast_print_node PkgConfig::GLIB)
add_test(NAME ast_print_node
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMAND python ${GEMSTONE_TEST_DIR}/ast/test_ast.py check_print_node)
@ -41,11 +55,14 @@ add_test(NAME ast_print_node
add_executable(ast_graphviz
${PROJECT_SOURCE_DIR}/src/ast/ast.c
${PROJECT_SOURCE_DIR}/src/sys/log.c
${PROJECT_SOURCE_DIR}/src/io/files.c
${PROJECT_SOURCE_DIR}/src/sys/col.c
print_graphviz.c)
set_target_properties(ast_graphviz
PROPERTIES
OUTPUT_NAME "print_graphviz"
RUNTIME_OUTPUT_DIRECTORY ${GEMSTONE_BINARY_DIR}/tests/ast)
target_link_libraries(ast_graphviz PkgConfig::GLIB)
add_test(NAME ast_graphviz
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMAND python ${GEMSTONE_TEST_DIR}/ast/test_ast.py check_print_graphviz)

View File

@ -6,22 +6,22 @@
#include <sys/log.h>
void generate_statement(const AST_NODE_PTR stmt) {
const AST_NODE_PTR add = AST_new_node(AST_Add, NULL);
const AST_NODE_PTR add = AST_new_node(empty_location(), AST_Add, NULL);
AST_push_node(add, AST_new_node(AST_Int, "3"));
AST_push_node(add, AST_new_node(AST_Int, "6"));
AST_push_node(add, AST_new_node(empty_location(), AST_Int, "3"));
AST_push_node(add, AST_new_node(empty_location(), AST_Int, "6"));
AST_push_node(stmt, add);
}
void generate_branch(const AST_NODE_PTR stmt) {
const AST_NODE_PTR branch = AST_new_node(AST_If, NULL);
const AST_NODE_PTR gt = AST_new_node(AST_Greater, NULL);
const AST_NODE_PTR branch = AST_new_node(empty_location(), AST_If, NULL);
const AST_NODE_PTR gt = AST_new_node(empty_location(), AST_Greater, NULL);
AST_push_node(branch, gt);
AST_push_node(gt, AST_new_node(AST_Float, "2.3"));
AST_push_node(gt, AST_new_node(AST_Float, "0.79"));
AST_push_node(gt, AST_new_node(empty_location(), AST_Float, "2.3"));
AST_push_node(gt, AST_new_node(empty_location(), AST_Float, "0.79"));
AST_push_node(stmt, branch);
@ -30,7 +30,7 @@ void generate_branch(const AST_NODE_PTR stmt) {
int main(void) {
const AST_NODE_PTR root = AST_new_node(AST_Stmt, NULL);
const AST_NODE_PTR root = AST_new_node(empty_location(), AST_Stmt, NULL);
generate_branch(root);

View File

@ -7,15 +7,15 @@
int main(void) {
struct AST_Node_t* node = AST_new_node(AST_If, NULL);
struct AST_Node_t* node = AST_new_node(empty_location(), AST_If, NULL);
struct AST_Node_t* child = AST_new_node(AST_Add, NULL);
AST_push_node(child, AST_new_node(AST_Int, "43"));
AST_push_node(child, AST_new_node(AST_Int, "9"));
struct AST_Node_t* child = AST_new_node(empty_location(), AST_Add, NULL);
AST_push_node(child, AST_new_node(empty_location(), AST_Int, "43"));
AST_push_node(child, AST_new_node(empty_location(), AST_Int, "9"));
AST_push_node(node, child);
AST_push_node(node, AST_new_node(AST_Expr, NULL));
AST_push_node(node, AST_new_node(AST_Expr, NULL));
AST_push_node(node, AST_new_node(empty_location(), AST_Expr, NULL));
AST_push_node(node, AST_new_node(empty_location(), AST_Expr, NULL));
FILE* out = fopen("ast.gv", "w+");
// convert this file ^^^^^^

View File

@ -6,22 +6,22 @@
#include <sys/log.h>
void generate_statement(const AST_NODE_PTR stmt) {
const AST_NODE_PTR add = AST_new_node(AST_Add, NULL);
const AST_NODE_PTR add = AST_new_node(empty_location(), AST_Add, NULL);
AST_push_node(add, AST_new_node(AST_Int, "3"));
AST_push_node(add, AST_new_node(AST_Int, "6"));
AST_push_node(add, AST_new_node(empty_location(), AST_Int, "3"));
AST_push_node(add, AST_new_node(empty_location(), AST_Int, "6"));
AST_push_node(stmt, add);
}
void generate_branch(const AST_NODE_PTR stmt) {
const AST_NODE_PTR branch = AST_new_node(AST_If, NULL);
const AST_NODE_PTR gt = AST_new_node(AST_Greater, NULL);
const AST_NODE_PTR branch = AST_new_node(empty_location(), AST_If, NULL);
const AST_NODE_PTR gt = AST_new_node(empty_location(), AST_Greater, NULL);
AST_push_node(branch, gt);
AST_push_node(gt, AST_new_node(AST_Float, "2.3"));
AST_push_node(gt, AST_new_node(AST_Float, "0.79"));
AST_push_node(gt, AST_new_node(empty_location(), AST_Float, "2.3"));
AST_push_node(gt, AST_new_node(empty_location(), AST_Float, "0.79"));
AST_push_node(stmt, branch);
@ -32,7 +32,7 @@ int main(void) {
AST_init();
const AST_NODE_PTR root = AST_new_node(AST_Stmt, NULL);
const AST_NODE_PTR root = AST_new_node(empty_location(), AST_Stmt, NULL);
generate_branch(root);

View File

@ -8,7 +8,7 @@ int main(void) {
AST_init();
const AST_NODE_PTR node = AST_new_node(0, "value");
const AST_NODE_PTR node = AST_new_node(empty_location(), 0, "value");
for (size_t i = 0; i < AST_ELEMENT_COUNT; i++) {
// set kind

View File

@ -29,42 +29,58 @@ def run_check_print_node():
assert p.returncode == 0
assert """0 stmt
1 expr
2 value
1 module
2 expr
3 value
4 value
5 while
6 if
7 else if
8 else
9 condition
10 decl
11 assign
12 def
13 value
14 +
15 -
16 *
17 /
18 &
19 |
20 ^
21 !
22 &&
23 ||
24 ^^
25 !!
26 ==
27 >
28 <
29 cast
30 as
31 value
32 value
33 typedef
34 box
35 fun
36 value
5 value
6 while
7 if
8 else if
9 else
10 condition
11 decl
12 assign
13 def
14 value
15 +
16 -
17 *
18 /
19 &
20 |
21 ^
22 !
23 &&
24 ||
25 ^^
26 !!
27 ==
28 >
29 <
30 typecast
31 transmute
32 funcall
33 value
34 typedef
35 box
36 fun
37 value
38 list
39 expr list
40 arg list
41 param list
42 stmt list
43 ident list
44 value
45 type
46 value
47 value
48 value
49 -
50 parameter
51 value
52 parameter-declaration
""" == p.stdout

22
tests/glib/CMakeLists.txt Normal file
View File

@ -0,0 +1,22 @@
include(CTest)
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(PRIVATE ${GLIB_INCLUDE_DIRS})
find_package(PkgConfig REQUIRED)
pkg_search_module(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
# ------------------------------------------------------- #
# CTEST 1
# test Glib's hashmap
add_executable(glib_hashmap
glib_hashmap.c)
set_target_properties(glib_hashmap
PROPERTIES
OUTPUT_NAME "glib_hashmap"
RUNTIME_OUTPUT_DIRECTORY ${GEMSTONE_BINARY_DIR}/tests/glib)
target_link_libraries(glib_hashmap PkgConfig::GLIB)
add_test(NAME glib_hashmap
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMAND ${GEMSTONE_BINARY_DIR}/tests/glib/glib_hashmap)

27
tests/glib/glib_hashmap.c Normal file
View File

@ -0,0 +1,27 @@
#include <glib.h>
int main(int argc, char* argv[]) {
GHashTable* map = g_hash_table_new(g_str_hash, g_str_equal);
for (int i = 0; i < argc; i++) {
int* index = malloc(sizeof(int));
*index = i;
g_hash_table_insert(map, argv[i], index);
}
for (int i = 0; i < argc; i++) {
int* index = (int*) g_hash_table_lookup(map, argv[i]);
g_hash_table_remove(map, argv[i]);
free(index);
}
g_hash_table_destroy(map);
return 0;
}

View File

@ -2,12 +2,20 @@ include(CTest)
include_directories(${PROJECT_SOURCE_DIR}/src)
# ------------------------------------------------ #
# Setup Glib 2.0 #
# ------------------------------------------------ #
find_package(PkgConfig REQUIRED)
pkg_search_module(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
# ------------------------------------------------------- #
# CTEST 1
# test the default output of the logger
add_executable(logging_output
${PROJECT_SOURCE_DIR}/src/sys/log.c
${PROJECT_SOURCE_DIR}/src/sys/col.c
output.c)
set_target_properties(logging_output
PROPERTIES
@ -23,6 +31,7 @@ add_test(NAME logging_output
add_executable(logging_panic
${PROJECT_SOURCE_DIR}/src/sys/log.c
${PROJECT_SOURCE_DIR}/src/sys/col.c
panic.c)
set_target_properties(logging_panic
PROPERTIES
@ -38,6 +47,7 @@ add_test(NAME logging_panic
add_executable(logging_streams
${PROJECT_SOURCE_DIR}/src/sys/log.c
${PROJECT_SOURCE_DIR}/src/sys/col.c
streams.c)
set_target_properties(logging_streams
PROPERTIES
@ -53,6 +63,7 @@ add_test(NAME logging_streams
add_executable(logging_level
${PROJECT_SOURCE_DIR}/src/sys/log.c
${PROJECT_SOURCE_DIR}/src/sys/col.c
level.c)
set_target_properties(logging_level
PROPERTIES

View File

@ -3,11 +3,13 @@
//
#include "sys/log.h"
#include <sys/col.h>
#define LOG_LEVEL LOG_LEVEL_WARNING
int main(void) {
log_init();
col_init();
DEBUG("logging some debug...");
INFO("logging some info...");

View File

@ -3,9 +3,11 @@
//
#include "sys/log.h"
#include <sys/col.h>
int main(void) {
log_init();
col_init();
DEBUG("logging some debug...");
INFO("logging some info...");