Felix Brendel 7 anni fa
commit
e1c93c3c4a
12 ha cambiato i file con 483 aggiunte e 0 eliminazioni
  1. +1
    -0
      .gitignore
  2. +101
    -0
      ast.c
  3. +6
    -0
      build.sh
  4. +21
    -0
      built_ins.c
  5. +58
    -0
      env.c
  6. +60
    -0
      eval.c
  7. +3
    -0
      helpers.c
  8. +91
    -0
      io.c
  9. +67
    -0
      main.c
  10. +12
    -0
      parse.c
  11. +13
    -0
      test.lsp
  12. +50
    -0
      todo.org

+ 1
- 0
.gitignore Vedi File

@@ -0,0 +1 @@
/lisp

+ 101
- 0
ast.c Vedi File

@@ -0,0 +1,101 @@
struct Ast_Node;

typedef enum {
Ast_Node_Type_Nil,

Ast_Node_Type_Symbol,
Ast_Node_Type_Number,
Ast_Node_Type_String,

Ast_Node_Type_Cons_Cell,
Ast_Node_Type_Function,
Ast_Node_Type_Built_In_Function,
} Ast_Type;

typedef struct {
char* identifier;
} Symbol;

typedef struct {
double value;
} Number;

typedef struct {
char* value;
} String;

typedef struct {
struct Ast_Node* first;
struct Ast_Node* rest;
} Cons_Cell;

typedef struct {
Cons_Cell* regular_params;
Cons_Cell* keyword_params;
} Lambda_List;

typedef struct {
Lambda_List* parameters;
Cons_Cell* form;
} Function;

typedef struct {
char* identifier;
} Built_In_Function;

struct Ast_Node {
Ast_Type type;
union {
Symbol* symbol;
Number* number;
String* string;
Cons_Cell* cons_cell;
Function* function;
Built_In_Function* built_in_function;
} value;
};
// was forward declarated
typedef struct Ast_Node Ast_Node;


Ast_Node* create_ast_node_nil() {
Ast_Node* node = new(Ast_Node);
node->type = Ast_Node_Type_Nil;
node->value.cons_cell = NULL;
return node;
}

Ast_Node* create_ast_node_number(double number) {
Ast_Node* node = new(Ast_Node);
node->type = Ast_Node_Type_Number;
node->value.number = new(Number);
node->value.number->value = number;
return node;
}


Ast_Node* create_ast_node_symbol(char* identifier) {
Ast_Node* node = new(Ast_Node);
node->type = Ast_Node_Type_Symbol;
node->value.symbol = new(Symbol);
node->value.symbol->identifier = identifier;
return node;
}


Ast_Node* create_ast_node_built_in_function(char* identifier) {
Ast_Node* node = new(Ast_Node);
node->type = Ast_Node_Type_Built_In_Function;
node->value.built_in_function = new(Built_In_Function);
node->value.built_in_function->identifier = identifier;
return node;
}

Ast_Node* create_ast_node_pair(Ast_Node* first, Ast_Node* rest) {
Ast_Node* node = new(Ast_Node);
node->type = Ast_Node_Type_Cons_Cell;
node->value.cons_cell = new(Cons_Cell);
node->value.cons_cell->first = first;
node->value.cons_cell->rest = rest;
return node;
}

+ 6
- 0
build.sh Vedi File

@@ -0,0 +1,6 @@
clang main.c -g -o lisp --std=c99 || exit 1

echo ""
echo "--- Output Start ---"
./lisp test.lsp
echo "--- Output End ---"

+ 21
- 0
built_ins.c Vedi File

@@ -0,0 +1,21 @@
Ast_Node* built_in_add(Ast_Node* operands) {
double sum = 0;
while (operands->type == Ast_Node_Type_Cons_Cell) {
// TODO(Felix): assert type
sum += operands->value.cons_cell->first->value.number->value;
operands = operands->value.cons_cell->rest;
}

return create_ast_node_number(sum);
}

Ast_Node* built_in_substract(Ast_Node* operands) {
double diff = operands->value.cons_cell->first->value.number->value;
operands = operands->value.cons_cell->rest;
while (operands->type == Ast_Node_Type_Cons_Cell) {
// TODO(Felix): assert type
diff -= operands->value.cons_cell->first->value.number->value;
operands = operands->value.cons_cell->rest;
}
return create_ast_node_number(diff);
}

+ 58
- 0
env.c Vedi File

@@ -0,0 +1,58 @@

