Merge branch 'main' into 41-add-parser-rules-for-casts

This commit is contained in:
SirTalksalot75 2024-05-16 08:24:19 +02:00 committed by GitHub
commit af32c32c6a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 843 additions and 167 deletions

3
.gitignore vendored
View File

@ -15,3 +15,6 @@ parser.tab.c
parser.tab.h
build
/Testing/
CTestTestfile.cmake
DartConfiguration.tcl
*.cmake

View File

@ -61,8 +61,10 @@ 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
ARGS -Wcounterexamples -d -o ${YACC_GENERATED_SOURCE_FILE} ${YACC_SOURCE_FILE}
COMMAND bison
ARGS -Wno-yacc -Wcounterexamples -d -o ${YACC_GENERATED_SOURCE_FILE} ${YACC_SOURCE_FILE}
COMMENT "generate C source file for parser"
VERBATIM)

View File

@ -33,8 +33,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 +69,20 @@ void AST_init() {
lookup_table[AST_Box] = "box";
lookup_table[AST_Fun] = "fun";
lookup_table[AST_Call] = "funcall";
lookup_table[AST_Typecast] = "cast";
lookup_table[AST_Transmute] = "as";
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 +98,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:

View File

@ -12,6 +12,7 @@
*/
enum AST_SyntaxElement_t {
AST_Stmt = 0,
AST_Module,
AST_Expr,
// Literals
AST_Int,
@ -58,7 +59,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
};

View File

@ -2,9 +2,21 @@
%{
#include <yacc/parser.tab.h>
#include <sys/log.h>
#include <lex/util.h>
int yyLineNumber = 1;
int yylex();
extern int yyerror(const char* s);
#define YY_USER_ACTION beginToken(yytext);
#define YY_INPUT(buf,result,max_size) {\
result = nextChar(buf); \
if ( result <= 0 ) \
result = YY_NULL; \
}
%}
/* disable the following functions */
@ -79,7 +91,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 */ };
%%

79
src/lex/util.c Normal file
View File

@ -0,0 +1,79 @@
#include <lex/util.h>
#include <string.h>
#include <stdlib.h>
// implementation based on:
// https://github.com/sunxfancy/flex-bison-examples/blob/master/error-handling/ccalc.c
char* buffer = NULL;
static int eof = 0;
static int nRow = 0;
static int nBuffer = 0;
static int lBuffer = 0;
static int nTokenStart = 0;
static int nTokenLength = 0;
static int nTokenNextStart = 0;
static void lex_deinit(void) {
free(buffer);
}
void lex_init(void) {
buffer = malloc(MAX_READ_BUFFER_SIZE);
atexit(lex_deinit);
}
void beginToken(char *t) {
nTokenStart = nTokenNextStart;
nTokenLength = (int) strlen(t);
nTokenNextStart = nBuffer + 1;
yylloc.first_line = nRow;
yylloc.first_column = nTokenStart;
yylloc.last_line = nRow;
yylloc.last_column = nTokenStart + nTokenLength - 1;
}
int nextChar(char *dst) {
int frc;
if (eof)
return 0;
while (nBuffer >= lBuffer) {
frc = getNextLine();
if (frc != 0) {
return 0;
}
}
dst[0] = buffer[nBuffer];
nBuffer += 1;
return dst[0] != 0;
}
int getNextLine(void) {
char *p;
nBuffer = 0;
nTokenStart = -1;
nTokenNextStart = 1;
eof = 0;
p = fgets(buffer, MAX_READ_BUFFER_SIZE, yyin);
if (p == NULL) {
if (ferror(yyin)) {
return -1;
}
eof = 1;
return 1;
}
nRow += 1;
lBuffer = (int) strlen(buffer);
return 0;
}

