Просмотр исходного кода

Unscape all strings when parsing

master
FelixBrendel 7 лет назад
Родитель
Сommit
49f18d7771
6 измененных файлов: 121 добавлений и 24 удалений
  1. +24
    -10
      bin/pre.slime
  2. +0
    -1
      src/env.c
  3. +61
    -0
      src/helpers.c
  4. +1
    -0
      src/main.c
  5. +23
    -4
      src/parse.c
  6. +12
    -9
      todo.org

+ 24
- 10
bin/pre.slime Просмотреть файл

@@ -82,26 +82,40 @@ the (rest) of the last element of the sequence."
(mutate e (pair (first e) elem))) (mutate e (pair (first e) elem)))
seq) seq)


(defun incr (val)
(+ val 1))

(defun decr (val)
(- val 1))

(defun append (seq elem) (defun append (seq elem)
(extend seq (pair elem nil))) (extend seq (pair elem nil)))


(defun length (seq)
(if (nil? seq)
0
(incr (length (rest seq)))))

(defmacro n-times (@times @action) (defmacro n-times (@times @action)
(unless (<= (eval @times) 0) (unless (<= (eval @times) 0)
(eval @action) (eval @action)
(macro-define @args (pair (pair - (pair (eval @times) (pair 1 nil))) (pair @action nil)))
;; [o|o] --------------------------> [o|o] -> nil
;; | |
;; V V
;; [o|o] -> [o|o] -> [o|o]-> nil action
;; | | |
;; V V V
;; - times 1
(eval (pair n-times @args))))
(eval (list n-times (list - @times 1) @action))))

(defmacro for (@symbol @from @to :rest @for-body)
(if (< (eval @from) (eval @to))
(macro-define @op incr)
(if (> (eval @from) (eval @to))
(macro-define @op decr)
(macro-define @op nil)))
(when @op
(macro-define (eval @symbol) (eval @from))
(eval (pair prog @for-body))
(eval (extend (list for @symbol (@op @from) @to) @for-body))))


(defun range (:keys from :defaults-to 0 to) (defun range (:keys from :defaults-to 0 to)
"Returns a sequence of numbers starting with the number defined "Returns a sequence of numbers starting with the number defined
by the key 'from' and ends with the number defined in 'to'." by the key 'from' and ends with the number defined in 'to'."
(if (<= from to)
(if (< from to)
(pair from (range :from (+ 1 from) :to to)) (pair from (range :from (+ 1 from) :to to))
nil)) nil))




+ 0
- 1
src/env.c Просмотреть файл

