From 80e46e08de5f65702fa7f7cd3ef83f905d919bbc Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 3 Jun 2015 10:49:29 -0700 Subject: recovery: Switch to clang And a few trival fixes to suppress warnings. Change-Id: I38734b5f4434643e85feab25f4807b46a45d8d65 --- edify/Android.mk | 2 ++ 1 file changed, 2 insertions(+) (limited to 'edify') diff --git a/edify/Android.mk b/edify/Android.mk index 03c04e432..c36645045 100644 --- a/edify/Android.mk +++ b/edify/Android.mk @@ -25,6 +25,7 @@ LOCAL_CFLAGS := $(edify_cflags) -g -O0 LOCAL_MODULE := edify LOCAL_YACCFLAGS := -v LOCAL_CFLAGS += -Wno-unused-parameter +LOCAL_CLANG := true include $(BUILD_HOST_EXECUTABLE) @@ -38,5 +39,6 @@ LOCAL_SRC_FILES := $(edify_src_files) LOCAL_CFLAGS := $(edify_cflags) LOCAL_CFLAGS += -Wno-unused-parameter LOCAL_MODULE := libedify +LOCAL_CLANG := true include $(BUILD_STATIC_LIBRARY) -- cgit v1.2.3 From b02e90f85cb60a6de0ff93147e988c10c4cf213a Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Fri, 7 Aug 2015 17:24:49 -0700 Subject: Use CPPFLAGS instead of CFLAGS. While we build these as C, to the build system they are technically C++ and are subject to the global CPPFLAGS. Set LOCAL_CPPFLAGS here instead of LOCAL_CFLAGS so we can be sure we override anything provided by the build system. Bug: http://b/23043421 Change-Id: I344b54ae4ff9f142365a42c33ba160c1be17a342 --- edify/Android.mk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'edify') diff --git a/edify/Android.mk b/edify/Android.mk index c36645045..eb366c287 100644 --- a/edify/Android.mk +++ b/edify/Android.mk @@ -21,10 +21,10 @@ LOCAL_SRC_FILES := \ $(edify_src_files) \ main.c -LOCAL_CFLAGS := $(edify_cflags) -g -O0 +LOCAL_CPPFLAGS := $(edify_cflags) -g -O0 LOCAL_MODULE := edify LOCAL_YACCFLAGS := -v -LOCAL_CFLAGS += -Wno-unused-parameter +LOCAL_CPPFLAGS += -Wno-unused-parameter LOCAL_CLANG := true include $(BUILD_HOST_EXECUTABLE) @@ -36,8 +36,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(edify_src_files) -LOCAL_CFLAGS := $(edify_cflags) -LOCAL_CFLAGS += -Wno-unused-parameter +LOCAL_CPPFLAGS := $(edify_cflags) +LOCAL_CPPFLAGS += -Wno-unused-parameter LOCAL_MODULE := libedify LOCAL_CLANG := true -- cgit v1.2.3 From 2a5a49d3376eae890d76bb560e0d8ffc264ff5a6 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 20 Aug 2015 12:10:46 -0700 Subject: edify: Switch to C++. Change-Id: I71aede6e29af1dc4bb858a62016c8035db5d3452 --- edify/Android.mk | 16 +- edify/expr.c | 505 ------------------------------------------------------ edify/expr.cpp | 507 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ edify/expr.h | 10 +- edify/main.c | 214 ----------------------- edify/main.cpp | 214 +++++++++++++++++++++++ edify/parser.y | 8 +- 7 files changed, 732 insertions(+), 742 deletions(-) delete mode 100644 edify/expr.c create mode 100644 edify/expr.cpp delete mode 100644 edify/main.c create mode 100644 edify/main.cpp (limited to 'edify') diff --git a/edify/Android.mk b/edify/Android.mk index eb366c287..9b859d42e 100644 --- a/edify/Android.mk +++ b/edify/Android.mk @@ -5,12 +5,7 @@ LOCAL_PATH := $(call my-dir) edify_src_files := \ lexer.l \ parser.y \ - expr.c - -# "-x c" forces the lex/yacc files to be compiled as c the build system -# otherwise forces them to be c++. Need to also add an explicit -std because the -# build system will soon default C++ to -std=c++11. -edify_cflags := -x c -std=gnu89 + expr.cpp # # Build the host-side command line tool @@ -19,12 +14,13 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ $(edify_src_files) \ - main.c + main.cpp -LOCAL_CPPFLAGS := $(edify_cflags) -g -O0 +LOCAL_CPPFLAGS := -g -O0 LOCAL_MODULE := edify LOCAL_YACCFLAGS := -v LOCAL_CPPFLAGS += -Wno-unused-parameter +LOCAL_CPPFLAGS += -Wno-deprecated-register LOCAL_CLANG := true include $(BUILD_HOST_EXECUTABLE) @@ -36,8 +32,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(edify_src_files) -LOCAL_CPPFLAGS := $(edify_cflags) -LOCAL_CPPFLAGS += -Wno-unused-parameter +LOCAL_CPPFLAGS := -Wno-unused-parameter +LOCAL_CPPFLAGS += -Wno-deprecated-register LOCAL_MODULE := libedify LOCAL_CLANG := true diff --git a/edify/expr.c b/edify/expr.c deleted file mode 100644 index 79f6282d8..000000000 --- a/edify/expr.c +++ /dev/null @@ -1,505 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * 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 -#include -#include -#include -#include -#include - -#include "expr.h" - -// Functions should: -// -// - return a malloc()'d string -// - if Evaluate() on any argument returns NULL, return NULL. - -int BooleanString(const char* s) { - return s[0] != '\0'; -} - -char* Evaluate(State* state, Expr* expr) { - Value* v = expr->fn(expr->name, state, expr->argc, expr->argv); - if (v == NULL) return NULL; - if (v->type != VAL_STRING) { - ErrorAbort(state, "expecting string, got value type %d", v->type); - FreeValue(v); - return NULL; - } - char* result = v->data; - free(v); - return result; -} - -Value* EvaluateValue(State* state, Expr* expr) { - return expr->fn(expr->name, state, expr->argc, expr->argv); -} - -Value* StringValue(char* str) { - if (str == NULL) return NULL; - Value* v = malloc(sizeof(Value)); - v->type = VAL_STRING; - v->size = strlen(str); - v->data = str; - return v; -} - -void FreeValue(Value* v) { - if (v == NULL) return; - free(v->data); - free(v); -} - -Value* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc == 0) { - return StringValue(strdup("")); - } - char** strings = malloc(argc * sizeof(char*)); - int i; - for (i = 0; i < argc; ++i) { - strings[i] = NULL; - } - char* result = NULL; - int length = 0; - for (i = 0; i < argc; ++i) { - strings[i] = Evaluate(state, argv[i]); - if (strings[i] == NULL) { - goto done; - } - length += strlen(strings[i]); - } - - result = malloc(length+1); - int p = 0; - for (i = 0; i < argc; ++i) { - strcpy(result+p, strings[i]); - p += strlen(strings[i]); - } - result[p] = '\0'; - - done: - for (i = 0; i < argc; ++i) { - free(strings[i]); - } - free(strings); - return StringValue(result); -} - -Value* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 2 && argc != 3) { - free(state->errmsg); - state->errmsg = strdup("ifelse expects 2 or 3 arguments"); - return NULL; - } - char* cond = Evaluate(state, argv[0]); - if (cond == NULL) { - return NULL; - } - - if (BooleanString(cond) == true) { - free(cond); - return EvaluateValue(state, argv[1]); - } else { - if (argc == 3) { - free(cond); - return EvaluateValue(state, argv[2]); - } else { - return StringValue(cond); - } - } -} - -Value* AbortFn(const char* name, State* state, int argc, Expr* argv[]) { - char* msg = NULL; - if (argc > 0) { - msg = Evaluate(state, argv[0]); - } - free(state->errmsg); - if (msg) { - state->errmsg = msg; - } else { - state->errmsg = strdup("called abort()"); - } - return NULL; -} - -Value* AssertFn(const char* name, State* state, int argc, Expr* argv[]) { - int i; - for (i = 0; i < argc; ++i) { - char* v = Evaluate(state, argv[i]); - if (v == NULL) { - return NULL; - } - int b = BooleanString(v); - free(v); - if (!b) { - int prefix_len; - int len = argv[i]->end - argv[i]->start; - char* err_src = malloc(len + 20); - strcpy(err_src, "assert failed: "); - prefix_len = strlen(err_src); - memcpy(err_src + prefix_len, state->script + argv[i]->start, len); - err_src[prefix_len + len] = '\0'; - free(state->errmsg); - state->errmsg = err_src; - return NULL; - } - } - return StringValue(strdup("")); -} - -Value* SleepFn(const char* name, State* state, int argc, Expr* argv[]) { - char* val = Evaluate(state, argv[0]); - if (val == NULL) { - return NULL; - } - int v = strtol(val, NULL, 10); - sleep(v); - return StringValue(val); -} - -Value* StdoutFn(const char* name, State* state, int argc, Expr* argv[]) { - int i; - for (i = 0; i < argc; ++i) { - char* v = Evaluate(state, argv[i]); - if (v == NULL) { - return NULL; - } - fputs(v, stdout); - free(v); - } - return StringValue(strdup("")); -} - -Value* LogicalAndFn(const char* name, State* state, - int argc, Expr* argv[]) { - char* left = Evaluate(state, argv[0]); - if (left == NULL) return NULL; - if (BooleanString(left) == true) { - free(left); - return EvaluateValue(state, argv[1]); - } else { - return StringValue(left); - } -} - -Value* LogicalOrFn(const char* name, State* state, - int argc, Expr* argv[]) { - char* left = Evaluate(state, argv[0]); - if (left == NULL) return NULL; - if (BooleanString(left) == false) { - free(left); - return EvaluateValue(state, argv[1]); - } else { - return StringValue(left); - } -} - -Value* LogicalNotFn(const char* name, State* state, - int argc, Expr* argv[]) { - char* val = Evaluate(state, argv[0]); - if (val == NULL) return NULL; - bool bv = BooleanString(val); - free(val); - return StringValue(strdup(bv ? "" : "t")); -} - -Value* SubstringFn(const char* name, State* state, - int argc, Expr* argv[]) { - char* needle = Evaluate(state, argv[0]); - if (needle == NULL) return NULL; - char* haystack = Evaluate(state, argv[1]); - if (haystack == NULL) { - free(needle); - return NULL; - } - - char* result = strdup(strstr(haystack, needle) ? "t" : ""); - free(needle); - free(haystack); - return StringValue(result); -} - -Value* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) { - char* left = Evaluate(state, argv[0]); - if (left == NULL) return NULL; - char* right = Evaluate(state, argv[1]); - if (right == NULL) { - free(left); - return NULL; - } - - char* result = strdup(strcmp(left, right) == 0 ? "t" : ""); - free(left); - free(right); - return StringValue(result); -} - -Value* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) { - char* left = Evaluate(state, argv[0]); - if (left == NULL) return NULL; - char* right = Evaluate(state, argv[1]); - if (right == NULL) { - free(left); - return NULL; - } - - char* result = strdup(strcmp(left, right) != 0 ? "t" : ""); - free(left); - free(right); - return StringValue(result); -} - -Value* SequenceFn(const char* name, State* state, int argc, Expr* argv[]) { - Value* left = EvaluateValue(state, argv[0]); - if (left == NULL) return NULL; - FreeValue(left); - return EvaluateValue(state, argv[1]); -} - -Value* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 2) { - free(state->errmsg); - state->errmsg = strdup("less_than_int expects 2 arguments"); - return NULL; - } - - char* left; - char* right; - if (ReadArgs(state, argv, 2, &left, &right) < 0) return NULL; - - bool result = false; - char* end; - - long l_int = strtol(left, &end, 10); - if (left[0] == '\0' || *end != '\0') { - goto done; - } - - long r_int = strtol(right, &end, 10); - if (right[0] == '\0' || *end != '\0') { - goto done; - } - - result = l_int < r_int; - - done: - free(left); - free(right); - return StringValue(strdup(result ? "t" : "")); -} - -Value* GreaterThanIntFn(const char* name, State* state, - int argc, Expr* argv[]) { - if (argc != 2) { - free(state->errmsg); - state->errmsg = strdup("greater_than_int expects 2 arguments"); - return NULL; - } - - Expr* temp[2]; - temp[0] = argv[1]; - temp[1] = argv[0]; - - return LessThanIntFn(name, state, 2, temp); -} - -Value* Literal(const char* name, State* state, int argc, Expr* argv[]) { - return StringValue(strdup(name)); -} - -Expr* Build(Function fn, YYLTYPE loc, int count, ...) { - va_list v; - va_start(v, count); - Expr* e = malloc(sizeof(Expr)); - e->fn = fn; - e->name = "(operator)"; - e->argc = count; - e->argv = malloc(count * sizeof(Expr*)); - int i; - for (i = 0; i < count; ++i) { - e->argv[i] = va_arg(v, Expr*); - } - va_end(v); - e->start = loc.start; - e->end = loc.end; - return e; -} - -// ----------------------------------------------------------------- -// the function table -// ----------------------------------------------------------------- - -static int fn_entries = 0; -static int fn_size = 0; -NamedFunction* fn_table = NULL; - -void RegisterFunction(const char* name, Function fn) { - if (fn_entries >= fn_size) { - fn_size = fn_size*2 + 1; - fn_table = realloc(fn_table, fn_size * sizeof(NamedFunction)); - } - fn_table[fn_entries].name = name; - fn_table[fn_entries].fn = fn; - ++fn_entries; -} - -static int fn_entry_compare(const void* a, const void* b) { - const char* na = ((const NamedFunction*)a)->name; - const char* nb = ((const NamedFunction*)b)->name; - return strcmp(na, nb); -} - -void FinishRegistration() { - qsort(fn_table, fn_entries, sizeof(NamedFunction), fn_entry_compare); -} - -Function FindFunction(const char* name) { - NamedFunction key; - key.name = name; - NamedFunction* nf = bsearch(&key, fn_table, fn_entries, - sizeof(NamedFunction), fn_entry_compare); - if (nf == NULL) { - return NULL; - } - return nf->fn; -} - -void RegisterBuiltins() { - RegisterFunction("ifelse", IfElseFn); - RegisterFunction("abort", AbortFn); - RegisterFunction("assert", AssertFn); - RegisterFunction("concat", ConcatFn); - RegisterFunction("is_substring", SubstringFn); - RegisterFunction("stdout", StdoutFn); - RegisterFunction("sleep", SleepFn); - - RegisterFunction("less_than_int", LessThanIntFn); - RegisterFunction("greater_than_int", GreaterThanIntFn); -} - - -// ----------------------------------------------------------------- -// convenience methods for functions -// ----------------------------------------------------------------- - -// Evaluate the expressions in argv, giving 'count' char* (the ... is -// zero or more char** to put them in). If any expression evaluates -// to NULL, free the rest and return -1. Return 0 on success. -int ReadArgs(State* state, Expr* argv[], int count, ...) { - char** args = malloc(count * sizeof(char*)); - va_list v; - va_start(v, count); - int i; - for (i = 0; i < count; ++i) { - args[i] = Evaluate(state, argv[i]); - if (args[i] == NULL) { - va_end(v); - int j; - for (j = 0; j < i; ++j) { - free(args[j]); - } - free(args); - return -1; - } - *(va_arg(v, char**)) = args[i]; - } - va_end(v); - free(args); - return 0; -} - -// Evaluate the expressions in argv, giving 'count' Value* (the ... is -// zero or more Value** to put them in). If any expression evaluates -// to NULL, free the rest and return -1. Return 0 on success. -int ReadValueArgs(State* state, Expr* argv[], int count, ...) { - Value** args = malloc(count * sizeof(Value*)); - va_list v; - va_start(v, count); - int i; - for (i = 0; i < count; ++i) { - args[i] = EvaluateValue(state, argv[i]); - if (args[i] == NULL) { - va_end(v); - int j; - for (j = 0; j < i; ++j) { - FreeValue(args[j]); - } - free(args); - return -1; - } - *(va_arg(v, Value**)) = args[i]; - } - va_end(v); - free(args); - return 0; -} - -// Evaluate the expressions in argv, returning an array of char* -// results. If any evaluate to NULL, free the rest and return NULL. -// The caller is responsible for freeing the returned array and the -// strings it contains. -char** ReadVarArgs(State* state, int argc, Expr* argv[]) { - char** args = (char**)malloc(argc * sizeof(char*)); - int i = 0; - for (i = 0; i < argc; ++i) { - args[i] = Evaluate(state, argv[i]); - if (args[i] == NULL) { - int j; - for (j = 0; j < i; ++j) { - free(args[j]); - } - free(args); - return NULL; - } - } - return args; -} - -// Evaluate the expressions in argv, returning an array of Value* -// results. If any evaluate to NULL, free the rest and return NULL. -// The caller is responsible for freeing the returned array and the -// Values it contains. -Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]) { - Value** args = (Value**)malloc(argc * sizeof(Value*)); - int i = 0; - for (i = 0; i < argc; ++i) { - args[i] = EvaluateValue(state, argv[i]); - if (args[i] == NULL) { - int j; - for (j = 0; j < i; ++j) { - FreeValue(args[j]); - } - free(args); - return NULL; - } - } - return args; -} - -// Use printf-style arguments to compose an error message to put into -// *state. Returns NULL. -Value* ErrorAbort(State* state, const char* format, ...) { - char* buffer = malloc(4096); - va_list v; - va_start(v, format); - vsnprintf(buffer, 4096, format, v); - va_end(v); - free(state->errmsg); - state->errmsg = buffer; - return NULL; -} diff --git a/edify/expr.cpp b/edify/expr.cpp new file mode 100644 index 000000000..cd1e08726 --- /dev/null +++ b/edify/expr.cpp @@ -0,0 +1,507 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * 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 +#include +#include +#include +#include +#include + +#include "expr.h" + +// Functions should: +// +// - return a malloc()'d string +// - if Evaluate() on any argument returns NULL, return NULL. + +int BooleanString(const char* s) { + return s[0] != '\0'; +} + +char* Evaluate(State* state, Expr* expr) { + Value* v = expr->fn(expr->name, state, expr->argc, expr->argv); + if (v == NULL) return NULL; + if (v->type != VAL_STRING) { + ErrorAbort(state, "expecting string, got value type %d", v->type); + FreeValue(v); + return NULL; + } + char* result = v->data; + free(v); + return result; +} + +Value* EvaluateValue(State* state, Expr* expr) { + return expr->fn(expr->name, state, expr->argc, expr->argv); +} + +Value* StringValue(char* str) { + if (str == NULL) return NULL; + Value* v = reinterpret_cast(malloc(sizeof(Value))); + v->type = VAL_STRING; + v->size = strlen(str); + v->data = str; + return v; +} + +void FreeValue(Value* v) { + if (v == NULL) return; + free(v->data); + free(v); +} + +Value* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) { + if (argc == 0) { + return StringValue(strdup("")); + } + char** strings = reinterpret_cast(malloc(argc * sizeof(char*))); + int i; + for (i = 0; i < argc; ++i) { + strings[i] = NULL; + } + char* result = NULL; + int length = 0; + for (i = 0; i < argc; ++i) { + strings[i] = Evaluate(state, argv[i]); + if (strings[i] == NULL) { + goto done; + } + length += strlen(strings[i]); + } + + result = reinterpret_cast(malloc(length+1)); + int p; + p = 0; + for (i = 0; i < argc; ++i) { + strcpy(result+p, strings[i]); + p += strlen(strings[i]); + } + result[p] = '\0'; + + done: + for (i = 0; i < argc; ++i) { + free(strings[i]); + } + free(strings); + return StringValue(result); +} + +Value* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) { + if (argc != 2 && argc != 3) { + free(state->errmsg); + state->errmsg = strdup("ifelse expects 2 or 3 arguments"); + return NULL; + } + char* cond = Evaluate(state, argv[0]); + if (cond == NULL) { + return NULL; + } + + if (BooleanString(cond) == true) { + free(cond); + return EvaluateValue(state, argv[1]); + } else { + if (argc == 3) { + free(cond); + return EvaluateValue(state, argv[2]); + } else { + return StringValue(cond); + } + } +} + +Value* AbortFn(const char* name, State* state, int argc, Expr* argv[]) { + char* msg = NULL; + if (argc > 0) { + msg = Evaluate(state, argv[0]); + } + free(state->errmsg); + if (msg) { + state->errmsg = msg; + } else { + state->errmsg = strdup("called abort()"); + } + return NULL; +} + +Value* AssertFn(const char* name, State* state, int argc, Expr* argv[]) { + int i; + for (i = 0; i < argc; ++i) { + char* v = Evaluate(state, argv[i]); + if (v == NULL) { + return NULL; + } + int b = BooleanString(v); + free(v); + if (!b) { + int prefix_len; + int len = argv[i]->end - argv[i]->start; + char* err_src = reinterpret_cast(malloc(len + 20)); + strcpy(err_src, "assert failed: "); + prefix_len = strlen(err_src); + memcpy(err_src + prefix_len, state->script + argv[i]->start, len); + err_src[prefix_len + len] = '\0'; + free(state->errmsg); + state->errmsg = err_src; + return NULL; + } + } + return StringValue(strdup("")); +} + +Value* SleepFn(const char* name, State* state, int argc, Expr* argv[]) { + char* val = Evaluate(state, argv[0]); + if (val == NULL) { + return NULL; + } + int v = strtol(val, NULL, 10); + sleep(v); + return StringValue(val); +} + +Value* StdoutFn(const char* name, State* state, int argc, Expr* argv[]) { + int i; + for (i = 0; i < argc; ++i) { + char* v = Evaluate(state, argv[i]); + if (v == NULL) { + return NULL; + } + fputs(v, stdout); + free(v); + } + return StringValue(strdup("")); +} + +Value* LogicalAndFn(const char* name, State* state, + int argc, Expr* argv[]) { + char* left = Evaluate(state, argv[0]); + if (left == NULL) return NULL; + if (BooleanString(left) == true) { + free(left); + return EvaluateValue(state, argv[1]); + } else { + return StringValue(left); + } +} + +Value* LogicalOrFn(const char* name, State* state, + int argc, Expr* argv[]) { + char* left = Evaluate(state, argv[0]); + if (left == NULL) return NULL; + if (BooleanString(left) == false) { + free(left); + return EvaluateValue(state, argv[1]); + } else { + return StringValue(left); + } +} + +Value* LogicalNotFn(const char* name, State* state, + int argc, Expr* argv[]) { + char* val = Evaluate(state, argv[0]); + if (val == NULL) return NULL; + bool bv = BooleanString(val); + free(val); + return StringValue(strdup(bv ? "" : "t")); +} + +Value* SubstringFn(const char* name, State* state, + int argc, Expr* argv[]) { + char* needle = Evaluate(state, argv[0]); + if (needle == NULL) return NULL; + char* haystack = Evaluate(state, argv[1]); + if (haystack == NULL) { + free(needle); + return NULL; + } + + char* result = strdup(strstr(haystack, needle) ? "t" : ""); + free(needle); + free(haystack); + return StringValue(result); +} + +Value* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) { + char* left = Evaluate(state, argv[0]); + if (left == NULL) return NULL; + char* right = Evaluate(state, argv[1]); + if (right == NULL) { + free(left); + return NULL; + } + + char* result = strdup(strcmp(left, right) == 0 ? "t" : ""); + free(left); + free(right); + return StringValue(result); +} + +Value* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) { + char* left = Evaluate(state, argv[0]); + if (left == NULL) return NULL; + char* right = Evaluate(state, argv[1]); + if (right == NULL) { + free(left); + return NULL; + } + + char* result = strdup(strcmp(left, right) != 0 ? "t" : ""); + free(left); + free(right); + return StringValue(result); +} + +Value* SequenceFn(const char* name, State* state, int argc, Expr* argv[]) { + Value* left = EvaluateValue(state, argv[0]); + if (left == NULL) return NULL; + FreeValue(left); + return EvaluateValue(state, argv[1]); +} + +Value* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) { + if (argc != 2) { + free(state->errmsg); + state->errmsg = strdup("less_than_int expects 2 arguments"); + return NULL; + } + + char* left; + char* right; + if (ReadArgs(state, argv, 2, &left, &right) < 0) return NULL; + + bool result = false; + char* end; + + long l_int = strtol(left, &end, 10); + if (left[0] == '\0' || *end != '\0') { + goto done; + } + + long r_int; + r_int = strtol(right, &end, 10); + if (right[0] == '\0' || *end != '\0') { + goto done; + } + + result = l_int < r_int; + + done: + free(left); + free(right); + return StringValue(strdup(result ? "t" : "")); +} + +Value* GreaterThanIntFn(const char* name, State* state, + int argc, Expr* argv[]) { + if (argc != 2) { + free(state->errmsg); + state->errmsg = strdup("greater_than_int expects 2 arguments"); + return NULL; + } + + Expr* temp[2]; + temp[0] = argv[1]; + temp[1] = argv[0]; + + return LessThanIntFn(name, state, 2, temp); +} + +Value* Literal(const char* name, State* state, int argc, Expr* argv[]) { + return StringValue(strdup(name)); +} + +Expr* Build(Function fn, YYLTYPE loc, int count, ...) { + va_list v; + va_start(v, count); + Expr* e = reinterpret_cast(malloc(sizeof(Expr))); + e->fn = fn; + e->name = "(operator)"; + e->argc = count; + e->argv = reinterpret_cast(malloc(count * sizeof(Expr*))); + int i; + for (i = 0; i < count; ++i) { + e->argv[i] = va_arg(v, Expr*); + } + va_end(v); + e->start = loc.start; + e->end = loc.end; + return e; +} + +// ----------------------------------------------------------------- +// the function table +// ----------------------------------------------------------------- + +static int fn_entries = 0; +static int fn_size = 0; +NamedFunction* fn_table = NULL; + +void RegisterFunction(const char* name, Function fn) { + if (fn_entries >= fn_size) { + fn_size = fn_size*2 + 1; + fn_table = reinterpret_cast(realloc(fn_table, fn_size * sizeof(NamedFunction))); + } + fn_table[fn_entries].name = name; + fn_table[fn_entries].fn = fn; + ++fn_entries; +} + +static int fn_entry_compare(const void* a, const void* b) { + const char* na = ((const NamedFunction*)a)->name; + const char* nb = ((const NamedFunction*)b)->name; + return strcmp(na, nb); +} + +void FinishRegistration() { + qsort(fn_table, fn_entries, sizeof(NamedFunction), fn_entry_compare); +} + +Function FindFunction(const char* name) { + NamedFunction key; + key.name = name; + NamedFunction* nf = reinterpret_cast(bsearch(&key, fn_table, fn_entries, + sizeof(NamedFunction), fn_entry_compare)); + if (nf == NULL) { + return NULL; + } + return nf->fn; +} + +void RegisterBuiltins() { + RegisterFunction("ifelse", IfElseFn); + RegisterFunction("abort", AbortFn); + RegisterFunction("assert", AssertFn); + RegisterFunction("concat", ConcatFn); + RegisterFunction("is_substring", SubstringFn); + RegisterFunction("stdout", StdoutFn); + RegisterFunction("sleep", SleepFn); + + RegisterFunction("less_than_int", LessThanIntFn); + RegisterFunction("greater_than_int", GreaterThanIntFn); +} + + +// ----------------------------------------------------------------- +// convenience methods for functions +// ----------------------------------------------------------------- + +// Evaluate the expressions in argv, giving 'count' char* (the ... is +// zero or more char** to put them in). If any expression evaluates +// to NULL, free the rest and return -1. Return 0 on success. +int ReadArgs(State* state, Expr* argv[], int count, ...) { + char** args = reinterpret_cast(malloc(count * sizeof(char*))); + va_list v; + va_start(v, count); + int i; + for (i = 0; i < count; ++i) { + args[i] = Evaluate(state, argv[i]); + if (args[i] == NULL) { + va_end(v); + int j; + for (j = 0; j < i; ++j) { + free(args[j]); + } + free(args); + return -1; + } + *(va_arg(v, char**)) = args[i]; + } + va_end(v); + free(args); + return 0; +} + +// Evaluate the expressions in argv, giving 'count' Value* (the ... is +// zero or more Value** to put them in). If any expression evaluates +// to NULL, free the rest and return -1. Return 0 on success. +int ReadValueArgs(State* state, Expr* argv[], int count, ...) { + Value** args = reinterpret_cast(malloc(count * sizeof(Value*))); + va_list v; + va_start(v, count); + int i; + for (i = 0; i < count; ++i) { + args[i] = EvaluateValue(state, argv[i]); + if (args[i] == NULL) { + va_end(v); + int j; + for (j = 0; j < i; ++j) { + FreeValue(args[j]); + } + free(args); + return -1; + } + *(va_arg(v, Value**)) = args[i]; + } + va_end(v); + free(args); + return 0; +} + +// Evaluate the expressions in argv, returning an array of char* +// results. If any evaluate to NULL, free the rest and return NULL. +// The caller is responsible for freeing the returned array and the +// strings it contains. +char** ReadVarArgs(State* state, int argc, Expr* argv[]) { + char** args = (char**)malloc(argc * sizeof(char*)); + int i = 0; + for (i = 0; i < argc; ++i) { + args[i] = Evaluate(state, argv[i]); + if (args[i] == NULL) { + int j; + for (j = 0; j < i; ++j) { + free(args[j]); + } + free(args); + return NULL; + } + } + return args; +} + +// Evaluate the expressions in argv, returning an array of Value* +// results. If any evaluate to NULL, free the rest and return NULL. +// The caller is responsible for freeing the returned array and the +// Values it contains. +Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]) { + Value** args = (Value**)malloc(argc * sizeof(Value*)); + int i = 0; + for (i = 0; i < argc; ++i) { + args[i] = EvaluateValue(state, argv[i]); + if (args[i] == NULL) { + int j; + for (j = 0; j < i; ++j) { + FreeValue(args[j]); + } + free(args); + return NULL; + } + } + return args; +} + +// Use printf-style arguments to compose an error message to put into +// *state. Returns NULL. +Value* ErrorAbort(State* state, const char* format, ...) { + char* buffer = reinterpret_cast(malloc(4096)); + va_list v; + va_start(v, format); + vsnprintf(buffer, 4096, format, v); + va_end(v); + free(state->errmsg); + state->errmsg = buffer; + return NULL; +} diff --git a/edify/expr.h b/edify/expr.h index a9ed2f9c5..36f8e9612 100644 --- a/edify/expr.h +++ b/edify/expr.h @@ -21,10 +21,6 @@ #include "yydefs.h" -#ifdef __cplusplus -extern "C" { -#endif - #define MAX_STRING_LEN 1024 typedef struct Expr Expr; @@ -59,7 +55,7 @@ typedef Value* (*Function)(const char* name, State* state, struct Expr { Function fn; - char* name; + const char* name; int argc; Expr** argv; int start, end; @@ -166,8 +162,4 @@ void FreeValue(Value* v); int parse_string(const char* str, Expr** root, int* error_count); -#ifdef __cplusplus -} // extern "C" -#endif - #endif // _EXPRESSION_H diff --git a/edify/main.c b/edify/main.c deleted file mode 100644 index b1baa0b13..000000000 --- a/edify/main.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * 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 -#include -#include - -#include "expr.h" -#include "parser.h" - -extern int yyparse(Expr** root, int* error_count); - -int expect(const char* expr_str, const char* expected, int* errors) { - Expr* e; - char* result; - - printf("."); - - int error_count = parse_string(expr_str, &e, &error_count); - if (error_count > 0) { - printf("error parsing \"%s\" (%d errors)\n", - expr_str, error_count); - ++*errors; - return 0; - } - - State state; - state.cookie = NULL; - state.script = strdup(expr_str); - state.errmsg = NULL; - - result = Evaluate(&state, e); - free(state.errmsg); - free(state.script); - if (result == NULL && expected != NULL) { - printf("error evaluating \"%s\"\n", expr_str); - ++*errors; - return 0; - } - - if (result == NULL && expected == NULL) { - return 1; - } - - if (strcmp(result, expected) != 0) { - printf("evaluating \"%s\": expected \"%s\", got \"%s\"\n", - expr_str, expected, result); - ++*errors; - free(result); - return 0; - } - - free(result); - return 1; -} - -int test() { - int errors = 0; - - expect("a", "a", &errors); - expect("\"a\"", "a", &errors); - expect("\"\\x61\"", "a", &errors); - expect("# this is a comment\n" - " a\n" - " \n", - "a", &errors); - - - // sequence operator - expect("a; b; c", "c", &errors); - - // string concat operator - expect("a + b", "ab", &errors); - expect("a + \n \"b\"", "ab", &errors); - expect("a + b +\nc\n", "abc", &errors); - - // string concat function - expect("concat(a, b)", "ab", &errors); - expect("concat(a,\n \"b\")", "ab", &errors); - expect("concat(a + b,\nc,\"d\")", "abcd", &errors); - expect("\"concat\"(a + b,\nc,\"d\")", "abcd", &errors); - - // logical and - expect("a && b", "b", &errors); - expect("a && \"\"", "", &errors); - expect("\"\" && b", "", &errors); - expect("\"\" && \"\"", "", &errors); - expect("\"\" && abort()", "", &errors); // test short-circuiting - expect("t && abort()", NULL, &errors); - - // logical or - expect("a || b", "a", &errors); - expect("a || \"\"", "a", &errors); - expect("\"\" || b", "b", &errors); - expect("\"\" || \"\"", "", &errors); - expect("a || abort()", "a", &errors); // test short-circuiting - expect("\"\" || abort()", NULL, &errors); - - // logical not - expect("!a", "", &errors); - expect("! \"\"", "t", &errors); - expect("!!a", "t", &errors); - - // precedence - expect("\"\" == \"\" && b", "b", &errors); - expect("a + b == ab", "t", &errors); - expect("ab == a + b", "t", &errors); - expect("a + (b == ab)", "a", &errors); - expect("(ab == a) + b", "b", &errors); - - // substring function - expect("is_substring(cad, abracadabra)", "t", &errors); - expect("is_substring(abrac, abracadabra)", "t", &errors); - expect("is_substring(dabra, abracadabra)", "t", &errors); - expect("is_substring(cad, abracxadabra)", "", &errors); - expect("is_substring(abrac, axbracadabra)", "", &errors); - expect("is_substring(dabra, abracadabrxa)", "", &errors); - - // ifelse function - expect("ifelse(t, yes, no)", "yes", &errors); - expect("ifelse(!t, yes, no)", "no", &errors); - expect("ifelse(t, yes, abort())", "yes", &errors); - expect("ifelse(!t, abort(), no)", "no", &errors); - - // if "statements" - expect("if t then yes else no endif", "yes", &errors); - expect("if \"\" then yes else no endif", "no", &errors); - expect("if \"\" then yes endif", "", &errors); - expect("if \"\"; t then yes endif", "yes", &errors); - - // numeric comparisons - expect("less_than_int(3, 14)", "t", &errors); - expect("less_than_int(14, 3)", "", &errors); - expect("less_than_int(x, 3)", "", &errors); - expect("less_than_int(3, x)", "", &errors); - expect("greater_than_int(3, 14)", "", &errors); - expect("greater_than_int(14, 3)", "t", &errors); - expect("greater_than_int(x, 3)", "", &errors); - expect("greater_than_int(3, x)", "", &errors); - - printf("\n"); - - return errors; -} - -void ExprDump(int depth, Expr* n, char* script) { - printf("%*s", depth*2, ""); - char temp = script[n->end]; - script[n->end] = '\0'; - printf("%s %p (%d-%d) \"%s\"\n", - n->name == NULL ? "(NULL)" : n->name, n->fn, n->start, n->end, - script+n->start); - script[n->end] = temp; - int i; - for (i = 0; i < n->argc; ++i) { - ExprDump(depth+1, n->argv[i], script); - } -} - -int main(int argc, char** argv) { - RegisterBuiltins(); - FinishRegistration(); - - if (argc == 1) { - return test() != 0; - } - - FILE* f = fopen(argv[1], "r"); - if (f == NULL) { - printf("%s: %s: No such file or directory\n", argv[0], argv[1]); - return 1; - } - char buffer[8192]; - int size = fread(buffer, 1, 8191, f); - fclose(f); - buffer[size] = '\0'; - - Expr* root; - int error_count = 0; - int error = parse_string(buffer, &root, &error_count); - printf("parse returned %d; %d errors encountered\n", error, error_count); - if (error == 0 || error_count > 0) { - - ExprDump(0, root, buffer); - - State state; - state.cookie = NULL; - state.script = buffer; - state.errmsg = NULL; - - char* result = Evaluate(&state, root); - if (result == NULL) { - printf("result was NULL, message is: %s\n", - (state.errmsg == NULL ? "(NULL)" : state.errmsg)); - free(state.errmsg); - } else { - printf("result is [%s]\n", result); - } - } - return 0; -} diff --git a/edify/main.cpp b/edify/main.cpp new file mode 100644 index 000000000..b1baa0b13 --- /dev/null +++ b/edify/main.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * 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 +#include +#include + +#include "expr.h" +#include "parser.h" + +extern int yyparse(Expr** root, int* error_count); + +int expect(const char* expr_str, const char* expected, int* errors) { + Expr* e; + char* result; + + printf("."); + + int error_count = parse_string(expr_str, &e, &error_count); + if (error_count > 0) { + printf("error parsing \"%s\" (%d errors)\n", + expr_str, error_count); + ++*errors; + return 0; + } + + State state; + state.cookie = NULL; + state.script = strdup(expr_str); + state.errmsg = NULL; + + result = Evaluate(&state, e); + free(state.errmsg); + free(state.script); + if (result == NULL && expected != NULL) { + printf("error evaluating \"%s\"\n", expr_str); + ++*errors; + return 0; + } + + if (result == NULL && expected == NULL) { + return 1; + } + + if (strcmp(result, expected) != 0) { + printf("evaluating \"%s\": expected \"%s\", got \"%s\"\n", + expr_str, expected, result); + ++*errors; + free(result); + return 0; + } + + free(result); + return 1; +} + +int test() { + int errors = 0; + + expect("a", "a", &errors); + expect("\"a\"", "a", &errors); + expect("\"\\x61\"", "a", &errors); + expect("# this is a comment\n" + " a\n" + " \n", + "a", &errors); + + + // sequence operator + expect("a; b; c", "c", &errors); + + // string concat operator + expect("a + b", "ab", &errors); + expect("a + \n \"b\"", "ab", &errors); + expect("a + b +\nc\n", "abc", &errors); + + // string concat function + expect("concat(a, b)", "ab", &errors); + expect("concat(a,\n \"b\")", "ab", &errors); + expect("concat(a + b,\nc,\"d\")", "abcd", &errors); + expect("\"concat\"(a + b,\nc,\"d\")", "abcd", &errors); + + // logical and + expect("a && b", "b", &errors); + expect("a && \"\"", "", &errors); + expect("\"\" && b", "", &errors); + expect("\"\" && \"\"", "", &errors); + expect("\"\" && abort()", "", &errors); // test short-circuiting + expect("t && abort()", NULL, &errors); + + // logical or + expect("a || b", "a", &errors); + expect("a || \"\"", "a", &errors); + expect("\"\" || b", "b", &errors); + expect("\"\" || \"\"", "", &errors); + expect("a || abort()", "a", &errors); // test short-circuiting + expect("\"\" || abort()", NULL, &errors); + + // logical not + expect("!a", "", &errors); + expect("! \"\"", "t", &errors); + expect("!!a", "t", &errors); + + // precedence + expect("\"\" == \"\" && b", "b", &errors); + expect("a + b == ab", "t", &errors); + expect("ab == a + b", "t", &errors); + expect("a + (b == ab)", "a", &errors); + expect("(ab == a) + b", "b", &errors); + + // substring function + expect("is_substring(cad, abracadabra)", "t", &errors); + expect("is_substring(abrac, abracadabra)", "t", &errors); + expect("is_substring(dabra, abracadabra)", "t", &errors); + expect("is_substring(cad, abracxadabra)", "", &errors); + expect("is_substring(abrac, axbracadabra)", "", &errors); + expect("is_substring(dabra, abracadabrxa)", "", &errors); + + // ifelse function + expect("ifelse(t, yes, no)", "yes", &errors); + expect("ifelse(!t, yes, no)", "no", &errors); + expect("ifelse(t, yes, abort())", "yes", &errors); + expect("ifelse(!t, abort(), no)", "no", &errors); + + // if "statements" + expect("if t then yes else no endif", "yes", &errors); + expect("if \"\" then yes else no endif", "no", &errors); + expect("if \"\" then yes endif", "", &errors); + expect("if \"\"; t then yes endif", "yes", &errors); + + // numeric comparisons + expect("less_than_int(3, 14)", "t", &errors); + expect("less_than_int(14, 3)", "", &errors); + expect("less_than_int(x, 3)", "", &errors); + expect("less_than_int(3, x)", "", &errors); + expect("greater_than_int(3, 14)", "", &errors); + expect("greater_than_int(14, 3)", "t", &errors); + expect("greater_than_int(x, 3)", "", &errors); + expect("greater_than_int(3, x)", "", &errors); + + printf("\n"); + + return errors; +} + +void ExprDump(int depth, Expr* n, char* script) { + printf("%*s", depth*2, ""); + char temp = script[n->end]; + script[n->end] = '\0'; + printf("%s %p (%d-%d) \"%s\"\n", + n->name == NULL ? "(NULL)" : n->name, n->fn, n->start, n->end, + script+n->start); + script[n->end] = temp; + int i; + for (i = 0; i < n->argc; ++i) { + ExprDump(depth+1, n->argv[i], script); + } +} + +int main(int argc, char** argv) { + RegisterBuiltins(); + FinishRegistration(); + + if (argc == 1) { + return test() != 0; + } + + FILE* f = fopen(argv[1], "r"); + if (f == NULL) { + printf("%s: %s: No such file or directory\n", argv[0], argv[1]); + return 1; + } + char buffer[8192]; + int size = fread(buffer, 1, 8191, f); + fclose(f); + buffer[size] = '\0'; + + Expr* root; + int error_count = 0; + int error = parse_string(buffer, &root, &error_count); + printf("parse returned %d; %d errors encountered\n", error, error_count); + if (error == 0 || error_count > 0) { + + ExprDump(0, root, buffer); + + State state; + state.cookie = NULL; + state.script = buffer; + state.errmsg = NULL; + + char* result = Evaluate(&state, root); + if (result == NULL) { + printf("result was NULL, message is: %s\n", + (state.errmsg == NULL ? "(NULL)" : state.errmsg)); + free(state.errmsg); + } else { + printf("result is [%s]\n", result); + } + } + return 0; +} diff --git a/edify/parser.y b/edify/parser.y index f8fb2d12f..098a6370a 100644 --- a/edify/parser.y +++ b/edify/parser.y @@ -70,7 +70,7 @@ input: expr { *root = $1; } ; expr: STRING { - $$ = malloc(sizeof(Expr)); + $$ = reinterpret_cast(malloc(sizeof(Expr))); $$->fn = Literal; $$->name = $1; $$->argc = 0; @@ -91,7 +91,7 @@ expr: STRING { | IF expr THEN expr ENDIF { $$ = Build(IfElseFn, @$, 2, $2, $4); } | IF expr THEN expr ELSE expr ENDIF { $$ = Build(IfElseFn, @$, 3, $2, $4, $6); } | STRING '(' arglist ')' { - $$ = malloc(sizeof(Expr)); + $$ = reinterpret_cast(malloc(sizeof(Expr))); $$->fn = FindFunction($1); if ($$->fn == NULL) { char buffer[256]; @@ -113,12 +113,12 @@ arglist: /* empty */ { } | expr { $$.argc = 1; - $$.argv = malloc(sizeof(Expr*)); + $$.argv = reinterpret_cast(malloc(sizeof(Expr*))); $$.argv[0] = $1; } | arglist ',' expr { $$.argc = $1.argc + 1; - $$.argv = realloc($$.argv, $$.argc * sizeof(Expr*)); + $$.argv = reinterpret_cast(realloc($$.argv, $$.argc * sizeof(Expr*))); $$.argv[$$.argc-1] = $3; } ; -- cgit v1.2.3 From c8abc4ec45ae9c5310097a02a406cd663e5457ea Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Mon, 11 Jan 2016 18:14:17 -0800 Subject: Rename .l/.y to .ll/.yy Now to generate .cpp you need to use .ll/.yy. Bug: 26492989 Change-Id: Ib078e03b3b0758f7a62595c343e52ae856bcb33f --- edify/Android.mk | 4 +- edify/lexer.l | 112 -------------------------------------------- edify/lexer.ll | 112 ++++++++++++++++++++++++++++++++++++++++++++ edify/parser.y | 139 ------------------------------------------------------- edify/parser.yy | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 253 insertions(+), 253 deletions(-) delete mode 100644 edify/lexer.l create mode 100644 edify/lexer.ll delete mode 100644 edify/parser.y create mode 100644 edify/parser.yy (limited to 'edify') diff --git a/edify/Android.mk b/edify/Android.mk index 9b859d42e..038dec088 100644 --- a/edify/Android.mk +++ b/edify/Android.mk @@ -3,8 +3,8 @@ LOCAL_PATH := $(call my-dir) edify_src_files := \ - lexer.l \ - parser.y \ + lexer.ll \ + parser.yy \ expr.cpp # diff --git a/edify/lexer.l b/edify/lexer.l deleted file mode 100644 index fb2933bee..000000000 --- a/edify/lexer.l +++ /dev/null @@ -1,112 +0,0 @@ -%{ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * 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 - -#include "expr.h" -#include "yydefs.h" -#include "parser.h" - -int gLine = 1; -int gColumn = 1; -int gPos = 0; - -// TODO: enforce MAX_STRING_LEN during lexing -char string_buffer[MAX_STRING_LEN]; -char* string_pos; - -#define ADVANCE do {yylloc.start=gPos; yylloc.end=gPos+yyleng; \ - gColumn+=yyleng; gPos+=yyleng;} while(0) - -%} - -%x STR - -%option noyywrap - -%% - - -\" { - BEGIN(STR); - string_pos = string_buffer; - yylloc.start = gPos; - ++gColumn; - ++gPos; -} - -{ - \" { - ++gColumn; - ++gPos; - BEGIN(INITIAL); - *string_pos = '\0'; - yylval.str = strdup(string_buffer); - yylloc.end = gPos; - return STRING; - } - - \\n { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\n'; } - \\t { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\t'; } - \\\" { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\"'; } - \\\\ { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\\'; } - - \\x[0-9a-fA-F]{2} { - gColumn += yyleng; - gPos += yyleng; - int val; - sscanf(yytext+2, "%x", &val); - *string_pos++ = val; - } - - \n { - ++gLine; - ++gPos; - gColumn = 1; - *string_pos++ = yytext[0]; - } - - . { - ++gColumn; - ++gPos; - *string_pos++ = yytext[0]; - } -} - -if ADVANCE; return IF; -then ADVANCE; return THEN; -else ADVANCE; return ELSE; -endif ADVANCE; return ENDIF; - -[a-zA-Z0-9_:/.]+ { - ADVANCE; - yylval.str = strdup(yytext); - return STRING; -} - -\&\& ADVANCE; return AND; -\|\| ADVANCE; return OR; -== ADVANCE; return EQ; -!= ADVANCE; return NE; - -[+(),!;] ADVANCE; return yytext[0]; - -[ \t]+ ADVANCE; - -(#.*)?\n gPos += yyleng; ++gLine; gColumn = 1; - -. return BAD; diff --git a/edify/lexer.ll b/edify/lexer.ll new file mode 100644 index 000000000..fb2933bee --- /dev/null +++ b/edify/lexer.ll @@ -0,0 +1,112 @@ +%{ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * 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 + +#include "expr.h" +#include "yydefs.h" +#include "parser.h" + +int gLine = 1; +int gColumn = 1; +int gPos = 0; + +// TODO: enforce MAX_STRING_LEN during lexing +char string_buffer[MAX_STRING_LEN]; +char* string_pos; + +#define ADVANCE do {yylloc.start=gPos; yylloc.end=gPos+yyleng; \ + gColumn+=yyleng; gPos+=yyleng;} while(0) + +%} + +%x STR + +%option noyywrap + +%% + + +\" { + BEGIN(STR); + string_pos = string_buffer; + yylloc.start = gPos; + ++gColumn; + ++gPos; +} + +{ + \" { + ++gColumn; + ++gPos; + BEGIN(INITIAL); + *string_pos = '\0'; + yylval.str = strdup(string_buffer); + yylloc.end = gPos; + return STRING; + } + + \\n { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\n'; } + \\t { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\t'; } + \\\" { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\"'; } + \\\\ { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\\'; } + + \\x[0-9a-fA-F]{2} { + gColumn += yyleng; + gPos += yyleng; + int val; + sscanf(yytext+2, "%x", &val); + *string_pos++ = val; + } + + \n { + ++gLine; + ++gPos; + gColumn = 1; + *string_pos++ = yytext[0]; + } + + . { + ++gColumn; + ++gPos; + *string_pos++ = yytext[0]; + } +} + +if ADVANCE; return IF; +then ADVANCE; return THEN; +else ADVANCE; return ELSE; +endif ADVANCE; return ENDIF; + +[a-zA-Z0-9_:/.]+ { + ADVANCE; + yylval.str = strdup(yytext); + return STRING; +} + +\&\& ADVANCE; return AND; +\|\| ADVANCE; return OR; +== ADVANCE; return EQ; +!= ADVANCE; return NE; + +[+(),!;] ADVANCE; return yytext[0]; + +[ \t]+ ADVANCE; + +(#.*)?\n gPos += yyleng; ++gLine; gColumn = 1; + +. return BAD; diff --git a/edify/parser.y b/edify/parser.y deleted file mode 100644 index 098a6370a..000000000 --- a/edify/parser.y +++ /dev/null @@ -1,139 +0,0 @@ -%{ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * 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 -#include -#include - -#include "expr.h" -#include "yydefs.h" -#include "parser.h" - -extern int gLine; -extern int gColumn; - -void yyerror(Expr** root, int* error_count, const char* s); -int yyparse(Expr** root, int* error_count); - -struct yy_buffer_state; -void yy_switch_to_buffer(struct yy_buffer_state* new_buffer); -struct yy_buffer_state* yy_scan_string(const char* yystr); - -%} - -%locations - -%union { - char* str; - Expr* expr; - struct { - int argc; - Expr** argv; - } args; -} - -%token AND OR SUBSTR SUPERSTR EQ NE IF THEN ELSE ENDIF -%token STRING BAD -%type expr -%type arglist - -%parse-param {Expr** root} -%parse-param {int* error_count} -%error-verbose - -/* declarations in increasing order of precedence */ -%left ';' -%left ',' -%left OR -%left AND -%left EQ NE -%left '+' -%right '!' - -%% - -input: expr { *root = $1; } -; - -expr: STRING { - $$ = reinterpret_cast(malloc(sizeof(Expr))); - $$->fn = Literal; - $$->name = $1; - $$->argc = 0; - $$->argv = NULL; - $$->start = @$.start; - $$->end = @$.end; -} -| '(' expr ')' { $$ = $2; $$->start=@$.start; $$->end=@$.end; } -| expr ';' { $$ = $1; $$->start=@1.start; $$->end=@1.end; } -| expr ';' expr { $$ = Build(SequenceFn, @$, 2, $1, $3); } -| error ';' expr { $$ = $3; $$->start=@$.start; $$->end=@$.end; } -| expr '+' expr { $$ = Build(ConcatFn, @$, 2, $1, $3); } -| expr EQ expr { $$ = Build(EqualityFn, @$, 2, $1, $3); } -| expr NE expr { $$ = Build(InequalityFn, @$, 2, $1, $3); } -| expr AND expr { $$ = Build(LogicalAndFn, @$, 2, $1, $3); } -| expr OR expr { $$ = Build(LogicalOrFn, @$, 2, $1, $3); } -| '!' expr { $$ = Build(LogicalNotFn, @$, 1, $2); } -| IF expr THEN expr ENDIF { $$ = Build(IfElseFn, @$, 2, $2, $4); } -| IF expr THEN expr ELSE expr ENDIF { $$ = Build(IfElseFn, @$, 3, $2, $4, $6); } -| STRING '(' arglist ')' { - $$ = reinterpret_cast(malloc(sizeof(Expr))); - $$->fn = FindFunction($1); - if ($$->fn == NULL) { - char buffer[256]; - snprintf(buffer, sizeof(buffer), "unknown function \"%s\"", $1); - yyerror(root, error_count, buffer); - YYERROR; - } - $$->name = $1; - $$->argc = $3.argc; - $$->argv = $3.argv; - $$->start = @$.start; - $$->end = @$.end; -} -; - -arglist: /* empty */ { - $$.argc = 0; - $$.argv = NULL; -} -| expr { - $$.argc = 1; - $$.argv = reinterpret_cast(malloc(sizeof(Expr*))); - $$.argv[0] = $1; -} -| arglist ',' expr { - $$.argc = $1.argc + 1; - $$.argv = reinterpret_cast(realloc($$.argv, $$.argc * sizeof(Expr*))); - $$.argv[$$.argc-1] = $3; -} -; - -%% - -void yyerror(Expr** root, int* error_count, const char* s) { - if (strlen(s) == 0) { - s = "syntax error"; - } - printf("line %d col %d: %s\n", gLine, gColumn, s); - ++*error_count; -} - -int parse_string(const char* str, Expr** root, int* error_count) { - yy_switch_to_buffer(yy_scan_string(str)); - return yyparse(root, error_count); -} diff --git a/edify/parser.yy b/edify/parser.yy new file mode 100644 index 000000000..098a6370a --- /dev/null +++ b/edify/parser.yy @@ -0,0 +1,139 @@ +%{ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * 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 +#include +#include + +#include "expr.h" +#include "yydefs.h" +#include "parser.h" + +extern int gLine; +extern int gColumn; + +void yyerror(Expr** root, int* error_count, const char* s); +int yyparse(Expr** root, int* error_count); + +struct yy_buffer_state; +void yy_switch_to_buffer(struct yy_buffer_state* new_buffer); +struct yy_buffer_state* yy_scan_string(const char* yystr); + +%} + +%locations + +%union { + char* str; + Expr* expr; + struct { + int argc; + Expr** argv; + } args; +} + +%token AND OR SUBSTR SUPERSTR EQ NE IF THEN ELSE ENDIF +%token STRING BAD +%type expr +%type arglist + +%parse-param {Expr** root} +%parse-param {int* error_count} +%error-verbose + +/* declarations in increasing order of precedence */ +%left ';' +%left ',' +%left OR +%left AND +%left EQ NE +%left '+' +%right '!' + +%% + +input: expr { *root = $1; } +; + +expr: STRING { + $$ = reinterpret_cast(malloc(sizeof(Expr))); + $$->fn = Literal; + $$->name = $1; + $$->argc = 0; + $$->argv = NULL; + $$->start = @$.start; + $$->end = @$.end; +} +| '(' expr ')' { $$ = $2; $$->start=@$.start; $$->end=@$.end; } +| expr ';' { $$ = $1; $$->start=@1.start; $$->end=@1.end; } +| expr ';' expr { $$ = Build(SequenceFn, @$, 2, $1, $3); } +| error ';' expr { $$ = $3; $$->start=@$.start; $$->end=@$.end; } +| expr '+' expr { $$ = Build(ConcatFn, @$, 2, $1, $3); } +| expr EQ expr { $$ = Build(EqualityFn, @$, 2, $1, $3); } +| expr NE expr { $$ = Build(InequalityFn, @$, 2, $1, $3); } +| expr AND expr { $$ = Build(LogicalAndFn, @$, 2, $1, $3); } +| expr OR expr { $$ = Build(LogicalOrFn, @$, 2, $1, $3); } +| '!' expr { $$ = Build(LogicalNotFn, @$, 1, $2); } +| IF expr THEN expr ENDIF { $$ = Build(IfElseFn, @$, 2, $2, $4); } +| IF expr THEN expr ELSE expr ENDIF { $$ = Build(IfElseFn, @$, 3, $2, $4, $6); } +| STRING '(' arglist ')' { + $$ = reinterpret_cast(malloc(sizeof(Expr))); + $$->fn = FindFunction($1); + if ($$->fn == NULL) { + char buffer[256]; + snprintf(buffer, sizeof(buffer), "unknown function \"%s\"", $1); + yyerror(root, error_count, buffer); + YYERROR; + } + $$->name = $1; + $$->argc = $3.argc; + $$->argv = $3.argv; + $$->start = @$.start; + $$->end = @$.end; +} +; + +arglist: /* empty */ { + $$.argc = 0; + $$.argv = NULL; +} +| expr { + $$.argc = 1; + $$.argv = reinterpret_cast(malloc(sizeof(Expr*))); + $$.argv[0] = $1; +} +| arglist ',' expr { + $$.argc = $1.argc + 1; + $$.argv = reinterpret_cast(realloc($$.argv, $$.argc * sizeof(Expr*))); + $$.argv[$$.argc-1] = $3; +} +; + +%% + +void yyerror(Expr** root, int* error_count, const char* s) { + if (strlen(s) == 0) { + s = "syntax error"; + } + printf("line %d col %d: %s\n", gLine, gColumn, s); + ++*error_count; +} + +int parse_string(const char* str, Expr** root, int* error_count) { + yy_switch_to_buffer(yy_scan_string(str)); + return yyparse(root, error_count); +} -- cgit v1.2.3 From 12f499e86db50cbb1b4990c94668a9de37653907 Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Wed, 27 Jan 2016 12:26:18 -0800 Subject: edify: accept long string literal. Bug: 24717917 Change-Id: I134cf00ae7efbc3703f976459a1b9f9a197e495d --- edify/lexer.ll | 24 +++++++++++------------- edify/main.cpp | 5 +++++ 2 files changed, 16 insertions(+), 13 deletions(-) (limited to 'edify') diff --git a/edify/lexer.ll b/edify/lexer.ll index fb2933bee..b764d1699 100644 --- a/edify/lexer.ll +++ b/edify/lexer.ll @@ -16,6 +16,7 @@ */ #include +#include #include "expr.h" #include "yydefs.h" @@ -25,9 +26,7 @@ int gLine = 1; int gColumn = 1; int gPos = 0; -// TODO: enforce MAX_STRING_LEN during lexing -char string_buffer[MAX_STRING_LEN]; -char* string_pos; +std::string string_buffer; #define ADVANCE do {yylloc.start=gPos; yylloc.end=gPos+yyleng; \ gColumn+=yyleng; gPos+=yyleng;} while(0) @@ -43,7 +42,7 @@ char* string_pos; \" { BEGIN(STR); - string_pos = string_buffer; + string_buffer.clear(); yylloc.start = gPos; ++gColumn; ++gPos; @@ -54,36 +53,35 @@ char* string_pos; ++gColumn; ++gPos; BEGIN(INITIAL); - *string_pos = '\0'; - yylval.str = strdup(string_buffer); + yylval.str = strdup(string_buffer.c_str()); yylloc.end = gPos; return STRING; } - \\n { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\n'; } - \\t { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\t'; } - \\\" { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\"'; } - \\\\ { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\\'; } + \\n { gColumn += yyleng; gPos += yyleng; string_buffer.push_back('\n'); } + \\t { gColumn += yyleng; gPos += yyleng; string_buffer.push_back('\t'); } + \\\" { gColumn += yyleng; gPos += yyleng; string_buffer.push_back('\"'); } + \\\\ { gColumn += yyleng; gPos += yyleng; string_buffer.push_back('\\'); } \\x[0-9a-fA-F]{2} { gColumn += yyleng; gPos += yyleng; int val; sscanf(yytext+2, "%x", &val); - *string_pos++ = val; + string_buffer.push_back(static_cast(val)); } \n { ++gLine; ++gPos; gColumn = 1; - *string_pos++ = yytext[0]; + string_buffer.push_back(yytext[0]); } . { ++gColumn; ++gPos; - *string_pos++ = yytext[0]; + string_buffer.push_back(yytext[0]); } } diff --git a/edify/main.cpp b/edify/main.cpp index b1baa0b13..6007a3d58 100644 --- a/edify/main.cpp +++ b/edify/main.cpp @@ -18,6 +18,8 @@ #include #include +#include + #include "expr.h" #include "parser.h" @@ -151,6 +153,9 @@ int test() { expect("greater_than_int(x, 3)", "", &errors); expect("greater_than_int(3, x)", "", &errors); + // big string + expect(std::string(8192, 's').c_str(), std::string(8192, 's').c_str(), &errors); + printf("\n"); return errors; -- cgit v1.2.3 From 162558382b768a4120b3e41090a4c7b53f11469a Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Sat, 30 Apr 2016 11:49:59 -0700 Subject: Allow recovery to return error codes Write error code, cause code, and retry count into last_install. So we can have more information about the reason of a failed OTA. Example of new last_install: @/cache/recovery/block.map package name 0 install result retry: 1 retry count (new) error: 30 error code (new) cause: 12 error cause (new) Details in: go/android-ota-errorcode Bug: 28471955 Change-Id: I00e7153c821e7355c1be81a86c7f228108f3dc37 --- edify/Android.mk | 4 ++++ edify/expr.cpp | 39 +++++++++++++++++++++++++++++---------- edify/expr.h | 18 +++++++++++++++++- 3 files changed, 50 insertions(+), 11 deletions(-) (limited to 'edify') diff --git a/edify/Android.mk b/edify/Android.mk index 038dec088..71cf7652a 100644 --- a/edify/Android.mk +++ b/edify/Android.mk @@ -22,6 +22,8 @@ LOCAL_YACCFLAGS := -v LOCAL_CPPFLAGS += -Wno-unused-parameter LOCAL_CPPFLAGS += -Wno-deprecated-register LOCAL_CLANG := true +LOCAL_C_INCLUDES += $(LOCAL_PATH)/.. +LOCAL_STATIC_LIBRARIES += libbase include $(BUILD_HOST_EXECUTABLE) @@ -36,5 +38,7 @@ LOCAL_CPPFLAGS := -Wno-unused-parameter LOCAL_CPPFLAGS += -Wno-deprecated-register LOCAL_MODULE := libedify LOCAL_CLANG := true +LOCAL_C_INCLUDES += $(LOCAL_PATH)/.. +LOCAL_STATIC_LIBRARIES += libbase include $(BUILD_STATIC_LIBRARY) diff --git a/edify/expr.cpp b/edify/expr.cpp index cd1e08726..cc14fbe93 100644 --- a/edify/expr.cpp +++ b/edify/expr.cpp @@ -21,6 +21,11 @@ #include #include +#include + +#include +#include + #include "expr.h" // Functions should: @@ -36,7 +41,7 @@ char* Evaluate(State* state, Expr* expr) { Value* v = expr->fn(expr->name, state, expr->argc, expr->argv); if (v == NULL) return NULL; if (v->type != VAL_STRING) { - ErrorAbort(state, "expecting string, got value type %d", v->type); + ErrorAbort(state, kArgsParsingFailure, "expecting string, got value type %d", v->type); FreeValue(v); return NULL; } @@ -493,15 +498,29 @@ Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]) { return args; } +static void ErrorAbortV(State* state, const char* format, va_list ap) { + std::string buffer; + android::base::StringAppendV(&buffer, format, ap); + free(state->errmsg); + state->errmsg = strdup(buffer.c_str()); + return; +} + // Use printf-style arguments to compose an error message to put into -// *state. Returns NULL. +// *state. Returns nullptr. Value* ErrorAbort(State* state, const char* format, ...) { - char* buffer = reinterpret_cast(malloc(4096)); - va_list v; - va_start(v, format); - vsnprintf(buffer, 4096, format, v); - va_end(v); - free(state->errmsg); - state->errmsg = buffer; - return NULL; + va_list ap; + va_start(ap, format); + ErrorAbortV(state, format, ap); + va_end(ap); + return nullptr; +} + +Value* ErrorAbort(State* state, CauseCode cause_code, const char* format, ...) { + va_list ap; + va_start(ap, format); + ErrorAbortV(state, format, ap); + va_end(ap); + state->cause_code = cause_code; + return nullptr; } diff --git a/edify/expr.h b/edify/expr.h index 36f8e9612..5c06de846 100644 --- a/edify/expr.h +++ b/edify/expr.h @@ -19,6 +19,7 @@ #include +#include "error_code.h" #include "yydefs.h" #define MAX_STRING_LEN 1024 @@ -39,6 +40,15 @@ typedef struct { // Should be NULL initially, will be either NULL or a malloc'd // pointer after Evaluate() returns. char* errmsg; + + // error code indicates the type of failure (e.g. failure to update system image) + // during the OTA process. + ErrorCode error_code = kNoError; + + // cause code provides more detailed reason of an OTA failure (e.g. fsync error) + // in addition to the error code. + CauseCode cause_code = kNoCause; + } State; #define VAL_STRING 1 // data will be NULL-terminated; size doesn't count null @@ -152,7 +162,13 @@ Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]); // Use printf-style arguments to compose an error message to put into // *state. Returns NULL. -Value* ErrorAbort(State* state, const char* format, ...) __attribute__((format(printf, 2, 3))); +Value* ErrorAbort(State* state, const char* format, ...) + __attribute__((format(printf, 2, 3), deprecated)); + +// ErrorAbort has an optional (but recommended) argument 'cause_code'. If the cause code +// is set, it will be logged into last_install and provides reason of OTA failures. +Value* ErrorAbort(State* state, CauseCode cause_code, const char* format, ...) + __attribute__((format(printf, 3, 4))); // Wrap a string into a Value, taking ownership of the string. Value* StringValue(char* str); -- cgit v1.2.3 From 7ce287d432dd3a4dc8841fc59e11ee1a0b7808a1 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Tue, 31 May 2016 09:29:49 -0700 Subject: Call ioctl before each write on retry If the update is a retry, ioctl(BLKDISCARD) the destination blocks before writing to these blocks. Bug: 28990135 Change-Id: I1e703808e68ebb1292cd66afd76be8fd6946ee59 --- edify/expr.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'edify') diff --git a/edify/expr.h b/edify/expr.h index 5c06de846..886347991 100644 --- a/edify/expr.h +++ b/edify/expr.h @@ -49,6 +49,8 @@ typedef struct { // in addition to the error code. CauseCode cause_code = kNoCause; + bool is_retry = false; + } State; #define VAL_STRING 1 // data will be NULL-terminated; size doesn't count null -- cgit v1.2.3