37
src/lex/util.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef LEX_UTIL_H_
#define LEX_UTIL_H_
#include <yacc/parser.tab.h>
#include <stdio.h>
#define MAX_READ_BUFFER_SIZE 1000
extern FILE* yyin;
extern YYLTYPE yylloc;
extern char* buffer;
/**
* @brief Initialize global state needed for the lexer
*/
void lex_init(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
*/
[[gnu::nonnull(1)]]
void beginToken(char *t);
/**
* @brief Stores the next character into the supplied buffer
* @param dst the buffer to store character in
*/
int nextChar(char *dst);
/**
* @brief Reads the next line from yyin into a global buffer
*/
int getNextLine(void);
#endif // LEX_UTIL_H_

View File

@ -2,10 +2,13 @@
#include <stdlib.h>
#include <sys/log.h>
#include <yacc/parser.tab.h>
#include <sys/col.h>
#include <lex/util.h>
#define LOG_LEVEL LOG_LEVEL_DEBUG
extern FILE *yyin;
AST_NODE_PTR root;
/**
* @brief Log a debug message to inform about beginning exit procedures
@ -41,6 +44,10 @@ void setup(void) {
// actual setup
AST_init();
col_init();
lex_init();
DEBUG("finished starting up gemstone...");
}
@ -65,7 +72,12 @@ int main(int argc, char *argv[]) {
}
yyin = file;
root = AST_new_node(AST_Module, NULL);
yyparse();
FILE *output = fopen("test.txt", "w");
AST_fprint_graphviz(output, root);
fclose(output);
AST_delete_node(root);
return 0;
}

87
src/sys/col.c Normal file
View File

@ -0,0 +1,87 @@
#include <stdlib.h>
#include <string.h>
#include <sys/col.h>
#include <sys/log.h>
#ifdef __unix__
#include <unistd.h>
#elif defined(_WIN32) || defined(WIN32)
#include <Windows.h>
#endif
char *RED;
char *YELLOW;
char *MAGENTA;
char *CYAN;
char *GREEN;
char *RESET;
char *BOLD;
char *FAINT;
void col_init(void) {
if (stdout_supports_ansi_esc()) {
enable_ansi_colors();
} else {
disable_ansi_colors();
}
}
void disable_ansi_colors() {
DEBUG("disabling ANSI escape codes");
RED = "";
YELLOW = "";
MAGENTA = "";
CYAN = "";
GREEN = "";
RESET = "";
BOLD = "";
FAINT = "";
}
void enable_ansi_colors() {
DEBUG("enabling ANSI escape codes");
RED = "\x1b[31m";
YELLOW = "\x1b[33m";
MAGENTA = "\x1b[35m";
CYAN = "\x1b[36m";
GREEN = "\x1b[32m";
RESET = "\x1b[0m";
BOLD = "\x1b[1m";
FAINT = "\x1b[2m";
}
int stdout_supports_ansi_esc() {
#ifdef __unix__
// check if TTY
if (isatty(STDOUT_FILENO)) {
const char *colors = getenv("COLORTERM");
// check if colors are set and allowed
if (colors != NULL && (strcmp(colors, "truecolor") == 0 || strcmp(colors, "24bit") == 0)) {
return ANSI_ENABLED;
}
}
#elif defined(_WIN32) || defined(WIN32)
// see:
// https://stackoverflow.com/questions/63913005/how-to-test-if-console-supports-ansi-color-codes
DWORD mode;
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if (!GetConsoleMode(hConsole, &mode)) {
ERROR("failed to get console mode");
return ANSI_ENABLED;
}
if ((mode & ENABLE_VIRTUAL_TERMINAL_INPUT) |
(mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
return ANSI_ENABLED;
}
#else
#warning "unsupported platform, ASNI escape codes disabled by default"
#endif
return ASNI_DISABLED;
}

43
src/sys/col.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef COLORS_H_
#define COLORS_H_
#define ANSI_ENABLED 1
#define ASNI_DISABLED 0
// Common escape codes
// can be used to print colored text
extern char *RED;
extern char *YELLOW;
extern char *MAGENTA;
extern char *CYAN;
extern char *GREEN;
extern char *RESET;
extern char *BOLD;
extern char *FAINT;
/**
* @brief Initialize global state
*/
void col_init(void);
/**
* @brief Enable ANSI escape codes. This will set the correct escape codes to
* the global strings above.
*/
void enable_ansi_colors();
/**
* @brief Disable ANSI escape codes. This will set all the above global strings to be empty.
*/
void disable_ansi_colors();
/**
* @brief Check if stdout may support ANSI escape codes.
* @attention This function may report escape codes to be unavailable even if they actually are.
* @return ANSI_ENABLED if escape sequences are supported ASNI_DISABLED otherwise
*/
[[nodiscard]]
int stdout_supports_ansi_esc();
#endif // COLORS_H_

View File

@ -1,16 +1,73 @@
%{
%locations
%define parse.error verbose
%code requires {
#include <sys/log.h>
#include <ast/ast.h>
#include <sys/col.h>
extern int yylineno;
int yyerror(char*);
int yyerror(const char*);
extern char* buffer;
extern int yylineno;
extern int yylex();
%}
extern AST_NODE_PTR root;
}
%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
@ -55,8 +112,11 @@
%token FunFunname
%token FunLineno
%token FunExtsupport
%token Invalid
/* Operator associativity */
/* Operators at lower line number have lower precedence */
/* Operators in same line have same precedence */
%right '='
%left OpOr
%left OpXor
@ -72,168 +132,452 @@
%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;
expr: ValFloat
| ValInt
| ValMultistr
| ValStr
| Ident
| operation
| boxaccess
| boxselfaccess
| typecast
| reinterpretcast;
exprlist: expr ',' exprlist
| expr;
argumentlist: argumentlist '(' exprlist ')'
| ;
programbody: moduleimport {$$ = $1;}
| fundef{$$ = $1;}
| box{$$ = $1;}
| definition{$$ = $1;}
| decl{$$ = $1;}
| typedef{$$ = $1;};
fundef: KeyFun Ident paramlist '{' statementlist'}' { DEBUG("Function");};
paramlist: paramlist '(' params ')'
| paramlist '(' ')'
| '(' params ')'
| '(' ')';
expr: ValFloat {$$ = AST_new_node(AST_Float, $1);}
| ValInt {$$ = AST_new_node(AST_Int, $1);}
| ValMultistr {$$ = AST_new_node(AST_String, $1);}
| ValStr {$$ = AST_new_node(AST_String, $1);}
| Ident {$$ = AST_new_node(AST_Ident, $1);}
| operation {$$ = $1;}
| boxaccess {$$ = $1;}
| boxselfaccess{$$ = $1;}
| typecast{$$ = $1;}
| reinterpretcast{$$ = $1;}
params: IOqualifyier paramdecl ',' params
| IOqualifyier paramdecl;
exprlist: expr ',' exprlist {AST_push_node($3, $1);
$$ = $3;}
| expr {AST_NODE_PTR list = AST_new_node(AST_ExprList, NULL);
AST_push_node(list, $1);
$$ = list;};
IOqualifyier: KeyIn
| KeyOut
| KeyIn KeyOut
| KeyOut KeyIn
| ;
argumentlist: argumentlist '(' exprlist ')' {AST_push_node($1, $3);
$$ = $1;}
| '(' exprlist ')'{AST_NODE_PTR list = AST_new_node(AST_ArgList, NULL);
AST_push_node(list, $2);
$$ = list;}
| argumentlist '(' ')'
| '(' ')'{AST_NODE_PTR list = AST_new_node(AST_ArgList, NULL);
$$ = list;};
typecast: expr KeyAs type %prec KeyAs { DEBUG("Type-Cast"); };
reinterpretcast: '(' type ')' expr { DEBUG("Reinterpret-Cast"); };
fundef: KeyFun Ident paramlist '{' statementlist'}' {AST_NODE_PTR fun = AST_new_node(AST_Fun, NULL);
AST_NODE_PTR ident = AST_new_node(AST_Ident, $2);
AST_push_node(fun, ident);
AST_push_node(fun, $3);
AST_push_node(fun, $5);
$$ = fun;
DEBUG("Function");};
paramdecl: type ':' Ident { DEBUG("Param-Declaration"); };
paramlist: paramlist '(' params ')' {AST_push_node($1, $3);
$$ = $1;}
| paramlist '(' ')'{$$ = $1;}
| '(' params ')' {AST_NODE_PTR list = AST_new_node(AST_List, NULL);
AST_push_node(list, $2);
$$ = list;}
| '(' ')' {$$ = AST_new_node(AST_List, NULL);};
box: KeyType KeyBox ':' Ident '{' boxbody '}' { DEBUG("Box"); }
| KeyType KeyBox ':' Ident '{' '}';
params: IOqualifyier paramdecl ',' params {AST_NODE_PTR parameter = AST_new_node(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(AST_ParamList, NULL);
AST_NODE_PTR parameter = AST_new_node(AST_Parameter, NULL);
AST_push_node(parameter, $1);
AST_push_node(parameter, $2);
AST_push_node(list, parameter);
$$ = list;};
boxbody: boxbody boxcontent
| boxcontent;
IOqualifyier: KeyIn { AST_NODE_PTR in = AST_new_node(AST_Qualifyier, "in");
AST_NODE_PTR list = AST_new_node(AST_List, NULL);
AST_push_node(list, in);
$$ = list;}
| KeyOut{ AST_NODE_PTR out = AST_new_node(AST_Qualifyier, "out");
AST_NODE_PTR list = AST_new_node(AST_List, NULL);
AST_push_node(list, out);
$$ = list;}
| KeyIn KeyOut{ AST_NODE_PTR in = AST_new_node(AST_Qualifyier, "in");
AST_NODE_PTR out = AST_new_node(AST_Qualifyier, "out");
AST_NODE_PTR list = AST_new_node(AST_List, NULL);
AST_push_node(list, in);
AST_push_node(list, out);
$$ = list;}
| KeyOut KeyIn{ AST_NODE_PTR in = AST_new_node(AST_Qualifyier, "in");
AST_NODE_PTR out = AST_new_node(AST_Qualifyier, "out");
AST_NODE_PTR list = AST_new_node(AST_List, NULL);
AST_push_node(list, in);
AST_push_node(list, out);
$$ = list;}
| {$$ = AST_new_node(AST_List, NULL);};
boxcontent: decl { DEBUG("Box decl Content"); }
| definition { DEBUG("Box def Content"); }
| fundef { DEBUG("Box fun Content"); };
paramdecl: type ':' Ident { AST_NODE_PTR paramdecl = AST_new_node(AST_ParamDecl, NULL);
AST_push_node(paramdecl, $1);
AST_NODE_PTR ident = AST_new_node(AST_Ident, $3);
AST_push_node(paramdecl, ident);
$$ = paramdecl;
DEBUG("Param-Declaration"); };
boxselfaccess: KeySelf '.' Ident
| KeySelf '.' boxaccess;
box: KeyType KeyBox ':' Ident '{' boxbody '}' {AST_NODE_PTR box = AST_new_node(AST_Box, NULL);
AST_NODE_PTR ident = AST_new_node(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(AST_Box, NULL);
AST_NODE_PTR ident = AST_new_node(AST_Ident, $4);
AST_push_node(box, ident);
$$ = box;};
boxaccess: Ident '.' Ident
| Ident '.' boxaccess;
boxbody: boxbody boxcontent {AST_push_node($1, $2);
$$ = $1;}
| boxcontent {AST_NODE_PTR list = AST_new_node(AST_List, NULL);
AST_push_node(list, $1);
$$ = list;};
boxcall: boxaccess argumentlist
| boxselfaccess argumentlist;
boxcontent: decl { $$ = $1;DEBUG("Box decl Content"); }
| definition { $$ = $1;DEBUG("Box def Content"); }
| fundef { $$ = $1;DEBUG("Box fun Content"); };
funcall: Ident argumentlist { DEBUG("Function call"); };
boxselfaccess: KeySelf '.' Ident {AST_NODE_PTR boxselfaccess = AST_new_node(AST_List, NULL);
AST_NODE_PTR self = AST_new_node(AST_Ident, "self");
AST_push_node(boxselfaccess, self);
AST_NODE_PTR identlist = AST_new_node(AST_IdentList, NULL);
AST_NODE_PTR ident = AST_new_node(AST_Ident, $3);
AST_push_node(identlist,ident);
AST_push_node(boxselfaccess, identlist);
$$ = boxselfaccess;}
| KeySelf '.' boxaccess {AST_NODE_PTR boxselfaccess = AST_new_node(AST_List, NULL);
AST_NODE_PTR self = AST_new_node(AST_Ident, "self");
AST_push_node(boxselfaccess, self);
AST_push_node(boxselfaccess, $3);
$$ = boxselfaccess;};
moduleimport: KeyImport ValStr { DEBUG("Module-Import"); };
boxaccess: Ident '.' Ident {AST_NODE_PTR identlist = AST_new_node(AST_IdentList, NULL);
AST_NODE_PTR ident1 = AST_new_node(AST_Ident, $1);
AST_NODE_PTR ident2 = AST_new_node(AST_Ident, $3);
AST_push_node(identlist,ident1);
AST_push_node(identlist,ident2);
$$ = identlist;}
| Ident '.' boxaccess {AST_NODE_PTR ident = AST_new_node(AST_Ident, $1);
AST_push_node($3,ident);
$$ = $3;};
statementlist: statement statementlist
| statement;
boxcall: boxaccess argumentlist {AST_NODE_PTR boxcall = AST_new_node(AST_Call, NULL);
AST_push_node(boxcall, $1);
AST_push_node(boxcall, $2);
$$ = boxcall;}
| boxselfaccess argumentlist {AST_NODE_PTR boxcall = AST_new_node(AST_Call, NULL);
AST_push_node(boxcall, $1);
AST_push_node(boxcall, $2);
$$ = boxcall;};
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"); };
typecast: expr KeyAs type %prec KeyAs {{AST_NODE_PTR reinterpretcast = AST_new_node(AST_reinterpretcast, NULL);
$$ = typecast;
DEBUG("Type-Cast"); };
branchelseifs: branchelseifs branchelseif
| branchelseif;
reinterpretcast: '(' type ')' expr {AST_NODE_PTR reinterpretcast = AST_new_node(AST_reinterpretcast, NULL);
$$ = reinterpretcast;
DEBUG("Reinterpret-Cast"); };
branch: branchif branchelseifs
| branchif branchelseifs branchelse;
while: KeyWhile expr '{' statementlist '}' { DEBUG("while"); };
funcall: Ident argumentlist {AST_NODE_PTR funcall = AST_new_node(AST_Call, NULL);
AST_NODE_PTR ident = AST_new_node(AST_Ident, $1);
AST_push_node(funcall, ident);
AST_push_node(funcall, $2);
$$ = funcall;
DEBUG("Function call"); };
identlist: Ident ',' identlist
| Ident;
moduleimport: KeyImport ValStr {$$ = AST_new_node(AST_Import, $2);
DEBUG("Module-Import"); };
decl: type ':' identlist
| storagequalifier type ':' identlist
statementlist: statementlist statement {AST_push_node($1, $2);
$$ = $1;}
| statement {AST_NODE_PTR list = AST_new_node(AST_StmtList, NULL);
AST_push_node(list, $1);
$$ = list;};
definition: decl '=' expr { DEBUG("Definition"); };
statement: assign {$$ = $1;}
| decl {$$ = $1;}
| definition {$$ = $1;}
| while {$$ = $1;}
| branchfull {$$ = $1;}
| funcall {$$ = $1;}
| boxcall{$$ = $1;};
storagequalifier: KeyGlobal
| KeyStatic
| KeyLocal;
branchif: KeyIf expr '{' statementlist '}' { AST_NODE_PTR branch = AST_new_node(AST_If, NULL);
AST_push_node(branch, $2);
AST_push_node(branch, $4);
$$ = branch; };
branchelse: KeyElse '{' statementlist '}' { AST_NODE_PTR branch = AST_new_node(AST_Else, NULL);
AST_push_node(branch, $3);
$$ = branch; };
branchelseif: KeyElse KeyIf expr '{' statementlist '}' { AST_NODE_PTR branch = AST_new_node(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(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(AST_While, NULL);
AST_push_node(whilenode, $2);
AST_push_node(whilenode, $4);
$$ = whilenode;};
identlist: Ident ',' identlist {AST_NODE_PTR ident = AST_new_node(AST_Ident, $1);
AST_push_node($3, ident);
$$ = $3;}
| Ident {AST_NODE_PTR list = AST_new_node(AST_IdentList, NULL);
AST_NODE_PTR ident = AST_new_node(AST_Ident, $1);
AST_push_node(list, ident);
$$ = list;};
decl: type ':' identlist {AST_NODE_PTR decl = AST_new_node(AST_Decl, NULL);
AST_push_node(decl, $1);
AST_push_node(decl, $3);
$$ = decl;}
| storagequalifier type ':' identlist {AST_NODE_PTR decl = AST_new_node(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(AST_Def, NULL);
AST_push_node(def, $1);
AST_push_node(def, $3);
$$ = def;
DEBUG("Definition"); };
storagequalifier: KeyGlobal {$$ = AST_new_node(AST_Storage, "global");}
| KeyStatic {$$ = AST_new_node(AST_Storage, "static");}
| KeyLocal {$$ = AST_new_node(AST_Storage, "local");};
assign: Ident '=' expr { AST_NODE_PTR assign = AST_new_node(AST_Assign, NULL);
AST_NODE_PTR ident = AST_new_node(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(AST_Sign, "signed");}
| KeyUnsigned{$$ = AST_new_node(AST_Sign, "unsigned");};
typedef: KeyType type':' Ident;
typedef: KeyType type':' Ident {AST_NODE_PTR typeDef = AST_new_node(AST_Typedef, NULL);
AST_push_node(typeDef, $2);
AST_NODE_PTR ident = AST_new_node(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(AST_Scale, "short");
AST_push_node($1, shortnode);
$$ = $1;}
| scale KeyHalf {AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "half");
AST_push_node($1, shortnode);
$$ = $1;}
| scale KeyLong {AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "long");
AST_push_node($1, shortnode);
$$ = $1;}
| scale KeyDouble {AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "double");
AST_push_node($1, shortnode);
$$ = $1;}
| KeyShort {AST_NODE_PTR scale = AST_new_node(AST_List, NULL);
AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "short");
AST_push_node(scale, shortnode);
$$ = scale;}
| KeyHalf {AST_NODE_PTR scale = AST_new_node(AST_List, NULL);
AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "half");
AST_push_node(scale, shortnode);
$$ = scale;}
| KeyLong {AST_NODE_PTR scale = AST_new_node(AST_List, NULL);
AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "long");
AST_push_node(scale, shortnode);
$$ = scale;}
| KeyDouble {AST_NODE_PTR scale = AST_new_node(AST_List, NULL);
AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "double");
AST_push_node(scale, shortnode);
$$ = scale;};
typekind: Ident
| KeyInt
| KeyFloat;
typekind: Ident {$$ = AST_new_node(AST_Typekind, $1);}
| KeyInt {$$ = AST_new_node(AST_Typekind, "int");}
| KeyFloat {$$ = AST_new_node(AST_Typekind, "float");};
type: typekind
| scale typekind
| sign typekind
| sign scale typekind;
type: typekind {AST_NODE_PTR type = AST_new_node(AST_Type, NULL);
AST_push_node(type, $1);
$$ = type;}
| scale typekind {AST_NODE_PTR type = AST_new_node(AST_Type, NULL);
AST_push_node(type, $1);
AST_push_node(type, $2);
$$ = type;}
| sign typekind {AST_NODE_PTR type = AST_new_node(AST_Type, NULL);
AST_push_node(type, $1);
AST_push_node(type, $2);
$$ = type;}
| sign scale typekind {AST_NODE_PTR type = AST_new_node(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(AST_Add, NULL);
AST_push_node(add, $1);
AST_push_node(add, $3);
$$ = add;}
| expr '-' expr {AST_NODE_PTR subtract = AST_new_node(AST_Sub, NULL);
AST_push_node(subtract, $1);
AST_push_node(subtract, $3);
$$ = subtract;}
| expr '*' expr {AST_NODE_PTR mul = AST_new_node(AST_Mul, NULL);
AST_push_node(mul, $1);
AST_push_node(mul, $3);
$$ = mul;}
| expr '/' expr {AST_NODE_PTR div = AST_new_node(AST_Div, NULL);
AST_push_node(div, $1);
AST_push_node(div, $3);
$$ = div;}
| '-' expr %prec '*'{AST_NODE_PTR negator = AST_new_node(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(AST_Eq, NULL);
AST_push_node(equals, $1);
AST_push_node(equals, $3);
$$ = equals;}
| expr '<' expr {AST_NODE_PTR less = AST_new_node(AST_Less, NULL);
AST_push_node(less, $1);
AST_push_node(less, $3);
$$ = less;}
| expr '>' expr{AST_NODE_PTR greater = AST_new_node(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(AST_BoolAnd, NULL);
AST_push_node(and, $1);
AST_push_node(and, $3);
$$ = and;}
| expr OpOr expr{AST_NODE_PTR or = AST_new_node(AST_BoolOr, NULL);
AST_push_node(or, $1);
AST_push_node(or, $3);
$$ = or;}
| expr OpXor expr{AST_NODE_PTR xor = AST_new_node(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(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(AST_BitAnd, NULL);
AST_push_node(and, $1);
AST_push_node(and, $3);
$$ = and;}
| expr OpBitor expr{AST_NODE_PTR or = AST_new_node(AST_BitOr, NULL);
AST_push_node(or, $1);
AST_push_node(or, $3);
$$ = or;}
| expr OpBitxor expr{AST_NODE_PTR xor = AST_new_node(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(AST_BitNot, NULL);
AST_push_node(not, $2);
$$ = not;};
%%
int yyerror(char *s) {
ERROR("%s", s);
return 0;
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);
}

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 cast
31 as
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