@@ -51,7 +51,6 @@ void define_symbol(Ast_Node* symbol, Ast_Node* value, Environment* env) {
// also searching for thesymbol from the back, so we will find the // also searching for thesymbol from the back, so we will find the
// latest defined one first, but a bit messy. Later we should use // latest defined one first, but a bit messy. Later we should use
// a hashmap here. @refactor // a hashmap here. @refactor

if (env->next_index == env->capacity) { if (env->next_index == env->capacity) {
env->capacity *= 2; env->capacity *= 2;
env->keys = (char**)realloc(env->keys, env->capacity * sizeof(char*)); env->keys = (char**)realloc(env->keys, env->capacity * sizeof(char*));


+ 61
- 0
src/helpers.c Просмотреть файл

@@ -79,6 +79,67 @@ int asprintf(char *strp[], const char *fmt, ...) {
} }
// asprintf implementation end // asprintf implementation end


static char get_nibble(char c) {
if (c >= 'A' && c <= 'F')
return (c - 'a') + 10;
else if (c >= 'a' && c <= 'f')
return (c - 'A') + 10;
return (c - '0');
}

bool unescape_string(char* in) {
if (!in)
return true;

char *out = in, *p = in;
const char *int_err = nullptr;

while (*p && !int_err) {
if (*p != '\\') {
/* normal case */
*out++ = *p++;
} else {
/* escape sequence */
switch (*++p) {
case 'a': *out++ = '\a'; ++p; break;
case 'b': *out++ = '\b'; ++p; break;
case 'f': *out++ = '\f'; ++p; break;
case 'n': *out++ = '\n'; ++p; break;
case 'r': *out++ = '\r'; ++p; break;
case 't': *out++ = '\t'; ++p; break;
case 'v': *out++ = '\v'; ++p; break;

case '"':
case '\'':
case '\\':
*out++ = *p++;
case '?':
break;

case 'x':
case 'X':
if (!isxdigit(p[1]) || !isxdigit(p[2])) {
int_err = "Invalid character on hexadecimal escape.";
} else {
*out++ = (char)(get_nibble(p[1]) * 0x10 + get_nibble(p[2]));
p += 3;
}
break;

default:
int_err = "Unexpected '\\' with no escape sequence.";
break;
}
}
}

/* Set the end of string. */
*out = '\0';
if (int_err)
return false;
return true;
}

char* read_entire_file (char* filename) { char* read_entire_file (char* filename) {
char *fileContent = nullptr; char *fileContent = nullptr;
FILE *fp = fopen(filename, "r"); FILE *fp = fopen(filename, "r");


+ 1
- 0
src/main.c Просмотреть файл

@@ -3,6 +3,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> /* needed for va_list */ #include <stdarg.h> /* needed for va_list */
#include <ctype.h>
#include <math.h> #include <math.h>


#include "./helpers.c" #include "./helpers.c"


+ 23
- 4
src/parse.c Просмотреть файл

@@ -128,7 +128,18 @@ Ast_Node* parse_string(char* text, int* index_in_text) {
text[*index_in_text+string_length] = '\0'; text[*index_in_text+string_length] = '\0';


char* string = (char*)malloc(string_length*sizeof(char)+1); // plus null char char* string = (char*)malloc(string_length*sizeof(char)+1); // plus null char

if (!unescape_string(text+(*index_in_text))) {
create_error(Error_Type_Unknown_Error, create_ast_node_nil());
return nullptr;
}
strcpy(string, text+(*index_in_text)); strcpy(string, text+(*index_in_text));
/* manually copy to parse control sequences correctly */
/* int temp_index = 0; */
/* while (text+(temp_index+(*index_in_text)) != '\0') { */
/* string[temp_index++] = text[temp_index+(*index_in_text)]; */
/* } */
/* string[temp_index++] = '\0'; */


text[*index_in_text+string_length] = '"'; text[*index_in_text+string_length] = '"';


@@ -201,9 +212,13 @@ Ast_Node* parse_expression(char* text, int* index_in_text) {


while (true) { while (true) {
if (text[(*index_in_text)] == '(' || text[(*index_in_text)] == '\'' ) { if (text[(*index_in_text)] == '(' || text[(*index_in_text)] == '\'' ) {
head->value.pair->first = parse_expression(text, index_in_text);
try {
head->value.pair->first = parse_expression(text, index_in_text);
}
} else { } else {
head->value.pair->first = parse_atom(text, index_in_text);
try {
head->value.pair->first = parse_atom(text, index_in_text);
}
} }


eat_until_code(text, index_in_text); eat_until_code(text, index_in_text);
@@ -245,9 +260,13 @@ Ast_Node* parse_single_expression(char* text) {
Ast_Node* result; Ast_Node* result;
eat_until_code(text, &index_in_text); eat_until_code(text, &index_in_text);
if (text[(index_in_text)] == '(' || text[(index_in_text)] == '\'' ) if (text[(index_in_text)] == '(' || text[(index_in_text)] == '\'' )
result = parse_expression(text, &index_in_text);
try {
result = parse_expression(text, &index_in_text);
}
else else
result = parse_atom(text, &index_in_text);
try {
result = parse_atom(text, &index_in_text);
}
eat_until_code(text, &index_in_text); eat_until_code(text, &index_in_text);
if (text[(index_in_text)] == '\0') if (text[(index_in_text)] == '\0')
return result; return result;


+ 12
- 9
todo.org Просмотреть файл

@@ -330,15 +330,18 @@ set to see if we are in an errornious state.
* DONE use an enum for builtin identifiers * DONE use an enum for builtin identifiers
CLOSED: [2018-10-11 Do 17:15] CLOSED: [2018-10-11 Do 17:15]


* TODO =assert_equal_type= macro in testing
* TODO =t= ast node type, universal source of truth
* TODO backquoting
* TODO dont create new nils or builtins, but store one of each globally
* TODO make keywords unique (binary tree)
* TODO store all ast nodes in a huge arena
* TODO source code locations for errors
* TODO String error messages
* TODO Rename macro to =special= or something
* DONE Print escaped chracters correctly
CLOSED: [2018-10-27 Sa 18:16]
* TODO [#A] =t= ast node type, universal source of truth
* TODO [#A] source code locations for errors
* TODO [#A] String error messages
* TODO [#A] Rename macro to =special= or something
* TODO [#B] =assert_equal_type= macro in testing
* TODO [#B] dont create new nils or builtins, but store one of each globally
* TODO [#B] make keywords unique (binary tree)
* TODO [#B] store all ast nodes in a huge arena
* TODO [#B] Auto doc generation
* TODO [#C] backquoting
* Build-in forms [29/30] * Build-in forms [29/30]
** TODO info ** TODO info




Загрузка…
Отмена
Сохранить