struct Environment {
struct Environment* parent;
int key_count;
char** keys;
Ast_Node* values;
};

typedef struct Environment Environment;

Environment* create_empty_environment() {
Environment* env = new(Environment);

env->parent = NULL;
env->key_count = 0;
env->keys = NULL;
env->values = NULL;

return env;
}

Ast_Node* lookup_symbol(Symbol* sym, Environment* env) {
for (int i = 0; i < env->key_count; ++i)
if (string_equal(env->keys[i], sym->identifier))
return env->values+i;

if (env->parent)
return lookup_symbol(sym, env->parent);

char* built_in_names[] = {
// Math stuff
"+", "-", "*", "/",
">", "<", "=",
// Conditional stuff
"if", "and", "or", "not",
// Cons stuff
"first", "rest", "pair",
// rest
"load", "define",
"lambda", "progn",
"eval", "quote",
"print", "read",
"help"
};
int built_in_count = 23;

for (int i = 0; i < built_in_count; ++i) {
if (string_equal(built_in_names[i], sym->identifier)) {
Ast_Node* ret = new(Ast_Node);
ret->type = Ast_Node_Type_Built_In_Function;
ret->value.built_in_function = new(Built_In_Function);
ret->value.built_in_function->identifier = built_in_names[i];
return ret;
}
}

return NULL;
}

+ 60
- 0
eval.c Vedi File

@@ -0,0 +1,60 @@
/* Ast_Node* apply_to_lambda () {} */

/* Ast_Node* apply_to_built_in (Ast_Node* function, Ast_Node* arguments) { */

/* } */

Ast_Node* eval_expr(Ast_Node* node, Environment* env);

void eval_operands(Ast_Node* operands, Environment* env) {
while (1) {
if (operands->type == Ast_Node_Type_Cons_Cell) {
operands->value.cons_cell->first = eval_expr(operands->value.cons_cell->first, env);
operands = operands->value.cons_cell->rest;
} else {
break;
}
}
}

Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
Ast_Node* ret = new(Ast_Node);
switch (node->type) {
case Ast_Node_Type_Nil:
ret->type = Ast_Node_Type_Nil;
return ret;
case Ast_Node_Type_Symbol:
return lookup_symbol(node->value.symbol, env);
case Ast_Node_Type_Number:
case Ast_Node_Type_String:
return node;

case Ast_Node_Type_Cons_Cell: {
Ast_Node* operator = eval_expr(node->value.cons_cell->first, env);
Ast_Node* operands = node->value.cons_cell->rest;

// check for built ins functions
if (operator->type == Ast_Node_Type_Built_In_Function) {
char* operator_name = operator->value.built_in_function->identifier;
if (string_equal("quote", operator_name)) {
return node->value.cons_cell->rest;
} else if (string_equal("+", operator_name)) {
eval_operands(operands, env);
return built_in_add(operands);
} else if (string_equal("-", operator_name)) {
eval_operands(operands, env);
return built_in_substract(operands);
} else {
log_message(Log_Level_Critical, "The operator is not yet implemented\n");
}
}

// assume it's lambda function and evaluate the operands in
// place
eval_operands(operands, env);
}

default:
return 0;
}
}

+ 3
- 0
helpers.c Vedi File

@@ -0,0 +1,3 @@
int string_equal(char* a, char* b) {
return !strcmp(a, b);
}

+ 91
- 0
io.c Vedi File

@@ -0,0 +1,91 @@
typedef enum {
Log_Level_Critical,
Log_Level_Warning,
Log_Level_Info,
Log_Level_Debug,
} Log_Level;

void log_message(Log_Level type, char* message) {
char* prefix;
switch (type) {
case Log_Level_Critical: prefix = "CRIT"; break;
case Log_Level_Warning: prefix = "WARN"; break;
case Log_Level_Info: prefix = "INFO"; break;
case Log_Level_Debug: prefix = "DBUG"; break;
}
printf("%s: %s",prefix, message);
}

