diff --git a/README.md b/README.md index 2dbea83..acdfb64 100644 --- a/README.md +++ b/README.md @@ -82,8 +82,9 @@ do println "MQTT Script 1.0 starting" subscribe local /test/# settimer 1 1000 % once per second - setvar $1 0 - setvar $2 0 + setvar $1=0 + setvar $2=0 + setvar $3=10 % Now the events, checked whenever something happens @@ -100,16 +101,15 @@ do % Let the LED on GPIO 2 blink gpio_out 2 $1 - setvar $1 not $1 + setvar $1 = not $1 % Count occurences in var $2 - setvar $2 $2 add 1 + setvar $2=$2+1 - % And if we have reached 100, print that to the console - if $2 gte 100 then - print "We have reached " - println $2 - setvar $2 0 + % And if we have reached 10, print that to the console + if $2 = $3 then + println "We have reached "|$2| " at " |$timestamp + setvar $3=$2+10 endif % Reload the timer @@ -134,7 +134,7 @@ In general, scripts have the following BNF: subscribe (local|remote) | unsubscribe (local|remote) | settimer | - setvar $ | + setvar $ = | gpio_out | if then endif | print | println @@ -142,7 +142,7 @@ In general, scripts have the following BNF: ::= | not - := eq | gt | gte | str_ge | str_gte | add | sub | mult | div + := '=' | gt | gte | str_ge | str_gte | '+' | '-' | '/' | '|' | div := | | # | $ | $this_item | $this_data | $timestamp diff --git a/firmware/0x00000.bin b/firmware/0x00000.bin index 3d86efa..269e35f 100644 Binary files a/firmware/0x00000.bin and b/firmware/0x00000.bin differ diff --git a/firmware/0x10000.bin b/firmware/0x10000.bin index 786331e..13ec9e8 100644 Binary files a/firmware/0x10000.bin and b/firmware/0x10000.bin differ diff --git a/user/demo_script b/user/demo_script index 29f8375..4fb72c6 100644 --- a/user/demo_script +++ b/user/demo_script @@ -10,8 +10,9 @@ do println "MQTT Script 1.0 starting" subscribe local /test/# settimer 1 1000 % once per second - setvar $1 0 - setvar $2 0 + setvar $1=0 + setvar $2=0 + setvar $3=10 % Now the events, checked whenever something happens @@ -28,16 +29,15 @@ do % Let the LED on GPIO 2 blink gpio_out 2 $1 - setvar $1 not $1 + setvar $1 = not $1 % Count occurences in var $2 - setvar $2 $2 add 1 + setvar $2=$2+1 % And if we have reached 10, print that to the console - if $2 gte 10 then - print "We have reached " - println $2 - setvar $2 0 + if $2 = $3 then + println "We have reached "|$2| " at " |$timestamp + setvar $3=$2+10 endif % Reload the timer diff --git a/user/lang.c b/user/lang.c index 37b44a8..c9dc56a 100644 --- a/user/lang.c +++ b/user/lang.c @@ -14,9 +14,10 @@ extern void do_command(char *t1, char *t2, char *t3); extern void con_print(uint8_t *str); +static char EOT[] = "end of text"; #define len_check(x) \ if (interpreter_status==SYNTAX_CHECK && next_token+(x) >= max_token) \ - return syntax_error(next_token+(x), "end of text") + return syntax_error(next_token+(x), EOT) #define syn_chk (interpreter_status==SYNTAX_CHECK) #define ON "\xf0" @@ -147,20 +148,43 @@ int ICACHE_FLASH_ATTR text_into_tokens(char *str) { } else if (*p <= ' ' && !in_token) { // mark this as whitespace *q++ = 1; + } else if (*p == '|' && !in_token) { + // mark this as concat + *q++ = 2; + } else if (*p == '+' && !in_token) { + // mark this as add + *q++ = 3; + } else if (*p == '-' && !in_token) { + // mark this as sub + *q++ = 4; + } else if (*p == '*' && !in_token) { + // mark this as mult + *q++ = 5; + } else if (*p == '=' && !in_token) { + // mark this as div + *q++ = 6; } else { *q++ = *p; } } *q = 0; - // eliminate double whitespace and count tokens + // eliminate double whitespace, detect operators and count tokens lang_debug("lexxer whitespaces\r\n"); in_token = false; for (p = q = str; *p != 0; p++) { - if (*p == 1) { - if (in_token) { - *q++ = 1; + if (*p < ' ') { + // it is a whitespace or an operator + if (*p == 1 && in_token) { + // it is a whitespace + *q++ = *p; + in_token = false; + } + if (*p > 1) { + // it is an operator + *q++ = *p; + token_count++; in_token = false; } } else { @@ -187,7 +211,33 @@ int ICACHE_FLASH_ATTR text_into_tokens(char *str) { if (*p == 1) { *p = '\0'; in_token = false; - } else { + } + else if (*p == 2) { + my_token[token_count++] = "|"; + *p = '\0'; + in_token = false; + } + else if (*p == 3) { + my_token[token_count++] = "+"; + *p = '\0'; + in_token = false; + } + else if (*p == 4) { + my_token[token_count++] = "-"; + *p = '\0'; + in_token = false; + } + else if (*p == 5) { + my_token[token_count++] = "*"; + *p = '\0'; + in_token = false; + } + else if (*p == 6) { + my_token[token_count++] = "="; + *p = '\0'; + in_token = false; + } + else { if (!in_token) { my_token[token_count++] = p; in_token = true; @@ -338,16 +388,20 @@ int ICACHE_FLASH_ATTR parse_action(int next_token, bool doit) { while (next_token < max_token && !is_token(next_token, ON) && !is_token(next_token, CONFIG) && !is_token(next_token, "endif")) { - lang_debug("action %s %s\r\n", my_token[next_token], doit ? "do" : "ignore"); - bool is_nl = false; + + if (doit) { + lang_debug("action %s\r\n", my_token[next_token]); + } + //os_printf("action %s %s\r\n", my_token[next_token], doit ? "do" : "ignore"); + if ((is_nl = is_token(next_token, "println")) || is_token(next_token, "print")) { char *p_char; int p_len; Value_Type p_type; len_check(1); - if ((next_token = parse_expression(next_token + 1, &p_char, &p_len, &p_type)) == -1) + if ((next_token = parse_expression(next_token + 1, &p_char, &p_len, &p_type, doit)) == -1) return -1; if (doit) { con_print(p_char); @@ -457,7 +511,7 @@ int ICACHE_FLASH_ATTR parse_action(int next_token, bool doit) { Value_Type if_type; len_check(3); - if ((next_token = parse_expression(next_token + 1, &if_char, &if_len, &if_type)) == -1) + if ((next_token = parse_expression(next_token + 1, &if_char, &if_len, &if_type, doit)) == -1) return -1; if (syn_chk && !is_token(next_token, "then")) return syntax_error(next_token, "'then' expected"); @@ -497,17 +551,19 @@ int ICACHE_FLASH_ATTR parse_action(int next_token, bool doit) { } else if (is_token(next_token, "setvar")) { - len_check(2); - if (my_token[next_token + 1][0] != '$') + len_check(3); + if (syn_chk && my_token[next_token + 1][0] != '$') return syntax_error(next_token + 1, "invalid var identifier"); uint32_t var_no = atoi(&(my_token[next_token + 1][1])); if (var_no == 0 || var_no > MAX_VARS) return syntax_error(next_token + 1, "invalid var number"); + if (syn_chk && os_strcmp(my_token[next_token + 2], "=") != 0) + return syntax_error(next_token + 2, "'=' expected"); char *var_data; int var_len; Value_Type var_type; - if ((next_token = parse_expression(next_token + 2, &var_data, &var_len, &var_type)) == -1) + if ((next_token = parse_expression(next_token + 3, &var_data, &var_len, &var_type, doit)) == -1) return -1; if (doit) { @@ -533,7 +589,7 @@ int ICACHE_FLASH_ATTR parse_action(int next_token, bool doit) { char *gpio_data; int gpio_len; Value_Type gpio_type; - if ((next_token = parse_expression(next_token + 2, &gpio_data, &gpio_len, &gpio_type)) == -1) + if ((next_token = parse_expression(next_token + 2, &gpio_data, &gpio_len, &gpio_type, doit)) == -1) return -1; if (doit) { @@ -553,13 +609,13 @@ int ICACHE_FLASH_ATTR parse_action(int next_token, bool doit) { return next_token; } -int ICACHE_FLASH_ATTR parse_expression(int next_token, char **data, int *data_len, Value_Type * data_type) { +int ICACHE_FLASH_ATTR parse_expression(int next_token, char **data, int *data_len, Value_Type * data_type, bool doit) { if (is_token(next_token, "not")) { len_check(1); lang_debug("expr not\r\n"); - if ((next_token = parse_expression(next_token + 1, data, data_len, data_type)) == -1) + if ((next_token = parse_expression(next_token + 1, data, data_len, data_type, doit)) == -1) return -1; *data = atoi(*data) ? "0" : "1"; *data_len = 1; @@ -571,11 +627,12 @@ int ICACHE_FLASH_ATTR parse_expression(int next_token, char **data, int *data_le return -1; // if it is not some kind of binary operation - finished - if (!is_token(next_token, "eq") - && !is_token(next_token, "add") - && !is_token(next_token, "sub") - && !is_token(next_token, "mult") + if (!is_token(next_token, "=") + && !is_token(next_token, "+") + && !is_token(next_token, "-") + && !is_token(next_token, "*") && !is_token(next_token, "div") + && !is_token(next_token, "|") && !is_token(next_token, "gt") && !is_token(next_token, "gte") && !is_token(next_token, "str_gt") @@ -588,34 +645,30 @@ int ICACHE_FLASH_ATTR parse_expression(int next_token, char **data, int *data_le char *r_data; int r_data_len; Value_Type r_data_type; - static char res_str[10]; // parse second operand - if ((next_token = parse_expression(next_token + 1, &r_data, &r_data_len, &r_data_type)) == -1) + if ((next_token = parse_expression(next_token + 1, &r_data, &r_data_len, &r_data_type, doit)) == -1) return -1; //os_printf("l:%s(%d) r:%s(%d)\r\n", *data, *data_len, r_data, r_data_len); - *data_len = 1; + if (!doit) + return next_token; + +// reuse of the syntax_error_buffer (unused during execution), dirty but saves RAM +#define res_str syntax_error_buffer + *data_type = STRING_T; - if (is_token(op, "eq")) { + if (is_token(op, "=")) { *data = os_strcmp(*data, r_data) ? "0" : "1"; - } else if (is_token(op, "gt")) { - *data = atoi(*data) > atoi(r_data) ? "1" : "0"; - } else if (is_token(op, "gte")) { - *data = atoi(*data) >= atoi(r_data) ? "1" : "0"; - } else if (is_token(op, "str_gt")) { - *data = os_strcmp(*data, r_data) > 0 ? "1" : "0"; - } else if (is_token(op, "str_gte")) { - *data = os_strcmp(*data, r_data) >= 0 ? "1" : "0"; - } else if (is_token(op, "add")) { + } else if (is_token(op, "+")) { os_sprintf(res_str, "%d", atoi(*data) + atoi(r_data)); *data = res_str; *data_len = os_strlen(res_str); - } else if (is_token(op, "sub")) { + } else if (is_token(op, "-")) { os_sprintf(res_str, "%d", atoi(*data) - atoi(r_data)); *data = res_str; *data_len = os_strlen(res_str); - } else if (is_token(op, "mult")) { + } else if (is_token(op, "*")) { os_sprintf(res_str, "%d", atoi(*data) * atoi(r_data)); *data = res_str; *data_len = os_strlen(res_str); @@ -623,6 +676,29 @@ int ICACHE_FLASH_ATTR parse_expression(int next_token, char **data, int *data_le os_sprintf(res_str, "%d", atoi(*data) / atoi(r_data)); *data = res_str; *data_len = os_strlen(res_str); + } else if (is_token(op, "|")) { + uint16_t len = os_strlen(*data) + os_strlen(r_data); + char catbuf[len+1]; + os_sprintf(catbuf, "%s%s", *data, r_data); + if (len > sizeof(res_str)-1) { + len = sizeof(res_str); + catbuf[len] = '\0'; + } + *data_len = len; + os_memcpy(res_str, catbuf, *data_len + 1); + *data = res_str; + } else if (is_token(op, "gt")) { + *data = atoi(*data) > atoi(r_data) ? "1" : "0"; + *data_len = 1; + } else if (is_token(op, "gte")) { + *data = atoi(*data) >= atoi(r_data) ? "1" : "0"; + *data_len = 1; + } else if (is_token(op, "str_gt")) { + *data = os_strcmp(*data, r_data) > 0 ? "1" : "0"; + *data_len = 1; + } else if (is_token(op, "str_gte")) { + *data = os_strcmp(*data, r_data) >= 0 ? "1" : "0"; + *data_len = 1; } } @@ -787,7 +863,7 @@ int ICACHE_FLASH_ATTR interpreter_topic_received(const char *topic, const char * interpreter_topic = (char *)topic; interpreter_data_len = data_len; if ((interpreter_data = (uint8_t *) os_malloc(data_len + 1)) == 0) { - os_printf("Out of Memory\r\n"); + os_printf("Out of memory\r\n"); return -1; } os_memcpy(interpreter_data, data, data_len); diff --git a/user/lang.h b/user/lang.h index 3b39260..329833a 100644 --- a/user/lang.h +++ b/user/lang.h @@ -16,6 +16,7 @@ int syntax_error(int i, char *message); int parse_statement(int next_token); int parse_event(int next_token, bool *happened); int parse_action(int next_token, bool doit); +int parse_expression(int next_token, char **data, int *data_len, Value_Type * data_type, bool doit); int parse_value(int next_token, char **data, int *data_len, Value_Type *data_type); extern bool script_enabled; diff --git a/user/user_main.c b/user/user_main.c index beb72bc..102a9d7 100644 --- a/user/user_main.c +++ b/user/user_main.c @@ -582,8 +582,16 @@ void ICACHE_FLASH_ATTR console_handle_command(struct espconn *pespconn) { goto command_handled; } + if (strcmp(tokens[1], "delete") == 0) { + script_enabled = false; + free_script(); + blob_zero(0, MAX_SCRIPT_SIZE); + os_sprintf(response, "Script deleted"); + goto command_handled; + } + port = atoi(tokens[1]); - if (nTokens == 0) { + if (port == 0) { os_sprintf(response, "Invalid port"); goto command_handled; }