Skip to content

Commit

Permalink
Added ! operator, ~ operator, and the interpreter builtins getchar, i…
Browse files Browse the repository at this point in the history
…sspace, isalpha, and isdigit.
  • Loading branch information
nicholascc committed Sep 6, 2022
1 parent d160e91 commit 45b000d
Show file tree
Hide file tree
Showing 14 changed files with 114 additions and 17 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ To compile a program, run:
```
eme source_file -o obj_file [asm_file] [llvm_ir_file]
```
This will output an object file, along with optionally an x64 assembly file and an LLVM bytecode file. Currently, Eme relies on the C standard library for interfacing with the operating system, so the recommended way to compile it is by linking it to a short C program.
This will output an object file, along with optionally an x64 assembly file and an LLVM bytecode file. Currently, Eme relies on the C standard library for interfacing with the operating system, so the recommended way to compile it is by linking it to a short C program. Note that these file paths must be not be relative.

For example, I compile my Eme programs with this file:

Expand Down
1 change: 1 addition & 0 deletions src/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ typedef enum Ast_Binary_Op_Type {
OPPLUS_EQUALS,
OPMINUS_EQUALS,

OPNOT,
OPAND,
OPOR,

Expand Down
8 changes: 8 additions & 0 deletions src/bytecode.c
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,14 @@ u32 generate_bytecode_expr(Ast_Node *node, u32 *block, Bytecode_Function *fn, Sc
result_reg,
reg_b);
}
case OPNOT: {
u32 reg_b = generate_bytecode_expr(n->operand, block, fn, scope);
Type result_type = fn->register_types.data[reg_b];
u32 result_reg = add_register(fn, result_type);
return add_unary_op_instruction(&fn->blocks.data[*block], BC_NOT,
result_reg,
reg_b);
}
default: {
print_error_message("Internal compiler error: I cannot generate bytecode for this node.", node->loc);
exit(1);
Expand Down
1 change: 1 addition & 0 deletions src/bytecode.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ typedef enum Bytecode_Instruction_Type {

BC_AND,
BC_OR,
BC_NOT,

BC_EQUALS,
BC_LESS_THAN,
Expand Down
4 changes: 2 additions & 2 deletions src/files.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include "c-utils/darray.h"
#include "errors.h"

char *concat_path(char *a, char *b, Location loc) {
char *concat_path(char *a, char *b) {
int size = 0;
while(a[size++] != 0);
int a_size = size-1;
Expand Down Expand Up @@ -85,7 +85,7 @@ void init_file_array(void) {
}

int add_file(char *root_directory, char *filename, Location loc) {
char *full_filename = concat_path(root_directory, filename, loc);
char *full_filename = concat_path(root_directory, filename);
for(int i = 0; i < files.length; i++) {
if(strcmp(full_filename, files.data[i].filename) == 0) {
return i;
Expand Down
35 changes: 34 additions & 1 deletion src/interpreter.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "interpreter.h"

#include "math.h"
#include <stdio.h>

#include "c-utils/integer.h"
#include "bytecode.h"
Expand Down Expand Up @@ -216,6 +217,16 @@ u8 *interpret_bytecode_function(Bytecode_Function fn, u8 **params) {
local[r_to_id[reg_a]] = a;
break;
}
case BC_NOT: {
u32 reg_a = inst.data.bin_op.reg_a;
u32 reg_b = inst.data.bin_op.reg_b;
Type b_type = fn.register_types.data[reg_b];
assert(b_type.reference_count == 0 && b_type.info->type == TYPE_BOOL);
u8 b = local[r_to_id[reg_b]];
u8 a = !b;
local[r_to_id[reg_a]] = a;
break;
}
case BC_EQUALS:
case BC_LESS_THAN:
case BC_LESS_THAN_EQUALS: {
Expand Down Expand Up @@ -251,7 +262,7 @@ u8 *interpret_bytecode_function(Bytecode_Function fn, u8 **params) {
local[r_to_id[reg_a]] = a;
break;


} else if(b_type.info->type == TYPE_FLOAT) {
Type conv_type;
if(can_implicitly_cast_type(b_type, c_type)) {
Expand Down Expand Up @@ -483,6 +494,28 @@ u8 *interpret_bytecode_unit(Bytecode_Unit *unit, u8 **params) {
u8 param;
memcpy(&param, params[0], sizeof(u8));
printf("%c", param);
} else if(fn->u.name == st_get_id_of("getchar", -1)) {
result = malloc(sizeof(s32));
s32 *r_s32 = (s32 *)result;
*r_s32 = (s32)getchar();
} else if(fn->u.name == st_get_id_of("isspace", -1)) {
result = malloc(sizeof(u8));
u8 *r_u8 = (u8 *)result;
char param0;
memcpy(&param0, params[0], sizeof(char));
*r_u8 = isspace(param0);
} else if(fn->u.name == st_get_id_of("isdigit", -1)) {
result = malloc(sizeof(u8));
u8 *r_u8 = (u8 *)result;
char param0;
memcpy(&param0, params[0], sizeof(char));
*r_u8 = isdigit(param0);
} else if(fn->u.name == st_get_id_of("isalpha", -1)) {
result = malloc(sizeof(u8));
u8 *r_u8 = (u8 *)result;
char param0;
memcpy(&param0, params[0], sizeof(char));
*r_u8 = isalpha(param0);
} else if(fn->u.name == st_get_id_of("exit", -1)) {
u64 param;
memcpy(&param, params[0], sizeof(u64));
Expand Down
4 changes: 2 additions & 2 deletions src/lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void print_token(Token t) {

case TOR: printf("|"); break;
case TCARET: printf("^"); break;
case TTILDA: printf("~"); break;
case TTILDE: printf("~"); break;
case TDOUBLE_OR: printf("||"); break;
case TDOUBLE_AMPERSAND: printf("&&"); break;
case TNOT: printf("!"); break;
Expand Down Expand Up @@ -404,7 +404,7 @@ Token_Array lex_string(char *to_lex, int file_id) {
t.type = TCARET;
break;
}
case '~': t.type = TTILDA; break;
case '~': t.type = TTILDE; break;
case '!': if(next_c == '=') {
t.type = TNOT_EQUALS;
i++;
Expand Down
2 changes: 1 addition & 1 deletion src/lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ typedef enum Token_Type {

TOR,
TCARET,
TTILDA,
TTILDE,
TDOUBLE_OR,
TDOUBLE_AMPERSAND,
TNOT,
Expand Down
14 changes: 14 additions & 0 deletions src/llvm_generation.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,20 @@ void generate_llvm_function(LLVMModuleRef mod, LLVMBuilderRef builder, Bytecode_
LLVMBuildStore(builder, a, r[inst.data.bin_op.reg_a]);
break;
}
case BC_NOT: {
LLVMValueRef b = LLVMBuildLoad(builder, r[inst.data.bin_op.reg_b], "");
{
Type b_type = fn.register_types.data[inst.data.bin_op.reg_b];

b = generate_llvm_cast(builder, b, b_type, BOOL_TYPE);
}

LLVMValueRef a;
a = LLVMBuildNot(builder, b, "");

LLVMBuildStore(builder, a, r[inst.data.bin_op.reg_a]);
break;
}

case BC_EQUALS:
case BC_LESS_THAN:
Expand Down
5 changes: 1 addition & 4 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,7 @@ int main(int argc, char *argv[]) {
printf("An error occurred during parsing, exiting.\n");
exit(1);
}

//printf("\n\nParsed result:\n\n");
// print_compilation_unit(main_module);


bool compilation_has_errors = false;

Bytecode_Unit *main;
Expand Down
21 changes: 19 additions & 2 deletions src/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ bool is_infix_operator(Token t) {
case TASTERISK:
case TFORWARD_SLASH:
case TMODULUS:
case TTILDE:
case TEQUALS:
case TPLUS_EQUALS:
case TMINUS_EQUALS:
Expand Down Expand Up @@ -68,6 +69,7 @@ bool is_prefix_operator(Token t) {
case TCARET:
case TDOUBLE_PLUS:
case TDOUBLE_MINUS:
case TNOT:
return true;
default:
return false;
Expand Down Expand Up @@ -238,6 +240,7 @@ Ast_Unary_Op *unary_op_to_ast(Token operator, Ast_Node *operand, bool prefix) {
case TMINUS: ast_op = OPNEGATE; break;
case TASTERISK: ast_op = OPDEREFERENCE; break;
case TCARET: ast_op = OPREFERENCE; break;
case TNOT: ast_op = OPNOT; break;
case TDOUBLE_PLUS:
if(prefix) ast_op = OPPLUS_PLUS_FIRST;
else ast_op = OPPLUS_PLUS_SECOND;
Expand Down Expand Up @@ -339,6 +342,9 @@ u8_pair infix_op_binding_power(Token_Type type) {
case TMODULUS:
return (u8_pair){25,26};

case TTILDE:
return (u8_pair){4,3};

case TDOT:
case TDOT_CARET:
case TOPEN_BRACKET:
Expand All @@ -356,6 +362,7 @@ u8 prefix_op_binding_power(Token_Type type) {
case TCARET:
case TDOUBLE_PLUS:
case TDOUBLE_MINUS:
case TNOT:
return 40;
default: assert(false && "(internal compiler error) prefix op does not exist");
}
Expand Down Expand Up @@ -480,8 +487,17 @@ Ast_Node *parse_expression(Token_Reader *r, Scope *scope, u8 min_power, bool *ne
error_unexpected_token(next);
lhs_ast = (Ast_Node *)binary_op_to_ast(lhs_ast, op, rhs_ast);
lhs_needs_semicolon = true;
} else if(op.type == TTILDE) {
Token next = peek_token(r);
if(next.type != TSYMBOL)
error_unexpected_token(next);
Ast_Node *identifier = (Ast_Node *)symbol_to_ast(next);
Token paren = peek_token(r);
if(paren.type != TOPEN_PAREN)
error_unexpected_token(paren);
lhs_ast = parse_function_call(r, scope, lhs_ast, identifier, paren, uses_bind_symbol);
} else if(op.type == TOPEN_PAREN) {
lhs_ast = (Ast_Node *)parse_function_call(r, scope, lhs_ast, op, uses_bind_symbol);
lhs_ast = (Ast_Node *)parse_function_call(r, scope, NULL, lhs_ast, op, uses_bind_symbol);
} else {
Ast_Node *rhs_ast = parse_expression(r, scope, powers.right, NULL, uses_bind_symbol);
lhs_ast = (Ast_Node *)binary_op_to_ast(lhs_ast, op, rhs_ast);
Expand All @@ -503,8 +519,9 @@ Ast_Node *parse_expression(Token_Reader *r, Scope *scope, u8 min_power, bool *ne
return lhs_ast;
}

Ast_Node *parse_function_call(Token_Reader *r, Scope *scope, Ast_Node *identifier, Token open_paren, bool *uses_bind_symbol) {
Ast_Node *parse_function_call(Token_Reader *r, Scope *scope, Ast_Node *tilde_argument, Ast_Node *identifier, Token open_paren, bool *uses_bind_symbol) {
Ast_Node_Ptr_Array args = init_Ast_Node_Ptr_Array(2);
if(tilde_argument) Ast_Node_Ptr_Array_push(&args, tilde_argument);
save_state(r);
Token first = peek_token(r);
if(first.type != TCLOSE_PAREN) {
Expand Down
3 changes: 2 additions & 1 deletion src/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
#include "ast.h"

Ast_Node *parse_expression(Token_Reader *r, Scope *scope, u8 min_power, bool *needs_semicolon, bool *uses_bind_symbol);
Ast_Node *parse_function_call(Token_Reader *r, Scope *scope, Ast_Node *function, Token open_paren, bool *uses_bind_symbol);
// tilde_argument can be the first argument of the function in a tilde-expression (e.g. arr~append(test))
Ast_Node *parse_function_call(Token_Reader *r, Scope *scope, Ast_Node *tilde_argument, Ast_Node *function, Token open_paren, bool *uses_bind_symbol);
Ast_Node *parse_any_statement(Token_Reader *r, Scope *scope, bool require_semicolon_for_expressions);
Ast_Node *parse_decl(Token_Reader *r, Scope *scope);
Ast_Node *parse_block(Token_Reader *r, Scope *parent_scope);
Expand Down
2 changes: 1 addition & 1 deletion src/type.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ void print_type_info(Type_Info t) {
}
case TYPE_UNIQUE: print_symbol(t.data.unique.name); break;
default:
printf("(unprintable type)"); break;
printf("(unprintable type)%i",t.type); break;
}
}

Expand Down
29 changes: 27 additions & 2 deletions src/type_inference.c
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,16 @@ Type infer_type_of_expr(Ast_Node *node, Scope *scope, Compilation_Unit *unit, bo
}
return op;
}
case OPNOT: {
Type op = infer_type_of_expr(n->operand, scope, unit, true, unit_poisoned);
if(op.info->type == TYPE_POISON) return POISON_TYPE;
else if(op.info->type == TYPE_BOOL && op.reference_count == 0) {
return BOOL_TYPE;
} else {
type_inference_error("I cannot use the '!' operator on a non-bool type.", n->n.loc, unit_poisoned);
return POISON_TYPE;
}
}
default: assert(false);
}
break;
Expand Down Expand Up @@ -1258,9 +1268,24 @@ Type infer_type_of_expr(Ast_Node *node, Scope *scope, Compilation_Unit *unit, bo
n->body = body;
return return_type;
} else {
free(arguments);
type_inference_error(NULL, node->loc, unit_poisoned);
printf("I cannot find a function %s with these argument types.\n", st_get_str_of(identifier));
if(n->arguments.length == 0) {
printf("I cannot find a function %s with no arguments.\n", st_get_str_of(identifier));
} else {
printf("I cannot find a function %s with arguments: ", st_get_str_of(identifier));
for(int i = 0; i < n->arguments.length; i++) {
if(i > 0) printf(", ");
if(arguments[i].type == ARGUMENT_TYPE) {
printf("type ");
print_type(arguments[i].data.type);
} else {
print_type(arguments[i].data.non_type);
}
}
printf(".\n");
}

free(arguments);
return POISON_TYPE;
}
}
Expand Down

0 comments on commit 45b000d

Please sign in to comment.