char* read_entire_file (char* filename) {
char *fileContent = NULL;
FILE *fp = fopen(filename, "r");
if (fp != NULL) {
/* Go to the end of the file. */
if (fseek(fp, 0L, SEEK_END) == 0) {
/* Get the size of the file. */
long bufsize = ftell(fp);
if (bufsize == -1) {
fputs("Empty file", stderr);
goto closeFile;
}

/* Go back to the start of the file. */
if (fseek(fp, 0L, SEEK_SET) != 0) {
fputs("Error reading file", stderr);
goto closeFile;
}

/* Allocate our buffer to that size. */
fileContent = malloc(sizeof(char) * (bufsize));

/* Read the entire file into memory. */
size_t newLen = fread(fileContent, sizeof(char), bufsize, fp);
if ( ferror( fp ) != 0 ) {
fputs("Error reading file", stderr);
}
}
closeFile:
fclose(fp);
}

return fileContent;
/* Don't forget to call free() later! */
}

void print(Ast_Node* node) {
switch (node->type) {
case (Ast_Node_Type_Nil): {
printf("nil");
} break;
case (Ast_Node_Type_Number): {
printf("%f", node->value.number->value);
} break;
case (Ast_Node_Type_String): {
printf("\"%s\"", node->value.string->value);
} break;
case (Ast_Node_Type_Symbol): {
printf("%s", node->value.symbol->identifier);
} break;
case (Ast_Node_Type_Function): {
printf("[lambda]");
} break;
case (Ast_Node_Type_Built_In_Function): {
printf("[built-in-function %s]", node->value.built_in_function->identifier);
} break;
case (Ast_Node_Type_Cons_Cell): {
printf("(");
if (node->value.cons_cell->first)
print(node->value.cons_cell->first);
else
printf("nil");

printf(" . ");

if (node->value.cons_cell->rest)
print(node->value.cons_cell->rest);
else
printf("nil");
printf(")");
} break;
}
}

+ 67
- 0
main.c Vedi File

@@ -0,0 +1,67 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define new(type) (type*)malloc(sizeof(type))

#include "./helpers.c"
#include "./ast.c"
#include "./io.c"
#include "./parse.c"
#include "./built_ins.c"
#include "./env.c"
#include "./eval.c"

void test() {
// (+ 4 10)
Ast_Node* nil = create_ast_node_nil();
Ast_Node* ten = create_ast_node_number(10);
Ast_Node* four = create_ast_node_number(4);
Ast_Node* plus = create_ast_node_symbol("+");
Ast_Node* minus = create_ast_node_symbol("-");

Ast_Node* form1 = create_ast_node_pair(
plus,
create_ast_node_pair(
ten,
create_ast_node_pair(
four,
nil)));

Ast_Node* form2 = create_ast_node_pair(
plus,
create_ast_node_pair(
four,
create_ast_node_pair(
four,
nil)));

Ast_Node* root = create_ast_node_pair(
minus,
create_ast_node_pair(
form1,
create_ast_node_pair(
form2,
nil)));

print(root);
printf("\n");
Ast_Node* result = eval_expr(root, new(Environment));
print(result);
printf("\n");
}

int main (int argc, char *argv[]) {
/* if (argc > 1) { */
/* char* fileContent = read_entire_file(argv[1]); */
/* if (fileContent) { */
/* printf("File: %s\n", fileContent); */
/* } */
/* } else { */
/* printf("No source provided.\n"); */
/* } */

/* test(); */
print(parse_expression("(+ 4 7)"));
return 0;
}

+ 12
- 0
parse.c Vedi File

@@ -0,0 +1,12 @@
Ast_Node* parse_expression(char* expr) {
typedef enum {
Parser_State_Code,
Parser_State_String,
Parser_State_Comment,
} Parser_State;

// initial state is code
Parser_State current_parser_state = Parser_State_Code;

}

+ 13
- 0
test.lsp Vedi File

@@ -0,0 +1,13 @@
(+ 1 (- 100 7) 3)

(defun unpack (&rest args)
(car args))
(unpack '(1 2))

(defun add (&rest args)
(if args
(+ (first args)
(apply 'add 'args)))
0)

(add 2 123 99)

+ 50
- 0
todo.org Vedi File

@@ -0,0 +1,50 @@
* Build-in forms

- +
- -
- *
- /
- >
- <
- =

- if
- and
- or
- not

- first (car)
- rest (cdr)
- pair (cons)

- load (import)
- define

- lambda
- progn

- eval
- quote

- print
- read

- help
* Types
- Symbol
- Number
- String
- Cons-cell (list)
- lambda function lambda
- built-in function

* Arbeitsweise

1) Parse to AST
2) Start with namespace only containing the built-ins
3) every AST node has its own namespace,
inherting the one from its parent (pointer /
references) because when a function sets a
variable within an upper namespace it should
infact change the environment even if the
function exited

Caricamento…
Annulla
Salva