diff --git a/Makefile b/Makefile index 375c7c02f..b0732af98 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,9 @@ OBJ_DIR = obj SOURCES = \ $(sort \ - $(wildcard ./src/*.c)) + $(wildcard ./src/*.c)\ + $(wildcard ./src/libperipherals/*.c)\ + $(wildcard ./src/libcoreint/*.c)) INCLUDES = \ -I src \ @@ -48,7 +50,7 @@ CFLAGS ?= $(INCLUDES) -std=c99 -m32 -fdiagnostics-color=always #CFLAGS += -ffunction-sections -fdata-sections DEBUG_OPTIONS = -g3 -O0 -DDEBUG #-fsanitize=address -RELEASE_OPTIONS = -Os -Werror +RELEASE_OPTIONS = -Os # -Werror DEFINES = -DMEM_HEAP_CHUNK_SIZE=256 -DMEM_HEAP_AREA_SIZE=32768 diff --git a/src/generated.h b/src/generated.h index 75a92745a..fcd3b82d5 100644 --- a/src/generated.h +++ b/src/generated.h @@ -14,41 +14,16 @@ */ static const char* generated_source = "" -"// AST\n" -"// ECMA has no way of including files. Do we need such feature?\n" -"// EG: Not in initial version\n" -"require (leds);\n" -"\n" -"function LEDsOn () {\n" -"LEDOn (LED3);\n" -"LEDOn (LED6);\n" -"LEDOn (LED7);\n" -"LEDOn (LED4);\n" -"LEDOn (LED10);\n" -"LEDOn (LED8);\n" -"LEDOn (LED9);\n" -"LEDOn (LED5);\n" -"}\n" -"\n" -"function LEDsOff () {\n" -"LEDOff (LED3);\n" -"LEDOff (LED6);\n" -"LEDOff (LED7);\n" -"LEDOff (LED4);\n" -"LEDOff (LED10);\n" -"LEDOff (LED8);\n" -"LEDOff (LED9);\n" -"LEDOff (LED5);\n" -"}\n" -"\n" -"/*\n" -"IMHO we don't need this function in our code,\n" -"we may perform lazy LEDs initialization.\n" -"*/\n" -"// initLEDs ();\n" -"\n" "while (true) {\n" -"setTimeout (LEDsOn, 500);\n" -"setTimeout (LEDsOff, 500);\n" +"LEDToggle (LED3);\n" +"LEDToggle (LED6);\n" +"LEDToggle (LED7);\n" +"LEDToggle (LED4);\n" +"LEDToggle (LED10);\n" +"LEDToggle (LED8);\n" +"LEDToggle (LED9);\n" +"LEDToggle (LED5);\n" +"\n" +"wait(500);\n" "}\n" ; diff --git a/src/lexer.c b/src/lexer.c index 31a05df90..2f7dd4df5 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -116,55 +116,55 @@ get_char (int i) assert (file); if (buffer == NULL) + { + buffer = (char *) malloc (BUFFER_SIZE); + error = fread (buffer, 1, BUFFER_SIZE, file); + if (error < 0) + fatal (ERR_IO); + if (error == 0) + return '\0'; + if (error < BUFFER_SIZE) + memset (buffer + error, '\0', BUFFER_SIZE - error); + buffer_start = buffer; + } + + if (tail_size <= i) + { + /* We are almost at the end of the buffer. */ + if (token_start) { - buffer = (char *) malloc (BUFFER_SIZE); - error = fread (buffer, 1, BUFFER_SIZE, file); + const int token_size = buffer - token_start; + /* Whole buffer contains single token. */ + if (token_start == buffer_start) + fatal (ERR_BUFFER_SIZE); + /* Move parsed token and tail of buffer to head. */ + memmove (buffer_start, token_start, tail_size + token_size); + /* Adjust pointers. */ + token_start = buffer_start; + buffer = buffer_start + token_size; + /* Read more characters form input file. */ + error = fread (buffer + tail_size, 1, BUFFER_SIZE - tail_size - token_size, file); if (error < 0) fatal (ERR_IO); if (error == 0) return '\0'; - if (error < BUFFER_SIZE) - memset (buffer + error, '\0', BUFFER_SIZE - error); - buffer_start = buffer; + if (error < BUFFER_SIZE - tail_size - token_size) + memset (buffer + tail_size + error, '\0', + BUFFER_SIZE - tail_size - token_size - error); } - - if (tail_size <= i) + else { - /* We are almost at the end of the buffer. */ - if (token_start) - { - const int token_size = buffer - token_start; - /* Whole buffer contains single token. */ - if (token_start == buffer_start) - fatal (ERR_BUFFER_SIZE); - /* Move parsed token and tail of buffer to head. */ - memmove (buffer_start, token_start, tail_size + token_size); - /* Adjust pointers. */ - token_start = buffer_start; - buffer = buffer_start + token_size; - /* Read more characters form input file. */ - error = fread (buffer + tail_size, 1, BUFFER_SIZE - tail_size - token_size, file); - if (error < 0) - fatal (ERR_IO); - if (error == 0) - return '\0'; - if (error < BUFFER_SIZE - tail_size - token_size) - memset (buffer + tail_size + error, '\0', - BUFFER_SIZE - tail_size - token_size - error); - } - else - { - memmove (buffer_start, buffer, tail_size); - buffer = buffer_start; - error = fread (buffer + tail_size, 1, BUFFER_SIZE - tail_size, file); - if (error < 0) - fatal (ERR_IO); - if (error == 0) - return '\0'; - if (error < BUFFER_SIZE - tail_size) - memset (buffer + tail_size + error, '\0', BUFFER_SIZE - tail_size - error); - } + memmove (buffer_start, buffer, tail_size); + buffer = buffer_start; + error = fread (buffer + tail_size, 1, BUFFER_SIZE - tail_size, file); + if (error < 0) + fatal (ERR_IO); + if (error == 0) + return '\0'; + if (error < BUFFER_SIZE - tail_size) + memset (buffer + tail_size + error, '\0', BUFFER_SIZE - tail_size - error); } + } return *(buffer + i); } @@ -245,55 +245,74 @@ parse_name () new_token (); consume_char (); while (true) - { - c = LA (0); - if (c == '\0') - c = c; - if (!isalpha (c) && !isdigit (c) && c != '$' && c != '_') - break; - if (every_char_islower && (!isalpha (c) || !islower (c))) - every_char_islower = false; - consume_char (); - } + { + c = LA (0); + if (c == '\0') + c = c; + if (!isalpha (c) && !isdigit (c) && c != '$' && c != '_') + break; + if (every_char_islower && (!isalpha (c) || !islower (c))) + every_char_islower = false; + consume_char (); + } tok = current_token (); if (every_char_islower) + { + keyword kw = decode_keyword (tok); + if (kw != KW_NONE) { - keyword kw = decode_keyword (tok); - if (kw != KW_NONE) - { - free ((char *) tok); - return (token) { .type = TOK_KEYWORD, .data.kw = kw }; - } + free ((char *) tok); - if (!strcmp ("null", tok)) - { - free ((char *) tok); - return (token) { .type = TOK_NULL, .data.none = NULL }; - } - - if (!strcmp ("true", tok)) - { - free ((char *) tok); - return (token) { .type = TOK_BOOL, .data.is_true = true }; - } - - if (!strcmp ("false", tok)) - { - free ((char *) tok); - return (token) { .type = TOK_BOOL, .data.is_true = false }; - } + return (token) + { + .type = TOK_KEYWORD, .data.kw = kw + }; } - return (token) { .type = TOK_NAME, .data.name = tok }; + if (!strcmp ("null", tok)) + { + free ((char *) tok); + + return (token) + { + .type = TOK_NULL, .data.none = NULL + }; + } + + if (!strcmp ("true", tok)) + { + free ((char *) tok); + + return (token) + { + .type = TOK_BOOL, .data.is_true = true + }; + } + + if (!strcmp ("false", tok)) + { + free ((char *) tok); + + return (token) + { + .type = TOK_BOOL, .data.is_true = false + }; + } + } + + return (token) + { + .type = TOK_NAME, .data.name = tok + }; } static bool is_hex_digit (char c) { return isdigit (c) || c == 'a' || c == 'A' || c == 'b' || c == 'B' - || c == 'c' || c == 'C' || c == 'd' || c == 'D' - || c == 'e' || c == 'E' || c == 'f' || c == 'F'; + || c == 'c' || c == 'C' || c == 'd' || c == 'D' + || c == 'e' || c == 'E' || c == 'f' || c == 'F'; } static int @@ -301,29 +320,29 @@ hex_to_int (char hex) { switch (hex) { - case '0': return 0x0; - case '1': return 0x1; - case '2': return 0x2; - case '3': return 0x3; - case '4': return 0x4; - case '5': return 0x5; - case '6': return 0x6; - case '7': return 0x7; - case '8': return 0x8; - case '9': return 0x9; - case 'a': - case 'A': return 0xA; - case 'b': - case 'B': return 0xB; - case 'c': - case 'C': return 0xC; - case 'd': - case 'D': return 0xD; - case 'e': - case 'E': return 0xE; - case 'f': - case 'F': return 0xF; - default: unreachable (); + case '0': return 0x0; + case '1': return 0x1; + case '2': return 0x2; + case '3': return 0x3; + case '4': return 0x4; + case '5': return 0x5; + case '6': return 0x6; + case '7': return 0x7; + case '8': return 0x8; + case '9': return 0x9; + case 'a': + case 'A': return 0xA; + case 'b': + case 'B': return 0xB; + case 'c': + case 'C': return 0xC; + case 'd': + case 'D': return 0xD; + case 'e': + case 'E': return 0xE; + case 'f': + case 'F': return 0xF; + default: unreachable (); } } @@ -347,38 +366,42 @@ parse_number () is_hex = true; if (c == '.') - { - assert (!isalpha (LA (1))); - is_fp = true; - } + { + assert (!isalpha (LA (1))); + is_fp = true; + } if (is_hex) + { + // Eat up '0x' + consume_char (); + consume_char (); + new_token (); + while (true) { - // Eat up '0x' + c = LA (0); + if (!is_hex_digit (c)) + break; consume_char (); - consume_char (); - new_token (); - while (true) - { - c = LA (0); - if (!is_hex_digit (c)) - break; - consume_char (); - } - - if (isalpha (c) || c == '_' || c == '$') - fatal (ERR_INT_LITERAL); - - tok_length = buffer - token_start; - tok = current_token (); - // OK, I know that integer overflow can occur here - for (int i = 0; i < tok_length; i++) - res = (res << 4) + hex_to_int (tok[i]); - - free ((char *) tok); - return (token) { .type = TOK_INT, .data.num = res }; } + if (isalpha (c) || c == '_' || c == '$') + fatal (ERR_INT_LITERAL); + + tok_length = buffer - token_start; + tok = current_token (); + // OK, I know that integer overflow can occur here + for (int i = 0; i < tok_length; i++) + res = (res << 4) + hex_to_int (tok[i]); + + free ((char *) tok); + + return (token) + { + .type = TOK_INT, .data.num = res + }; + } + assert (!is_hex && !is_exp); new_token (); @@ -388,49 +411,53 @@ parse_number () consume_char (); while (true) + { + c = LA (0); + if (is_fp && c == '.') + fatal (ERR_INT_LITERAL); + if (is_exp && (c == 'e' || c == 'E')) + fatal (ERR_INT_LITERAL); + + if (c == '.') { - c = LA (0); - if (is_fp && c == '.') + if (isalpha (LA (1)) || LA (1) == '_' || LA (1) == '$') fatal (ERR_INT_LITERAL); - if (is_exp && (c == 'e' || c == 'E')) - fatal (ERR_INT_LITERAL); - - if (c == '.') - { - if (isalpha (LA (1)) || LA (1) == '_' || LA (1) == '$') - fatal (ERR_INT_LITERAL); - is_fp = true; - consume_char (); - continue; - } - - if (c == 'e' || c == 'E') - { - if (LA (1) == '-' || LA (1) == '+') - consume_char (); - if (!isdigit (LA (1))) - fatal (ERR_INT_LITERAL); - is_exp = true; - consume_char (); - continue; - } - - if (isalpha (c) || c == '_' || c == '$') - fatal (ERR_INT_LITERAL); - - if (!isdigit (c)) - break; - + is_fp = true; consume_char (); + continue; } + if (c == 'e' || c == 'E') + { + if (LA (1) == '-' || LA (1) == '+') + consume_char (); + if (!isdigit (LA (1))) + fatal (ERR_INT_LITERAL); + is_exp = true; + consume_char (); + continue; + } + + if (isalpha (c) || c == '_' || c == '$') + fatal (ERR_INT_LITERAL); + + if (!isdigit (c)) + break; + + consume_char (); + } + if (is_fp || is_exp) + { + tok = current_token (); + float res = strtof (tok, NULL); + free ((char *) tok); + + return (token) { - tok = current_token (); - float res = strtof (tok, NULL); - free ((char *) tok); - return (token) { .type = TOK_FLOAT, .data.fp_num = res }; - } + .type = TOK_FLOAT, .data.fp_num = res + }; + } tok_length = buffer - token_start; tok = current_token (); @@ -439,7 +466,11 @@ parse_number () res = res * 10 + hex_to_int (tok[i]); free ((char *) tok); - return (token) { .type = TOK_INT, .data.num = res }; + + return (token) + { + .type = TOK_INT, .data.num = res + }; } static char @@ -447,16 +478,16 @@ escape_char (char c) { switch (c) { - case 'b': return '\b'; - case 'f': return '\f'; - case 'n': return '\n'; - case 'r': return '\r'; - case 't': return '\t'; - case 'v': return '\v'; - case '\'': - case '"': - case '\\': - default: return c; + case 'b': return '\b'; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case 't': return '\t'; + case 'v': return '\v'; + case '\'': + case '"': + case '\\': + default: return c; } } @@ -478,63 +509,66 @@ parse_string () new_token (); while (true) + { + c = LA (0); + if (c == '\0') + fatal (ERR_UNCLOSED); + if (c == '\n') + fatal (ERR_STRING); + if (c == '\\') { - c = LA (0); - if (c == '\0') - fatal (ERR_UNCLOSED); - if (c == '\n') + /* Only single escape character is allowed. */ + if (LA (1) == 'x' || LA (1) == 'u' || isdigit (LA (1))) fatal (ERR_STRING); - if (c == '\\') - { - /* Only single escape character is allowed. */ - if (LA (1) == 'x' || LA (1) == 'u' || isdigit (LA (1))) - fatal (ERR_STRING); - if ((LA (1) == '\'' && !is_double_quoted) - || (LA (1) == '"' && is_double_quoted) - || LA (1) == '\n') - { - consume_char (); - consume_char (); - continue; - } - } - else if ((c == '\'' && !is_double_quoted) - || (c == '"' && is_double_quoted)) - break; - - consume_char (); + if ((LA (1) == '\'' && !is_double_quoted) + || (LA (1) == '"' && is_double_quoted) + || LA (1) == '\n') + { + consume_char (); + consume_char (); + continue; + } } + else if ((c == '\'' && !is_double_quoted) + || (c == '"' && is_double_quoted)) + break; + + consume_char (); + } length = buffer - token_start; tok = (char *) malloc (length); index = tok; for (char *i = token_start; i < buffer; i++) + { + if (*i == '\\') { - if (*i == '\\') - { - if (*(i+1) == '\n') - { - i++; - continue; - } - *index = escape_char (*(i+1)); - index++; - i++; - continue; - } - - *index = *i; + if (*(i + 1) == '\n') + { + i++; + continue; + } + *index = escape_char (*(i + 1)); index++; + i++; + continue; } + *index = *i; + index++; + } + memset (index, '\0', length - (index - tok)); token_start = NULL; // Eat up '"' consume_char (); - return (token) { .type = TOK_STRING, .data.str = tok }; + return (token) + { + .type = TOK_STRING, .data.str = tok + }; } static void @@ -543,10 +577,10 @@ grobble_whitespaces () char c = LA (0); while ((isspace (c) && c != '\n') || c == '\0') - { - consume_char (); - c = LA (0); - } + { + consume_char (); + c = LA (0); + } } void @@ -554,7 +588,9 @@ lexer_set_file (FILE *ex_file) { assert (ex_file); file = ex_file; +#ifdef DEBUG lexer_debug_log = fopen ("lexer.log", "w"); +#endif } static bool @@ -573,25 +609,25 @@ replace_comment_by_newline () consume_char (); while (true) + { + c = LA (0); + if (!multiline && (c == '\n' || c == '\0')) + return false; + if (multiline && c == '*' && LA (1) == '/') { - c = LA (0); - if (!multiline && (c == '\n' || c == '\0')) - return false; - if (multiline && c == '*' && LA (1) == '/') - { - consume_char (); - consume_char (); - if (was_newlines) - return true; - else - return false; - } - if (multiline && c == '\n') - was_newlines = true; - if (multiline && c == '\0') - fatal (ERR_UNCLOSED); consume_char (); + consume_char (); + if (was_newlines) + return true; + else + return false; } + if (multiline && c == '\n') + was_newlines = true; + if (multiline && c == '\0') + fatal (ERR_UNCLOSED); + consume_char (); + } } token @@ -604,11 +640,11 @@ lexer_next_token () char c = LA (0); if (saved_token.type != TOK_EOF) - { - token res = saved_token; - saved_token.type = TOK_EOF; - return res; - } + { + token res = saved_token; + saved_token.type = TOK_EOF; + return res; + } assert (token_start == NULL); @@ -619,98 +655,108 @@ lexer_next_token () return parse_number (); if (c == '\n') + { + consume_char (); + + return (token) { - consume_char (); - return (token) { .type = TOK_NEWLINE, .data.none = NULL }; - } + .type = TOK_NEWLINE, .data.none = NULL + }; + } if (c == '\0') - return (token) { .type = TOK_EOF, .data.none = NULL }; + return (token) + { + .type = TOK_EOF, .data.none = NULL + }; if (c == '\'' || c == '"') return parse_string (); if (isspace (c)) - { - grobble_whitespaces (); - return lexer_next_token (); - } + { + grobble_whitespaces (); + return lexer_next_token (); + } if (c == '/' && LA (1) == '*') + { + if (replace_comment_by_newline ()) + return (token) { - if (replace_comment_by_newline ()) - return (token) { .type = TOK_NEWLINE, .data.none = NULL }; - else - return lexer_next_token (); - } + .type = TOK_NEWLINE, .data.none = NULL + }; + else + return lexer_next_token (); + } if (c == '/' && LA (1) == '/') - { - replace_comment_by_newline (); - return lexer_next_token (); - } + { + replace_comment_by_newline (); + return lexer_next_token (); + } switch (c) { - case '{': RETURN_PUNC (TOK_OPEN_BRACE); - case '}': RETURN_PUNC (TOK_CLOSE_BRACE); - case '(': RETURN_PUNC (TOK_OPEN_PAREN); - case ')': RETURN_PUNC (TOK_CLOSE_PAREN); - case '[': RETURN_PUNC (TOK_OPEN_SQUARE); - case ']': RETURN_PUNC (TOK_CLOSE_SQUARE); - case '.': RETURN_PUNC (TOK_DOT); - case ';': RETURN_PUNC (TOK_SEMICOLON); - case ',': RETURN_PUNC (TOK_COMMA); - case '~': RETURN_PUNC (TOK_COMPL); - case ':': RETURN_PUNC (TOK_COLON); - case '?': RETURN_PUNC (TOK_QUERY); + case '{': RETURN_PUNC (TOK_OPEN_BRACE); + case '}': RETURN_PUNC (TOK_CLOSE_BRACE); + case '(': RETURN_PUNC (TOK_OPEN_PAREN); + case ')': RETURN_PUNC (TOK_CLOSE_PAREN); + case '[': RETURN_PUNC (TOK_OPEN_SQUARE); + case ']': RETURN_PUNC (TOK_CLOSE_SQUARE); + case '.': RETURN_PUNC (TOK_DOT); + case ';': RETURN_PUNC (TOK_SEMICOLON); + case ',': RETURN_PUNC (TOK_COMMA); + case '~': RETURN_PUNC (TOK_COMPL); + case ':': RETURN_PUNC (TOK_COLON); + case '?': RETURN_PUNC (TOK_QUERY); - case '*': IF_LA_IS ('=', TOK_MULT_EQ, TOK_MULT); - case '/': IF_LA_IS ('=', TOK_DIV_EQ, TOK_DIV); - case '^': IF_LA_IS ('=', TOK_XOR_EQ, TOK_XOR); - case '%': IF_LA_IS ('=', TOK_MOD_EQ, TOK_MOD); + case '*': IF_LA_IS ('=', TOK_MULT_EQ, TOK_MULT); + case '/': IF_LA_IS ('=', TOK_DIV_EQ, TOK_DIV); + case '^': IF_LA_IS ('=', TOK_XOR_EQ, TOK_XOR); + case '%': IF_LA_IS ('=', TOK_MOD_EQ, TOK_MOD); - case '+': IF_LA_IS_OR ('+', TOK_DOUBLE_PLUS, '=', TOK_PLUS_EQ, TOK_PLUS); - case '-': IF_LA_IS_OR ('-', TOK_DOUBLE_MINUS, '=', TOK_MINUS_EQ, TOK_MINUS); - case '&': IF_LA_IS_OR ('&', TOK_DOUBLE_AND, '=', TOK_AND_EQ, TOK_AND); - case '|': IF_LA_IS_OR ('|', TOK_DOUBLE_OR, '=', TOK_OR_EQ, TOK_OR); + case '+': IF_LA_IS_OR ('+', TOK_DOUBLE_PLUS, '=', TOK_PLUS_EQ, TOK_PLUS); + case '-': IF_LA_IS_OR ('-', TOK_DOUBLE_MINUS, '=', TOK_MINUS_EQ, TOK_MINUS); + case '&': IF_LA_IS_OR ('&', TOK_DOUBLE_AND, '=', TOK_AND_EQ, TOK_AND); + case '|': IF_LA_IS_OR ('|', TOK_DOUBLE_OR, '=', TOK_OR_EQ, TOK_OR); - case '<': - switch (LA (1)) - { - case '<': IF_LA_N_IS ('=', TOK_LSHIFT_EQ, TOK_LSHIFT, 2); - case '=': RETURN_PUNC_EX (TOK_LESS_EQ, 2); - default: RETURN_PUNC (TOK_LESS); - } + case '<': + switch (LA (1)) + { + case '<': IF_LA_N_IS ('=', TOK_LSHIFT_EQ, TOK_LSHIFT, 2); + case '=': RETURN_PUNC_EX (TOK_LESS_EQ, 2); + default: RETURN_PUNC (TOK_LESS); + } + case '>': + switch (LA (1)) + { case '>': - switch (LA (1)) + switch (LA (2)) { - case '>': - switch (LA (2)) - { - case '>': IF_LA_N_IS ('=', TOK_RSHIFT_EX_EQ, TOK_RSHIFT_EX, 3); - case '=': RETURN_PUNC_EX (TOK_RSHIFT_EQ, 3); - default: RETURN_PUNC_EX (TOK_RSHIFT, 2); - } - case '=': RETURN_PUNC_EX (TOK_GREATER_EQ, 2); - default: RETURN_PUNC (TOK_GREATER); + case '>': IF_LA_N_IS ('=', TOK_RSHIFT_EX_EQ, TOK_RSHIFT_EX, 3); + case '=': RETURN_PUNC_EX (TOK_RSHIFT_EQ, 3); + default: RETURN_PUNC_EX (TOK_RSHIFT, 2); } + case '=': RETURN_PUNC_EX (TOK_GREATER_EQ, 2); + default: RETURN_PUNC (TOK_GREATER); + } - case '=': - if (LA (1) == '=') - IF_LA_N_IS ('=', TOK_TRIPLE_EQ, TOK_DOUBLE_EQ, 2); - else - RETURN_PUNC (TOK_EQ); + case '=': + if (LA (1) == '=') + IF_LA_N_IS ('=', TOK_TRIPLE_EQ, TOK_DOUBLE_EQ, 2); + else + RETURN_PUNC (TOK_EQ); - case '!': - if (LA (1) == '=') - IF_LA_N_IS ('=', TOK_NOT_DOUBLE_EQ, TOK_NOT_EQ, 2); - else - RETURN_PUNC (TOK_NOT); + case '!': + if (LA (1) == '=') + IF_LA_N_IS ('=', TOK_NOT_DOUBLE_EQ, TOK_NOT_EQ, 2); + else + RETURN_PUNC (TOK_NOT); - default: - unreachable (); + default: + unreachable (); } fatal (ERR_NON_CHAR); } @@ -725,11 +771,11 @@ lexer_next_token () if (tok.type == TOK_NEWLINE) return tok; if (tok.type == TOK_CLOSE_BRACE) - { - if (i == 300) - fprintf (lexer_debug_log, "lexer_next_token(%d): type=0x%x, data=%p\n", i, tok.type, tok.data.none); - i++; - } + { + if (i == 300) + fprintf (lexer_debug_log, "lexer_next_token(%d): type=0x%x, data=%p\n", i, tok.type, tok.data.none); + i++; + } return tok; } #endif @@ -737,10 +783,10 @@ lexer_next_token () void lexer_save_token (token tok) { - #ifdef DEBUG +#ifdef DEBUG if (tok.type == TOK_CLOSE_BRACE) fprintf (lexer_debug_log, "lexer_save_token(%d): type=0x%x, data=%p\n", i, tok.type, tok.data.none); - #endif +#endif saved_token = tok; } diff --git a/src/libcoreint/interpreter.c b/src/libcoreint/interpreter.c new file mode 100644 index 000000000..18320c462 --- /dev/null +++ b/src/libcoreint/interpreter.c @@ -0,0 +1,87 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "error.h" +#include "lexer.h" +#include "parser.h" +#include "pretty-printer.h" +#include "interpreter.h" +#include "opcode.h" + + +void +safe_opcode (FILE *file, opcode_ptr ptr, int arg1, int arg2) +{ + curr_opcode.func = ptr; + curr_opcode.arg1 = arg1; + curr_opcode.arg2 = arg2; + + if (file != NULL) + { + fwrite (&curr_opcode, sizeof (struct opcode_packed), 1, file); + } +} + +void +gen_bytecode (FILE *src_file) +{ + statement *st; + lexer_set_file (src_file); + parser_init (); + st = parser_parse_statement (); + assert (st); + while (st->type != STMT_EOF) + { + pp_statement (st); + st = parser_parse_statement (); + assert (st); + } + pp_finish (); + + FILE *file = fopen (FILE_NAME, "w+b"); + int i; + + for (i = 0; i <= 10; i++) + { + safe_opcode (file, control_op, i, i); + safe_opcode (file, decl_op, i, i); + safe_opcode (file, call_op, i, i); + } + + fclose (file); +} + +void +run_int () +{ + FILE *file = fopen (FILE_NAME, "rb"); + + if (file == NULL) + { + fputs ("File error", stderr); + exit (1); + } + + while (!feof (file)) + { + fread (&curr_opcode, sizeof (struct opcode_packed), 1, file); + + //printf ("read %d, %d, %p\n", curr_opcode.arg1, curr_opcode.arg2, curr_opcode.func); + curr_opcode.func (curr_opcode.arg1, curr_opcode.arg2); + } + + fclose (file); +} + diff --git a/src/libcoreint/interpreter.h b/src/libcoreint/interpreter.h new file mode 100644 index 000000000..a2f172913 --- /dev/null +++ b/src/libcoreint/interpreter.h @@ -0,0 +1,39 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * File: interpreter.h + * Author: egavrin + * + * Created on July 2, 2014, 3:10 PM + */ + +#ifndef INTERPRETER_H +#define INTERPRETER_H + +#include +#include +#include + +#include "opcode.h" + +#define FILE_NAME "application.bin" + +void safe_opcode(FILE *, opcode_ptr, int, int); +void gen_bytecode(FILE*); +void run_int(); + +#endif /* INTERPRETER_H */ + diff --git a/src/libcoreint/opcode.c b/src/libcoreint/opcode.c new file mode 100644 index 000000000..7a05f325d --- /dev/null +++ b/src/libcoreint/opcode.c @@ -0,0 +1,33 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "opcode.h" + +#include + +OP_DEFINITION (control_op) +{ + printf ("control_op %d, %d\n", arg1, arg2); +} + +OP_DEFINITION (decl_op) +{ + printf ("decl_op %d, %d\n", arg1, arg2); +} + +OP_DEFINITION (call_op) +{ + printf ("call_op %d, %d\n", arg1, arg2); +} \ No newline at end of file diff --git a/src/libcoreint/opcode.h b/src/libcoreint/opcode.h new file mode 100644 index 000000000..3571f0db4 --- /dev/null +++ b/src/libcoreint/opcode.h @@ -0,0 +1,55 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * File: opcode.h + * Author: egavrin + * + * Created on July 2, 2014, 3:12 PM + */ + +#ifndef OPCODE_H +#define OPCODE_H + +#define OP_RET_TYPE void +#define OP_ARG_TYPE int + +#define OP_ATTR_DECL OP_ARG_TYPE, OP_ARG_TYPE +#define OP_ATTR_DEF OP_ARG_TYPE arg1, OP_ARG_TYPE arg2 + +#define OP_DECLARATION(opname) OP_RET_TYPE opname (OP_ATTR_DECL) +#define OP_DEFINITION(opname) OP_RET_TYPE opname (OP_ATTR_DEF) + +// opcode ptr +typedef OP_RET_TYPE (*opcode_ptr)(OP_ATTR_DECL); + +struct +__attribute__ ((__packed__)) +opcode_packed +{ + opcode_ptr func; + OP_ARG_TYPE arg1; + OP_ARG_TYPE arg2; +} +curr_opcode; + +#define INIT_OPCODE_PTR(func) opcode_ptr func_ptr = ptr; + +OP_DECLARATION (decl_op); +OP_DECLARATION (call_op); +OP_DECLARATION (control_op); + +#endif /* OPCODE_H */ + diff --git a/src/main.c b/src/main.c index a88a0d491..0c0ba42e0 100644 --- a/src/main.c +++ b/src/main.c @@ -18,13 +18,22 @@ #include #include "error.h" -#include "lexer.h" -#include "parser.h" -#include "pretty-printer.h" #include "ctx-manager.h" #include "mem-allocator.h" +#include "interpreter.h" + +#include "generated.h" + +void fake_exit (); + +void +fake_exit (void) +{ + for (;;); +} + int main (int argc, char **argv) { @@ -58,36 +67,17 @@ main (int argc, char **argv) file = fopen (file_name, "r"); if (file == NULL) + { fatal (ERR_IO); - - if (dump_tokens) - { - token tok; - lexer_set_file (file); - tok = lexer_next_token (); - pp_reset (); - while (tok.type != TOK_EOF) - { - pp_token (tok); - tok = lexer_next_token (); - } } - if (dump_ast) - { - statement *st; - lexer_set_file (file); - parser_init (); - st = parser_parse_statement (); - assert (st); - while (st->type != STMT_EOF) - { - pp_statement (st); - st = parser_parse_statement (); - assert (st); - } - pp_finish (); - } + //gen_bytecode (generated_source); + gen_bytecode (file); + run_int (); + +#ifdef __TARGET_MCU + fake_exit (); +#endif return 0; } diff --git a/tests/jerry-tests/blinky-min.js b/tests/jerry-tests/blinky-min.js new file mode 100644 index 000000000..eb39f9943 --- /dev/null +++ b/tests/jerry-tests/blinky-min.js @@ -0,0 +1,26 @@ +// Copyright 2014 Samsung Electronics Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +while (true) { + LEDToggle (LED3); + LEDToggle (LED6); + LEDToggle (LED7); + LEDToggle (LED4); + LEDToggle (LED10); + LEDToggle (LED8); + LEDToggle (LED9); + LEDToggle (LED5); + + wait(500); +} diff --git a/tools/generator.sh b/tools/generator.sh new file mode 100755 index 000000000..b8af8754f --- /dev/null +++ b/tools/generator.sh @@ -0,0 +1,22 @@ +# Copyright 2014 Samsung Electronics Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#!/bin/bash + +echo "static const char* generated_source = \"\"" > "generated.h" +while read line +do + echo "\"$line\n\"" >> "generated.h" +done < $1 +echo ";" >> "generated.h" \ No newline at end of file