From 0193d490b88bba3b8eedfb1d1ac8e2157ed9e4ca Mon Sep 17 00:00:00 2001 From: Lizzzka007 <gashchuk2011@mail.ru> Date: Thu, 21 Dec 2023 01:16:00 +0300 Subject: [PATCH] Add parser --- CMakeLists.txt | 5 + parser/CMakeLists.txt | 54 + parser/call_parser.F90 | 87 ++ parser/call_parser.c | 38 + parser/call_parser.cpp | 78 ++ parser/call_parser.h | 20 + parser/cfg-cmd.cpp | 157 +++ parser/cfg-cmd.h | 70 ++ parser/cfg-value.cpp | 1092 +++++++++++++++++ parser/cfg-value.h | 140 +++ parser/cfg-vec.cpp | 816 +++++++++++++ parser/cfg-vec.h | 146 +++ parser/config-parser.cpp | 2382 ++++++++++++++++++++++++++++++++++++++ parser/config-parser.h | 191 +++ parser/io-guts.cpp | 152 +++ parser/io-guts.h | 39 + parser/lexeme-list.cpp | 159 +++ parser/lexeme-list.h | 71 ++ parser/lexeme-parser.cpp | 604 ++++++++++ parser/lexeme-parser.h | 49 + parser/lexeme.cpp | 173 +++ parser/lexeme.h | 112 ++ parser/mem-buffer.h | 148 +++ parser/scm-mem.h | 523 +++++++++ parser/scm-sys.h | 50 + 25 files changed, 7356 insertions(+) create mode 100644 parser/CMakeLists.txt create mode 100644 parser/call_parser.F90 create mode 100644 parser/call_parser.c create mode 100644 parser/call_parser.cpp create mode 100644 parser/call_parser.h create mode 100644 parser/cfg-cmd.cpp create mode 100644 parser/cfg-cmd.h create mode 100644 parser/cfg-value.cpp create mode 100644 parser/cfg-value.h create mode 100644 parser/cfg-vec.cpp create mode 100644 parser/cfg-vec.h create mode 100644 parser/config-parser.cpp create mode 100644 parser/config-parser.h create mode 100644 parser/io-guts.cpp create mode 100644 parser/io-guts.h create mode 100644 parser/lexeme-list.cpp create mode 100644 parser/lexeme-list.h create mode 100644 parser/lexeme-parser.cpp create mode 100644 parser/lexeme-parser.h create mode 100644 parser/lexeme.cpp create mode 100644 parser/lexeme.h create mode 100644 parser/mem-buffer.h create mode 100644 parser/scm-mem.h create mode 100644 parser/scm-sys.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a846f6..0261993 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,9 +132,14 @@ if(INCLUDE_CXX OR INCLUDE_CUDA) set(CMAKE_CUDA_FLAGS " -g ") endif(INCLUDE_CXX OR INCLUDE_CUDA) +add_subdirectory(parser/) + add_executable(drag ${SOURCES}) add_definitions(${RUN_MACRO}) set_property(TARGET drag PROPERTY LINKER_LANGUAGE Fortran) +target_include_directories(drag PUBLIC ${CMAKE_BINARY_DIR}/modules/) +target_link_libraries(drag parser_F parser_CXX) + #copy data on post build add_custom_command( diff --git a/parser/CMakeLists.txt b/parser/CMakeLists.txt new file mode 100644 index 0000000..da342d4 --- /dev/null +++ b/parser/CMakeLists.txt @@ -0,0 +1,54 @@ +cmake_minimum_required(VERSION 3.0) + +# option(INCLUDE_CXX "CXX build in mode" OFF) + +project(Pars) + +enable_language(Fortran) +enable_language(C) +enable_language(CXX) +set(CMAKE_CXX_STANDARD 11) + +set(SOURCES_CXX + call_parser.cpp + cfg-cmd.cpp + cfg-value.cpp + cfg-vec.cpp + config-parser.cpp + lexeme.cpp + lexeme-list.cpp + io-guts.cpp + lexeme-parser.cpp +) +set(HEADERS_CXX + call_parser.h + cfg-cmd.h + cfg-value.h + cfg-vec.h + config-parser.h + lexeme.h + lexeme-list.h + scm-mem.h + scm-sys.h + io-guts.h + mem-buffer.h + lexeme-parser.h +) + +set(SOURCES_C + call_parser.c +) + +set(SOURCES_F + call_parser.F90 +) + +set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/modules) + +set(SOURCES_CXX ${SOURCES_CXX} ${SOURCES_C}) +set(HEADERS_CXX ${HEADERS_CXX}) + +add_library(parser_CXX STATIC ${HEADERS_CXX} ${SOURCES_CXX}) +add_library(parser_F STATIC ${SOURCES_F}) +set_property(TARGET parser_F PROPERTY LINKER_LANGUAGE Fortran) +target_link_libraries(parser_F parser_CXX) diff --git a/parser/call_parser.F90 b/parser/call_parser.F90 new file mode 100644 index 0000000..a662050 --- /dev/null +++ b/parser/call_parser.F90 @@ -0,0 +1,87 @@ +! module C_FUNC_SUB +! contains + +! INTEGER function get_char_len(name) BIND(C) +! USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_CHAR +! IMPLICIT NONE +! CHARACTER (KIND=C_CHAR), intent(in) :: name(*) +! end function get_char_len + +! end module C_FUNC_SUB + +module PARSER_C_FUNC + + INTERFACE + SUBROUTINE run(filename) BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_CHAR + IMPLICIT NONE + CHARACTER (KIND=C_CHAR), intent(in) :: filename(*) + END SUBROUTINE run + + SUBROUTINE get_int(name, value) BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_CHAR, C_INT + IMPLICIT NONE + CHARACTER (KIND=C_CHAR), intent(in) :: name(*) + INTEGER (KIND=C_INT), intent(out) :: value + END SUBROUTINE get_int + + SUBROUTINE get_float(name, value) BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_CHAR, C_FLOAT + IMPLICIT NONE + CHARACTER (KIND=C_CHAR), intent(in) :: name(*) + REAL (KIND=C_FLOAT), intent(out) :: value + END SUBROUTINE get_float + + SUBROUTINE get_double(name, value) BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_CHAR, C_DOUBLE + IMPLICIT NONE + CHARACTER (KIND=C_CHAR), intent(in) :: name(*) + REAL (KIND=C_DOUBLE), intent(out) :: value + END SUBROUTINE get_double + + ! TODO: + SUBROUTINE get_char_len(name, len) BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_CHAR, C_INT + IMPLICIT NONE + CHARACTER (KIND=C_CHAR), intent(in) :: name(*) + INTEGER (KIND=C_INT), intent(out) :: len + END SUBROUTINE get_char_len + + SUBROUTINE get_charc(name, value) BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_CHAR + IMPLICIT NONE + CHARACTER (KIND=C_CHAR), intent(in) :: name(*) + CHARACTER (KIND=C_CHAR), intent(out) :: value(*) + END SUBROUTINE get_charc + + END INTERFACE +end module PARSER_C_FUNC + +! TODO: + +SUBROUTINE get_char_lenf(name, len) + USE PARSER_C_FUNC + + IMPLICIT NONE + CHARACTER, intent(in) :: name(*) + INTEGER, intent(out) :: len + + call get_char_len(name, len) +END SUBROUTINE get_char_lenf + +SUBROUTINE get_charf(name, char_value) + USE PARSER_C_FUNC + + IMPLICIT NONE + CHARACTER, allocatable, intent(OUT) :: char_value(:) + + CHARACTER, intent(in) :: name(*) + INTEGER :: len + + call get_char_lenf(name, len) + + write(*, *) 'len = ', len + + ! IF(ALLOCATED(char_value)) DEALLOCATE(char_value) + ! allocate(char_value(4)) +END SUBROUTINE get_charf \ No newline at end of file diff --git a/parser/call_parser.c b/parser/call_parser.c new file mode 100644 index 0000000..109668d --- /dev/null +++ b/parser/call_parser.c @@ -0,0 +1,38 @@ +#include "call_parser.h" +#include <stdio.h> +#include "ISO_Fortran_binding.h" + +int run(const char* filename) +{ + return runCXX(filename); +} + +int get_int(const char* name, int* value) +{ + return get_intCXX(name, value); +} + +int get_float(const char* name, float* value) +{ + return get_floatCXX(name, value); +} + +int get_double(const char* name, double* value) +{ + return get_doubleCXX(name, value); +} + +int get_charc(const char* name, char* value) +{ + return get_charCXX(name, value); +} + +void get_char_len(const char* name, int *len) +{ + *len = get_char_lenCXX(name); +} + +// int get_bool(const char* name, bool* value) +// { +// return get_valueCXX(name, value); +// } \ No newline at end of file diff --git a/parser/call_parser.cpp b/parser/call_parser.cpp new file mode 100644 index 0000000..d08a0b9 --- /dev/null +++ b/parser/call_parser.cpp @@ -0,0 +1,78 @@ +#include "call_parser.h" +#include "config-parser.h" +#include <string> + +static scm::ConfigParser Parser; + +#ifdef __cplusplus +extern "C" { +#endif + + int runCXX(const char* filename) + { + bool res = Parser.run(filename); + + if(res == false) return 0; + return 1; + } + + int get_intCXX(const char* name, int* value) + { + bool res = Parser.get_value(name, value); + + if(res == false) return 0; + return 1; + } + + int get_floatCXX(const char* name, float* value) + { + bool res = Parser.get_value(name, value); + + if(res == false) return 0; + return 1; + } + + int get_doubleCXX(const char* name, double* value) + { + bool res = Parser.get_value(name, value); + + if(res == false) return 0; + return 1; + } + + int get_char_lenCXX(const char* name) + { + std::string target_res; + bool res = Parser.get_value(name, target_res); + + return target_res.size(); + } + + int get_charCXX(const char* name, char* value) + { + std::string target_res; + bool res = Parser.get_value(name, target_res); + + printf("target_res = %s, len = %d\n", target_res.c_str(), target_res.size()); + + const int n = target_res.size(); + + for (int i = 0; i < n; i++) + value[i] = target_res[i]; + + if(res == false) return 0; + return 1; + } + + // bool get_valueCXX(const char* name, std::string& value) + // { + // return Parser.get_value(name, value); + // } + + // bool get_valueCXX(const char* name, bool* value) + // { + // return Parser.get_value(name, value); + // } +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/parser/call_parser.h b/parser/call_parser.h new file mode 100644 index 0000000..567fd60 --- /dev/null +++ b/parser/call_parser.h @@ -0,0 +1,20 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + + int runCXX(const char* filename); + int get_intCXX(const char* name, int* value); + int get_floatCXX(const char* name, float* value); + int get_doubleCXX(const char* name, double* value); + // bool get_valueCXX(const char* name, long double* value); + + int get_char_lenCXX(const char* name); + int get_charCXX(const char* name, char* value); + + // bool get_valueCXX(const char* name, bool* value); + +#ifdef __cplusplus +} +#endif diff --git a/parser/cfg-cmd.cpp b/parser/cfg-cmd.cpp new file mode 100644 index 0000000..1ef0eda --- /dev/null +++ b/parser/cfg-cmd.cpp @@ -0,0 +1,157 @@ +#include "cfg-cmd.h" + +#include "scm-mem.h" +#include <string.h> +#include <stdio.h> + +// -------------------------------------------------------------------------------------------- // +// * Implementation * +// -------------------------------------------------------------------------------------------- // + +scm::cfgCommand::cfgCommand() +{ + nalloc = 0; + narg = 0; + + name_memsize = 1; + name = new char[name_memsize]; + *name = '\0'; +} + +scm::cfgCommand::~cfgCommand() +{ + if (nalloc > 0) delete[] arg; + delete[] name; + + narg = 0; + nalloc = 0; +} + +scm::cfgCommand::cfgCommand(const cfgCommand& cmd) +{ + name_memsize = strlen(cmd.name) + 1; + name = new char[name_memsize]; + strcpy(name, cmd.name); + + narg = cmd.narg; + if (narg > 0) { + arg = new cfgVector[narg]; + for (int k = 0; k < narg; k++) + arg[k] = cmd.arg[k]; + } + + nalloc = narg; +} +// -------------------------------------------------------------------------------------------- // + +// * swap & assignment * // +// -------------------------------------------------------------------------------------------- // +const scm::cfgCommand& +scm::cfgCommand::operator=(cfgCommand cmd) +{ + swap(cmd); + return (*this); +} + +void scm::cfgCommand::swap( + cfgCommand& cmd) +{ + scm::swap(narg, cmd.narg); + scm::swap(nalloc, cmd.nalloc); + scm::swap(arg, cmd.arg); + + scm::swap(name, cmd.name); + scm::swap(name_memsize, cmd.name_memsize); +} +// -------------------------------------------------------------------------------------------- // + +// * add argument * // +// -------------------------------------------------------------------------------------------- // +bool scm::cfgCommand::add_arg(const cfgVector& _arg) +{ + if (!_arg.is_defined()) return false; + + if (narg == nalloc) { + + cfgVector *arg_list; + arg_list = new cfgVector[nalloc + c_nalloc_inc]; + + for (int k = 0; k < narg; k++) + arg_list[k] = arg[k]; + + if (nalloc > 0) delete[] arg; + arg = arg_list; + + nalloc += c_nalloc_inc; + } + + arg[narg] = _arg; + narg++; + + return true; +} +// -------------------------------------------------------------------------------------------- // + +// * change command name * // +// -------------------------------------------------------------------------------------------- // +void scm::cfgCommand::set_name(const char* ex_name) +{ + if (ex_name == NULL) return; + + const size_t ex_length = strlen(ex_name) + 1; + if (ex_length > name_memsize) { + delete[] name; + + name_memsize = ex_length; + name = new char[name_memsize]; + } + + strcpy(name, ex_name); +} +// -------------------------------------------------------------------------------------------- // + +// * reset command * // +// -------------------------------------------------------------------------------------------- // +void scm::cfgCommand::reset() +{ + narg = 0; + *name = '\0'; +} +// -------------------------------------------------------------------------------------------- // + +// * get & check calls * // +// -------------------------------------------------------------------------------------------- // +int scm::cfgCommand::get_narg() const +{ + return narg; +} + +scm::cfgVector scm::cfgCommand::get_arg(const int idx) const +{ + if ((idx < 0) || (idx >= narg)) return cfgVector(); + return arg[idx]; +} + +bool scm::cfgCommand::is_name_eq(const char* ex_name) const +{ + if (ex_name == NULL) return false; + return (!strcmp(ex_name, name)); +} + +const char* scm::cfgCommand::get_name() const +{ + return name; +} +// -------------------------------------------------------------------------------------------- // + +// * print * // +// -------------------------------------------------------------------------------------------- // +void scm::cfgCommand::print() const +{ + printf(" > COMMAND '%s', narg = %i\n", name, narg); + for (int k = 0; k < narg; k++) { + printf(" %i", k); + arg[k].print(); + } +} +// -------------------------------------------------------------------------------------------- // diff --git a/parser/cfg-cmd.h b/parser/cfg-cmd.h new file mode 100644 index 0000000..77fdad0 --- /dev/null +++ b/parser/cfg-cmd.h @@ -0,0 +1,70 @@ +#pragma once + +// [cfg-cmd.h]: configurable variable class 'cfgCommand' +// +// -------------------------------------------------------------------------------------------- // + +#include "cfg-vec.h" + +namespace scm +{ + class cfgCommand { + public: + + // add argument + // -------------------------------------------------------------------------------------------- // + bool add_arg(const cfgVector& _arg); + // -------------------------------------------------------------------------------------------- // + + // change command name + // -------------------------------------------------------------------------------------------- // + void set_name(const char* _name); + // -------------------------------------------------------------------------------------------- // + + // reset command, narg == 0 + // -------------------------------------------------------------------------------------------- // + void reset(); + // -------------------------------------------------------------------------------------------- // + + // get & check calls + // -------------------------------------------------------------------------------------------- // + int get_narg() const; + cfgVector get_arg(const int idx) const; + + bool is_name_eq(const char* ex_name) const; + + const char* get_name() const; + // -------------------------------------------------------------------------------------------- // + + // print + // -------------------------------------------------------------------------------------------- // + void print() const; + // -------------------------------------------------------------------------------------------- // + + // swap & assignment + // -------------------------------------------------------------------------------------------- // + const cfgCommand& operator=(cfgCommand cmd); + void swap(cfgCommand& cmd); + // -------------------------------------------------------------------------------------------- // + + // -------------------------------------------------------------------------------------------- // + cfgCommand(); + cfgCommand(const cfgCommand& cmd); + ~cfgCommand(); + // -------------------------------------------------------------------------------------------- // + + private: + // data (private): + // -------------------------------------------------------------------------------------------- // + + cfgVector *arg; + int narg; + + int nalloc; + static const int c_nalloc_inc = 2; + + char* name; + size_t name_memsize; + }; +} +// -------------------------------------------------------------------------------------------- // diff --git a/parser/cfg-value.cpp b/parser/cfg-value.cpp new file mode 100644 index 0000000..89b6231 --- /dev/null +++ b/parser/cfg-value.cpp @@ -0,0 +1,1092 @@ +#include "cfg-value.h" + +#define _CRT_SECURE_NO_DEPRECATE +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> +#include <limits.h> + +#include <errno.h> + +#include "scm-mem.h" +#include "io-guts.h" + +// -------------------------------------------------------------------------------------------- // +// * Implementation * +// -------------------------------------------------------------------------------------------- // + + +// CPP +namespace scm { + + // = x^p + int ipow(const int x, const int p) + { + if (p == 0) return 1; + if (p == 1) return x; + + int tmp = ipow(x, p / 2); + if (p % 2 == 0) return tmp*tmp; + else + return x*tmp*tmp; + } +} + +// -------------------------------------------------------------------------------------------- // +bool scm::is_integer(const char* token, int* value) +{ + const int mode = 10; + char* pend; + + if (strlen(token) == 0) return false; + + errno = 0; + long lvalue = strtol(token, &pend, mode); + if ((errno == ERANGE && (lvalue == LONG_MAX || lvalue == LONG_MIN)) || + (errno != 0 && lvalue == 0)) { + return false; + } + // checking integer bounds // + if ((lvalue >= INT_MAX) || (lvalue <= INT_MIN)) return false; + if (*pend != '\0') return false; + + *value = (int)lvalue; + return true; +} + +bool scm::is_integer(const char* token) +{ + int value; + return is_integer(token, &value); +} + +bool scm::is_double(const char* token, double* value) +{ + char* pend; + + if (strlen(token) == 0) return false; + + errno = 0; + *value = strtod(token, &pend); + if ((errno == ERANGE && (*value == HUGE_VAL || *value == -HUGE_VAL)) || + (errno != 0 && *value == (double)0)) { + return false; + } + + if (*pend != '\0') return false; + return true; +} + +bool scm::is_double(const char* token) +{ + double value; + return is_double(token, &value); +} + +bool scm::is_valid_c_name(const char* token) +{ + int token_length = (int)strlen(token); + + if (token_length == 0) return false; + if ((!isalpha(token[0])) && (token[0] != '_')) return false; + + for (int i = 1; i < token_length; i++) { + if ((!isalnum(token[i])) && (token[i] != '_')) return false; + } + + return true; +} + +bool scm::is_valid_string(const char* token) +{ + int token_length = (int)strlen(token); + + if (token_length <= 1) return false; + if ((token[0] != '"') || (token[token_length - 1] != '"')) return false; + + return true; +} + +bool scm::is_boolean(const char* token, bool* value) +{ + if (!strcmp(token, "true")) { + *value = true; + return true; + } + if (!strcmp(token, "false")) { + *value = false; + return true; + } + + return false; +} + +bool scm::is_boolean(const char* token) +{ + bool value; + return is_boolean(token, &value); +} + + +void scm::strcpyrm(char* a, const char* b, const char sym) +{ + int i = 0; + for (int k = 0; k < (int)strlen(b); k++) { + if (b[k] == sym) continue; + a[i] = b[k]; + i++; + } + a[i] = '\0'; +} +// -------------------------------------------------------------------------------------------- // + + +// -------------------------------------------------------------------------------------------- // +// * Implementation * +// * scm::cfgValue * +// -------------------------------------------------------------------------------------------- // + +// -------------------------------------------------------------------------------------------- // +scm::cfgValue::cfgValue() : + type(IS_UNDEF), + eint(0), edouble((double)0), estring(NULL), ebool(false) +{ +} + +scm::cfgValue::cfgValue(const int x) : + type(IS_INT), + eint(x), edouble((double)0), estring(NULL), ebool(false) +{ +} + +scm::cfgValue::cfgValue(const float x) : + type(IS_DOUBLE), + eint(0), edouble((double)x), estring(NULL), ebool(false) +{ +} + +scm::cfgValue::cfgValue(const double x) : + type(IS_DOUBLE), + eint(0), edouble(x), estring(NULL), ebool(false) +{ +} + +scm::cfgValue::cfgValue(const long double x) : + type(IS_DOUBLE), + eint(0), edouble((double)x), estring(NULL), ebool(false) +{ +} + +scm::cfgValue::cfgValue(const char* c_str) : + type(IS_STRING), + eint(0), edouble((double)0), estring(NULL), ebool(false) +{ + estring = new char[strlen(c_str) + 1]; + strcpy(estring, c_str); +} + +scm::cfgValue::cfgValue(const bool x) : + type(IS_BOOLEAN), + eint(0), edouble((double)0), estring(NULL), ebool(x) +{ +} + +scm::cfgValue::~cfgValue() +{ + clear(); +} + +scm::cfgValue::cfgValue(const cfgValue& x) +{ + type = x.type; + + if (type == IS_INT) eint = x.eint; + else if (type == IS_DOUBLE) edouble = x.edouble; + else if (type == IS_BOOLEAN) ebool = x.ebool; + else if (type == IS_STRING) + { + estring = new char[strlen(x.estring) + 1]; + strcpy(estring, x.estring); + } +} +// -------------------------------------------------------------------------------------------- // + +// * swap & assignment * // +// -------------------------------------------------------------------------------------------- // +const scm::cfgValue& +scm::cfgValue::operator=(cfgValue x) +{ + swap(x); + return (*this); +} + +void scm::cfgValue::swap( + cfgValue& x) +{ + scm::swap(type, x.type); + scm::swap(eint, x.eint); + scm::swap(edouble, x.edouble); + scm::swap(estring, x.estring); + scm::swap(ebool, x.ebool); +} +// -------------------------------------------------------------------------------------------- // + +// * make implicit value * // +// -------------------------------------------------------------------------------------------- // +scm::cfgValue scm::cfgValue::make_implicit(const char* value_in_string) +{ + cfgValue x; + + if (is_integer(value_in_string, &x.eint)) + x.type = IS_INT; + else if (is_double(value_in_string, &x.edouble)) + x.type = IS_DOUBLE; + else if (is_boolean(value_in_string, &x.ebool)) + x.type = IS_BOOLEAN; + else if (is_valid_string(value_in_string)) + { + x.type = IS_STRING; + x.estring = new char[strlen(value_in_string) + 1]; + strcpyrm(x.estring, value_in_string, '"'); + } + + return x; +} +// -------------------------------------------------------------------------------------------- // + +// * clear * // +// -------------------------------------------------------------------------------------------- // +void scm::cfgValue::clear() +{ + if (type == IS_STRING) { + delete[] estring; + estring = NULL; + } + + type = IS_UNDEF; +} +// -------------------------------------------------------------------------------------------- // + +// * get and check calls * // +// -------------------------------------------------------------------------------------------- // +bool scm::cfgValue::get(int* x) const +{ + if (type == IS_INT) { + (*x) = eint; + return true; + } + + return false; +} + +bool scm::cfgValue::get(float* x) const +{ + if (type == IS_DOUBLE) { + (*x) = (float)edouble; + return true; + } + if (type == IS_INT) { + (*x) = (float)eint; + return true; + } + + return false; +} + +bool scm::cfgValue::get(double* x) const +{ + if (type == IS_DOUBLE) { + (*x) = edouble; + return true; + } + if (type == IS_INT) { + (*x) = (double)eint; + return true; + } + + return false; +} + +bool scm::cfgValue::get(long double* x) const +{ + if (type == IS_DOUBLE) { + (*x) = (long double)edouble; + return true; + } + if (type == IS_INT) { + (*x) = (long double)eint; + return true; + } + + return false; +} + +bool scm::cfgValue::get(char** c_str) const +{ + if (type == IS_STRING) { + (*c_str) = new char[strlen(estring) + 1]; + strcpy(*c_str, estring); + return true; + } + + return false; +} + +bool scm::cfgValue::get(std::string& x) const +{ + if (type == IS_STRING) { + x = std::string(estring); + return true; + } + + return false; +} + +bool scm::cfgValue::get(bool* x) const +{ + if (type == IS_BOOLEAN) { + (*x) = ebool; + return true; + } + + return false; +} + +scm::cfgValue::VAR_TYPE scm::cfgValue::get_type() const +{ + return type; +} + +bool scm::cfgValue::is_defined() const +{ + return (type != IS_UNDEF); +} +// -------------------------------------------------------------------------------------------- // + +// * print * // +// -------------------------------------------------------------------------------------------- // +void scm::cfgValue::print() const +{ + print(stdout); +} + +void scm::cfgValue::print(FILE *ptr) const +{ + if (type == IS_INT) + fprintf(ptr, "%i", eint); + else if (type == IS_DOUBLE) + fprintf(ptr, "%f", edouble); + else if (type == IS_BOOLEAN) + fprintf(ptr, "%s", ebool ? "true" : "false"); + else if (type == IS_STRING) + fprintf(ptr, "%s", estring); + else + fprintf(ptr, "(UNDEFINED)"); +} + +void scm::cfgValue::print_typed() const +{ + if (type == IS_INT) + printf("(INT) %i", eint); + else if (type == IS_DOUBLE) + printf("(DOUBLE) %f", edouble); + else if (type == IS_BOOLEAN) + printf("(BOOLEAN) %s", ebool ? "true" : "false"); + else if (type == IS_STRING) + printf("(STRING) %s", estring); + else + printf("(UNDEFINED)"); +} +// -------------------------------------------------------------------------------------------- // + +// * operators * // +// -------------------------------------------------------------------------------------------- // +scm::cfgValue& scm::cfgValue::operator+=(const cfgValue& x) +{ + // (int) += (int) + // (int) += (double) + conversion to (double) + // (double) += (double) + // (double) += (int) + // (string) += (string) + if ((type == IS_INT) && (x.type == IS_INT)) + eint += x.eint; + else if ((type == IS_INT) && (x.type == IS_DOUBLE)) + { + edouble = (double)eint + x.edouble; + type = IS_DOUBLE; + } + else if ((type == IS_DOUBLE) && (x.type == IS_DOUBLE)) + edouble += x.edouble; + else if ((type == IS_DOUBLE) && (x.type == IS_INT)) + edouble += (double)x.eint; + else if ((type == IS_STRING) && (x.type == IS_STRING)) + { + const size_t length = strlen(estring) + strlen(x.estring) + 1; + char *buf = new char[length]; + + strcpy(buf, estring); + strcat(buf, x.estring); + + delete[] estring; + estring = buf; + } + else + { + clear(); // type:= IS_UNDEF + } + + return (*this); +} + +scm::cfgValue& scm::cfgValue::operator-=(const cfgValue& x) +{ + // (int) -= (int) + // (int) -= (double) + conversion to (double) + // (double) -= (double) + // (double) -= (int) + if ((type == IS_INT) && (x.type == IS_INT)) + eint -= x.eint; + else if ((type == IS_INT) && (x.type == IS_DOUBLE)) + { + edouble = (double)eint - x.edouble; + type = IS_DOUBLE; + } + else if ((type == IS_DOUBLE) && (x.type == IS_DOUBLE)) + edouble -= x.edouble; + else if ((type == IS_DOUBLE) && (x.type == IS_INT)) + edouble -= (double)x.eint; + else + { + clear(); // type:= IS_UNDEF + } + + return (*this); +} + +scm::cfgValue& scm::cfgValue::operator*=(const cfgValue& x) +{ + // (int) *= (int) + // (int) *= (double) + conversion to (double) + // (double) *= (double) + // (double) *= (int) + if ((type == IS_INT) && (x.type == IS_INT)) + eint *= x.eint; + else if ((type == IS_INT) && (x.type == IS_DOUBLE)) + { + edouble = (double)eint * x.edouble; + type = IS_DOUBLE; + } + else if ((type == IS_DOUBLE) && (x.type == IS_DOUBLE)) + edouble *= x.edouble; + else if ((type == IS_DOUBLE) && (x.type == IS_INT)) + edouble *= (double)x.eint; + else + { + clear(); // type:= IS_UNDEF + } + + return (*this); +} + +scm::cfgValue& scm::cfgValue::operator/=(const cfgValue& x) +{ + // (int) /= (int) + // (int) /= (double) + conversion to (double) + // (double) /= (double) + // (double) /= (int) + if ((type == IS_INT) && (x.type == IS_INT)) + eint /= x.eint; + else if ((type == IS_INT) && (x.type == IS_DOUBLE)) + { + edouble = (double)eint / x.edouble; + type = IS_DOUBLE; + } + else if ((type == IS_DOUBLE) && (x.type == IS_DOUBLE)) + edouble /= x.edouble; + else if ((type == IS_DOUBLE) && (x.type == IS_INT)) + edouble /= (double)x.eint; + else + { + clear(); // type:= IS_UNDEF + } + + return (*this); +} + +scm::cfgValue& scm::cfgValue::operator%=(const cfgValue& x) +{ + // int %= (int) + if ((type == IS_INT) && (x.type == IS_INT)) + eint %= x.eint; + else + { + clear(); // type:= IS_UNDEF + } + + return (*this); +} + +scm::cfgValue& scm::cfgValue::operator^=(const cfgValue& x) +{ + // (int) ^= (int) + // (int) ^= (double) + conversion to (double) + // (double) ^= (double) + // (double) ^= (int) + if ((type == IS_INT) && (x.type == IS_INT)) + eint = ipow(eint, x.eint); + else if ((type == IS_INT) && (x.type == IS_DOUBLE)) + { + edouble = pow((double)eint, x.edouble); + type = IS_DOUBLE; + } + else if ((type == IS_DOUBLE) && (x.type == IS_DOUBLE)) + edouble = pow(edouble, x.edouble); + else if ((type == IS_DOUBLE) && (x.type == IS_INT)) + edouble = pow(edouble, x.eint); + else + { + clear(); // type:= IS_UNDEF + } + + return (*this); +} + +// *: check if we should really use const on return (all operators) -> +const scm::cfgValue +scm::cfgValue::operator+(const cfgValue& x) const +{ + return cfgValue(*this) += x; +} + +const scm::cfgValue +scm::cfgValue::operator-(const cfgValue& x) const +{ + return cfgValue(*this) -= x; +} + +const scm::cfgValue +scm::cfgValue::operator*(const cfgValue& x) const +{ + return cfgValue(*this) *= x; +} + +const scm::cfgValue +scm::cfgValue::operator/(const cfgValue& x) const +{ + return cfgValue(*this) /= x; +} + +const scm::cfgValue +scm::cfgValue::operator%(const cfgValue& x) const +{ + return cfgValue(*this) %= x; +} + +const scm::cfgValue +scm::cfgValue::operator^(const cfgValue& x) const +{ + return cfgValue(*this) ^= x; +} + +const scm::cfgValue +scm::cfgValue::operator==(const cfgValue& x) const +{ + cfgValue res; + + if (type == IS_INT) + { + if (x.type == IS_INT) + { + res.type = IS_BOOLEAN; + res.ebool = (eint == x.eint); + } + else if (x.type == IS_DOUBLE) + { + res.type = IS_BOOLEAN; + res.ebool = (eint == x.edouble); + } + else if (x.type == IS_BOOLEAN) + { + res.type = IS_BOOLEAN; + res.ebool = (eint == (int)x.ebool); + } + } + else if (type == IS_DOUBLE) + { + if (x.type == IS_INT) + { + res.type = IS_BOOLEAN; + res.ebool = (edouble == x.eint); + } + else if (x.type == IS_DOUBLE) + { + res.type = IS_BOOLEAN; + res.ebool = (edouble == x.edouble); + } + else if (x.type == IS_BOOLEAN) + { + res.type = IS_BOOLEAN; + res.ebool = (edouble == (int)x.ebool); + } + } + else if (type == IS_BOOLEAN) + { + if (x.type == IS_INT) + { + res.type = IS_BOOLEAN; + res.ebool = ((int)ebool == x.eint); + } + else if (x.type == IS_DOUBLE) + { + res.type = IS_BOOLEAN; + res.ebool = ((int)ebool == x.edouble); + } + else if (x.type == IS_BOOLEAN) + { + res.type = IS_BOOLEAN; + res.ebool = (ebool == x.ebool); + } + } + else if (type == IS_STRING) + { + if (x.type == IS_STRING) + { + res.type = IS_BOOLEAN; + res.ebool = (!strcmp(estring, x.estring)); + } + } + + return res; +} + +const scm::cfgValue +scm::cfgValue::operator!=(const cfgValue& x) const +{ + cfgValue res = ((*this) == x); + if (res.type == IS_BOOLEAN) res.ebool = (!res.ebool); + + return res; +} + +const scm::cfgValue +scm::cfgValue::operator<(const cfgValue& x) const +{ + cfgValue res; + + if (type == IS_INT) + { + if (x.type == IS_INT) + { + res.type = IS_BOOLEAN; + res.ebool = (eint < x.eint); + } + else if (x.type == IS_DOUBLE) + { + res.type = IS_BOOLEAN; + res.ebool = (eint < x.edouble); + } + else if (x.type == IS_BOOLEAN) + { + res.type = IS_BOOLEAN; + res.ebool = (eint < (int)x.ebool); + } + } + else if (type == IS_DOUBLE) + { + if (x.type == IS_INT) + { + res.type = IS_BOOLEAN; + res.ebool = (edouble < x.eint); + } + else if (x.type == IS_DOUBLE) + { + res.type = IS_BOOLEAN; + res.ebool = (edouble < x.edouble); + } + else if (x.type == IS_BOOLEAN) + { + res.type = IS_BOOLEAN; + res.ebool = (edouble < (int)x.ebool); + } + } + else if (type == IS_BOOLEAN) + { + if (x.type == IS_INT) + { + res.type = IS_BOOLEAN; + res.ebool = ((int)ebool < x.eint); + } + else if (x.type == IS_DOUBLE) + { + res.type = IS_BOOLEAN; + res.ebool = ((int)ebool < x.edouble); + } + else if (x.type == IS_BOOLEAN) + { + res.type = IS_BOOLEAN; + res.ebool = (ebool < x.ebool); + } + } + + return res; +} + +const scm::cfgValue +scm::cfgValue::operator>(const cfgValue& x) const +{ + cfgValue res; + + if (type == IS_INT) + { + if (x.type == IS_INT) + { + res.type = IS_BOOLEAN; + res.ebool = (eint > x.eint); + } + else if (x.type == IS_DOUBLE) + { + res.type = IS_BOOLEAN; + res.ebool = (eint > x.edouble); + } + else if (x.type == IS_BOOLEAN) + { + res.type = IS_BOOLEAN; + res.ebool = (eint > (int)x.ebool); + } + } + else if (type == IS_DOUBLE) + { + if (x.type == IS_INT) + { + res.type = IS_BOOLEAN; + res.ebool = (edouble > x.eint); + } + else if (x.type == IS_DOUBLE) + { + res.type = IS_BOOLEAN; + res.ebool = (edouble > x.edouble); + } + else if (x.type == IS_BOOLEAN) + { + res.type = IS_BOOLEAN; + res.ebool = (edouble > (int)x.ebool); + } + } + else if (type == IS_BOOLEAN) + { + if (x.type == IS_INT) + { + res.type = IS_BOOLEAN; + res.ebool = ((int)ebool > x.eint); + } + else if (x.type == IS_DOUBLE) + { + res.type = IS_BOOLEAN; + res.ebool = ((int)ebool > x.edouble); + } + else if (x.type == IS_BOOLEAN) + { + res.type = IS_BOOLEAN; + res.ebool = (ebool > x.ebool); + } + } + + return res; +} + +const scm::cfgValue +scm::cfgValue::operator<=(const cfgValue& x) const +{ + cfgValue res = ((*this) > x); + if (res.type == IS_BOOLEAN) res.ebool = (!res.ebool); + + return res; +} + +const scm::cfgValue +scm::cfgValue::operator>=(const cfgValue& x) const +{ + cfgValue res = ((*this) < x); + if (res.type == IS_BOOLEAN) res.ebool = (!res.ebool); + + return res; +} + +const scm::cfgValue +scm::cfgValue::operator-() const +{ + // -(int) + // -(double) + cfgValue x; // default: type:= IS_UNDEF + + if (type == IS_INT) { + x = (*this); + x.eint = -x.eint; + } + else if (type == IS_DOUBLE) { + x = (*this); + x.edouble = -x.edouble; + } + + return x; +} + +const scm::cfgValue +scm::cfgValue::operator+() const +{ + // +(int) + // +(double) + cfgValue x; // default: type:= IS_UNDEF + + if (type == IS_INT) x = (*this); + else if (type == IS_DOUBLE) x = (*this); + + return x; +} + +const scm::cfgValue +scm::cfgValue::logical_and(const cfgValue& x) const +{ + cfgValue res; + + if ((type == IS_BOOLEAN) && (x.type == IS_BOOLEAN)) + { + res.type = IS_BOOLEAN; + res.ebool = (ebool && x.ebool); + } + + return res; +} + +const scm::cfgValue +scm::cfgValue::logical_or(const cfgValue& x) const +{ + cfgValue res; + + if ((type == IS_BOOLEAN) && (x.type == IS_BOOLEAN)) + { + res.type = IS_BOOLEAN; + res.ebool = (ebool || x.ebool); + } + + return res; +} + +// <- +// +// -------------------------------------------------------------------------------------------- // + +// * functions * // +// -------------------------------------------------------------------------------------------- // +const scm::cfgValue +scm::cfgValue::cfg_sin(const cfgValue& x) +{ + // sin(int) + // sin(double) + cfgValue y; // default: type:=IS_UNDEF + + if (x.type == IS_DOUBLE) { + y.edouble = sin(x.edouble); + y.type = IS_DOUBLE; + } + else if (x.type == IS_INT) { + y.edouble = sin((double)x.eint); + y.type = IS_DOUBLE; + } + + return y; +} + +const scm::cfgValue +scm::cfgValue::cfg_cos(const cfgValue& x) +{ + // cos(int) + // cos(double) + cfgValue y; // default: type:=IS_UNDEF + + if (x.type == IS_DOUBLE) { + y.edouble = cos(x.edouble); + y.type = IS_DOUBLE; + } + else if (x.type == IS_INT) { + y.edouble = cos((double)x.eint); + y.type = IS_DOUBLE; + } + + return y; +} + +const scm::cfgValue +scm::cfgValue::cfg_tan(const cfgValue& x) +{ + // tan(int) + // tan(double) + cfgValue y; // default: type:=IS_UNDEF + + if (x.type == IS_DOUBLE) { + y.edouble = tan(x.edouble); + y.type = IS_DOUBLE; + } + else if (x.type == IS_INT) { + y.edouble = tan((double)x.eint); + y.type = IS_DOUBLE; + } + + return y; +} + +const scm::cfgValue +scm::cfgValue::cfg_log(const cfgValue& x) +{ + // log(int) + // log(double) + cfgValue y; // default: type:=IS_UNDEF + + if (x.type == IS_DOUBLE) { + y.edouble = log(x.edouble); + y.type = IS_DOUBLE; + } + else if (x.type == IS_INT) { + y.edouble = log((double)x.eint); + y.type = IS_DOUBLE; + } + + return y; +} + +const scm::cfgValue +scm::cfgValue::cfg_sqrt(const cfgValue& x) +{ + // sqrt(int) + // sqrt(double) + cfgValue y; // default: type:=IS_UNDEF + + if (x.type == IS_DOUBLE) { + y.edouble = sqrt(x.edouble); + y.type = IS_DOUBLE; + } + else if (x.type == IS_INT) { + y.edouble = sqrt((double)x.eint); + y.type = IS_DOUBLE; + } + + return y; +} + +const scm::cfgValue +scm::cfgValue::cfg_abs(const cfgValue& x) +{ + // sqrt(int) + // sqrt(double) + + cfgValue y; // default: type:=IS_UNDEF + + if (x.type == IS_DOUBLE) { + y.edouble = (x.edouble < (double)0) ? + -x.edouble : x.edouble; + y.type = IS_DOUBLE; + } + else if (x.type == IS_INT) { + y.eint = (x.eint < 0) ? + -x.eint : x.eint; + y.type = IS_INT; + } + + return y; +} + +const scm::cfgValue +scm::cfgValue::cfg_to_string(const cfgValue& x) +{ + // string(int) + // string(double) + // string(string) + // string(boolean) + cfgValue y; // default: type:=IS_UNDEF + + if (x.type == IS_INT) + { + y.type = IS_STRING; + std::string val_string = convert_to_string(x.eint); + y.estring = new char[strlen(val_string.c_str()) + 1]; + strcpy(y.estring, val_string.c_str()); + } + else if (x.type == IS_DOUBLE) + { + y.type = IS_STRING; + std::string val_string = convert_to_string(x.edouble); + y.estring = new char[strlen(val_string.c_str()) + 1]; + strcpy(y.estring, val_string.c_str()); + } + else if (x.type == IS_BOOLEAN) + { + y.type = IS_STRING; + std::string val_string; + val_string = (x.ebool) ? "true" : "false"; + y.estring = new char[strlen(val_string.c_str()) + 1]; + strcpy(y.estring, val_string.c_str()); + } + else if (x.type == IS_STRING) y = x; + + return y; +} + +const scm::cfgValue +scm::cfgValue::cfg_min(const cfgValue& a, const cfgValue& b) +{ + // min(int, int) + // min(double, double) + // min(int, double) + // min(double, int) + cfgValue _min; // default: type:=IS_UNDEF + + if ((a.type == IS_DOUBLE) && (b.type == IS_DOUBLE)) + _min = (a.edouble < b.edouble) ? a : b; + else if ((a.type == IS_DOUBLE) && (b.type == IS_INT)) + { + _min.edouble = (a.edouble < (double)b.eint) ? + a.edouble : (double)b.eint; + _min.type = IS_DOUBLE; + } + else if ((a.type == IS_INT) && (b.type == IS_DOUBLE)) + { + _min.edouble = ((double)a.eint < b.edouble) ? + (double)a.eint : b.edouble; + _min.type = IS_DOUBLE; + } + else if ((a.type == IS_INT) && (b.type == IS_INT)) + _min = (a.eint < b.eint) ? a : b; + + return _min; +} + +const scm::cfgValue +scm::cfgValue::cfg_max(const cfgValue& a, const cfgValue& b) +{ + // max(int, int) + // max(double, double) + // max(int, double) + // max(double, int) + cfgValue _max; // default: type:=IS_UNDEF + + if ((a.type == IS_DOUBLE) && (b.type == IS_DOUBLE)) + _max = (a.edouble > b.edouble) ? a : b; + else if ((a.type == IS_DOUBLE) && (b.type == IS_INT)) + { + _max.edouble = (a.edouble > (double)b.eint) ? + a.edouble : (double)b.eint; + _max.type = IS_DOUBLE; + } + else if ((a.type == IS_INT) && (b.type == IS_DOUBLE)) + { + _max.edouble = ((double)a.eint > b.edouble) ? + (double)a.eint : b.edouble; + _max.type = IS_DOUBLE; + } + else if ((a.type == IS_INT) && (b.type == IS_INT)) + _max = (a.eint > b.eint) ? a : b; + + return _max; +} +// -------------------------------------------------------------------------------------------- // diff --git a/parser/cfg-value.h b/parser/cfg-value.h new file mode 100644 index 0000000..9479a5b --- /dev/null +++ b/parser/cfg-value.h @@ -0,0 +1,140 @@ +#pragma once + +// [cfg-var.h]: +// -------------------------------------------------------------------------------------------- // +// configurable variable class 'cfgValue' +// -------------------------------------------------------------------------------------------- // + +#define _CRT_SECURE_NO_WARNINGS +#include <string> + + +namespace scm +{ + bool is_integer(const char* token, int* value); + bool is_integer(const char* token); + + bool is_double(const char* token, double* value); + bool is_double(const char* token); + + bool is_valid_c_name(const char* token); + bool is_valid_string(const char* string); + + bool is_boolean(const char* token, bool* value); + bool is_boolean(const char* token); + + // --- copy a = b and remove [sym] + void strcpyrm(char* a, const char* b, const char sym); + // -------------------------------------------------------------------------------------------- // + + class cfgValue { + public: + + enum VAR_TYPE { IS_UNDEF, IS_INT, IS_DOUBLE, IS_STRING, IS_BOOLEAN }; + + // -------------------------------------------------------------------------------------------- // + cfgValue(); + cfgValue(const int x); + cfgValue(const float x); + cfgValue(const double x); + cfgValue(const long double x); + cfgValue(const char* c_str); + cfgValue(const bool x); + ~cfgValue(); + // -------------------------------------------------------------------------------------------- // + + // -------------------------------------------------------------------------------------------- // + cfgValue(const cfgValue& x); + const cfgValue& operator=(cfgValue x); + void swap(cfgValue& x); + // -------------------------------------------------------------------------------------------- // + + // --- assuming that string should be in double quotation marks "" + static cfgValue make_implicit(const char* x_in_string); + // -------------------------------------------------------------------------------------------- // + + // clear --> type = IS_UNDEF + // -------------------------------------------------------------------------------------------- // + void clear(); + // -------------------------------------------------------------------------------------------- // + + // get & check calls + // -------------------------------------------------------------------------------------------- // + bool get(int* x) const; + bool get(float* x) const; + bool get(double* x) const; + bool get(long double* x) const; + bool get(char** c_str) const; + bool get(std::string& x) const; + bool get(bool* x) const; + + VAR_TYPE get_type() const; + + // : type != IS_UNDEF + bool is_defined() const; + // -------------------------------------------------------------------------------------------- // + + // print + // -------------------------------------------------------------------------------------------- // + void print(FILE *ptr) const; + void print() const; + void print_typed() const; + // -------------------------------------------------------------------------------------------- // + + // operators + // -------------------------------------------------------------------------------------------- // + cfgValue& operator+=(const cfgValue& x); + cfgValue& operator-=(const cfgValue& x); + cfgValue& operator*=(const cfgValue& x); + cfgValue& operator/=(const cfgValue& x); + cfgValue& operator%=(const cfgValue& x); + cfgValue& operator^=(const cfgValue& x); + + const cfgValue operator+(const cfgValue& x) const; + const cfgValue operator-(const cfgValue& x) const; + const cfgValue operator*(const cfgValue& x) const; + const cfgValue operator/(const cfgValue& x) const; + const cfgValue operator%(const cfgValue& x) const; + const cfgValue operator^(const cfgValue& x) const; + + const cfgValue operator==(const cfgValue& x) const; + const cfgValue operator!=(const cfgValue& x) const; + const cfgValue operator<(const cfgValue& x) const; + const cfgValue operator>(const cfgValue& x) const; + const cfgValue operator<=(const cfgValue& x) const; + const cfgValue operator>=(const cfgValue& x) const; + + const cfgValue operator-() const; + const cfgValue operator+() const; + + const cfgValue logical_and(const cfgValue& x) const; // no short-circuit + const cfgValue logical_or(const cfgValue& y) const; // no short-circuit + // -------------------------------------------------------------------------------------------- // + + // functions + // -------------------------------------------------------------------------------------------- // + static const cfgValue cfg_sin(const cfgValue& x); + static const cfgValue cfg_cos(const cfgValue& x); + static const cfgValue cfg_tan(const cfgValue& x); + static const cfgValue cfg_log(const cfgValue& x); + static const cfgValue cfg_sqrt(const cfgValue& x); + static const cfgValue cfg_abs(const cfgValue& x); + static const cfgValue cfg_to_string(const cfgValue& x); + + static const cfgValue cfg_min(const cfgValue& a, const cfgValue& b); + static const cfgValue cfg_max(const cfgValue& a, const cfgValue& b); + // -------------------------------------------------------------------------------------------- // + + private: + // data (private): + // -------------------------------------------------------------------------------------------- // + + VAR_TYPE type; + + int eint; + double edouble; + char *estring; + bool ebool; + }; +} +// -------------------------------------------------------------------------------------------- // diff --git a/parser/cfg-vec.cpp b/parser/cfg-vec.cpp new file mode 100644 index 0000000..0c546d6 --- /dev/null +++ b/parser/cfg-vec.cpp @@ -0,0 +1,816 @@ +#include "cfg-vec.h" + +#include "scm-mem.h" +#include <string.h> +#include <stdio.h> + +// -------------------------------------------------------------------------------------------- // +// * Implementation * +// -------------------------------------------------------------------------------------------- // + + +scm::cfgVector::cfgVector() : + size(0), nalloc(0) +{ + name_memsize = 1; + name = new char[name_memsize]; + *name = '\0'; +} + +scm::cfgVector::cfgVector(const cfgValue& _value) : + size(1), nalloc(1) +{ + value = new cfgValue[nalloc]; + *value = _value; + + name_memsize = 1; + name = new char[name_memsize]; + *name = '\0'; +} + +scm::cfgVector::~cfgVector() +{ + if (nalloc > 0) delete[] value; + delete[] name; +} + +scm::cfgVector::cfgVector(const cfgVector& x) : + size(x.size), nalloc(size) +{ + if (nalloc > 0) { + value = new cfgValue[nalloc]; + for (int k = 0; k < size; k++) + value[k] = x.value[k]; + } + + name_memsize = strlen(x.name) + 1; + name = new char[name_memsize]; + strcpy(name, x.name); +} +// -------------------------------------------------------------------------------------------- // + +// * swap & assignment * // +// -------------------------------------------------------------------------------------------- // +const scm::cfgVector& scm::cfgVector::operator=(cfgVector x) +{ + swap(x); + return (*this); +} + +void scm::cfgVector::swap(cfgVector& x) +{ + scm::swap(size, x.size); + scm::swap(nalloc, x.nalloc); + scm::swap(value, x.value); + + scm::swap(name_memsize, x.name_memsize); + scm::swap(name, x.name); +} +// -------------------------------------------------------------------------------------------- // + +// * set & add calls * // +// -------------------------------------------------------------------------------------------- // +void scm::cfgVector::set(const cfgValue& _value) +{ + if (nalloc == 0) + { + nalloc = 1; + value = new cfgValue[nalloc]; + } + + size = 1; + *value = _value; +} + +void scm::cfgVector::set(const cfgValue& _value, const int _size) +{ + if (nalloc < _size) + { + if (nalloc > 0) delete[] value; + + nalloc = max(nalloc + c_nalloc_inc, _size); + value = new cfgValue[nalloc]; + } + + size = _size; + for (int k = 0; k < size; k++) + value[k] = _value; +} + +void scm::cfgVector::set(const int* x, const int _size) +{ + if (nalloc < _size) + { + if (nalloc > 0) delete[] value; + + nalloc = max(nalloc + c_nalloc_inc, _size); + value = new cfgValue[nalloc]; + } + + size = _size; + for (int k = 0; k < size; k++) + value[k] = cfgValue(x[k]); +} + +void scm::cfgVector::set(const float* x, const int _size) +{ + if (nalloc < _size) + { + if (nalloc > 0) delete[] value; + + nalloc = max(nalloc + c_nalloc_inc, _size); + value = new cfgValue[nalloc]; + } + + size = _size; + for (int k = 0; k < size; k++) + value[k] = cfgValue(x[k]); +} + +void scm::cfgVector::set(const double* x, const int _size) +{ + if (nalloc < _size) + { + if (nalloc > 0) delete[] value; + + nalloc = max(nalloc + c_nalloc_inc, _size); + value = new cfgValue[nalloc]; + } + + size = _size; + for (int k = 0; k < size; k++) + value[k] = cfgValue(x[k]); +} + +void scm::cfgVector::set(const long double* x, const int _size) +{ + if (nalloc < _size) + { + if (nalloc > 0) delete[] value; + + nalloc = max(nalloc + c_nalloc_inc, _size); + value = new cfgValue[nalloc]; + } + + size = _size; + for (int k = 0; k < size; k++) + value[k] = cfgValue(x[k]); +} + +bool scm::cfgVector::change(const int idx, const cfgValue& _value) +{ + if ((idx < 0) || (idx >= size)) return false; + + value[idx] = _value; + return true; +} + +void scm::cfgVector::append(const cfgValue& _value) +{ + if (size == nalloc) + { + if (nalloc == 0) + { + set(_value); + return; + } + + cfgValue *hvalue; + hvalue = new cfgValue[nalloc + c_nalloc_inc]; + + for (int k = 0; k < size; k++) { + hvalue[k].swap(value[k]); + } + + delete[] value; // size > 0 + value = hvalue; + + nalloc += c_nalloc_inc; + } + + value[size] = _value; + size++; +} + +void scm::cfgVector::set_name(const char* ex_name) +{ + if (ex_name == NULL) return; // keeping old name + + const size_t ex_size = strlen(ex_name) + 1; + if (ex_size > name_memsize) { + delete[] name; + + name_memsize = ex_size; + name = new char[name_memsize]; + } + + strcpy(name, ex_name); +} +// -------------------------------------------------------------------------------------------- // + +// * get calls * // +// -------------------------------------------------------------------------------------------- // +const scm::cfgValue scm::cfgVector::get(const int idx) const +{ + if ((idx < 0) || (idx >= size)) return cfgValue(); + return value[idx]; +} + +bool scm::cfgVector::get(const int idx, int* _value) const +{ + if ((idx < 0) || (idx >= size)) return false; + + return value[idx].get(_value); +} + +bool scm::cfgVector::get(const int idx, float* _value) const +{ + if ((idx < 0) || (idx >= size)) return false; + + return value[idx].get(_value); +} + +bool scm::cfgVector::get(const int idx, double* _value) const +{ + if ((idx < 0) || (idx >= size)) return false; + + return value[idx].get(_value); +} + +bool scm::cfgVector::get(const int idx, long double* _value) const +{ + if ((idx < 0) || (idx >= size)) return false; + + return value[idx].get(_value); +} + +bool scm::cfgVector::get(const int idx, char** c_str) const +{ + if ((idx < 0) || (idx >= size)) return false; + + return value[idx].get(c_str); +} + +bool scm::cfgVector::get(const int idx, std::string& _value) const +{ + if ((idx < 0) || (idx >= size)) return false; + + return value[idx].get(_value); +} + +bool scm::cfgVector::get(const int idx, bool* _value) const +{ + if ((idx < 0) || (idx >= size)) return false; + + return value[idx].get(_value); +} + +bool scm::cfgVector::get_if_single(int* _value) const +{ + if (size == 1) return (*value).get(_value); + return false; +} + +bool scm::cfgVector::get_if_single(float* _value) const +{ + if (size == 1) return (*value).get(_value); + return false; +} + +bool scm::cfgVector::get_if_single(double* _value) const +{ + if (size == 1) return (*value).get(_value); + return false; +} + +bool scm::cfgVector::get_if_single(long double* _value) const +{ + if (size == 1) return (*value).get(_value); + return false; +} + +bool scm::cfgVector::get_if_single(char** c_str) const +{ + if (size == 1) return (*value).get(c_str); + return false; +} + +bool scm::cfgVector::get_if_single(std::string& _value) const +{ + if (size == 1) return (*value).get(_value); + return false; +} + +bool scm::cfgVector::get_if_single(bool* _value) const +{ + if (size == 1) return (*value).get(_value); + return false; +} + +int scm::cfgVector::get_size() const +{ + return size; +} + +const char* scm::cfgVector::get_name() const +{ + return name; +} +// -------------------------------------------------------------------------------------------- // + +// * check calls * // +// -------------------------------------------------------------------------------------------- // +bool scm::cfgVector::is_defined() const +{ + for (int k = 0; k < size; k++) { + if (value[k].get_type() == cfgValue::IS_UNDEF) + return false; + } + + return (!is_empty()); +} + +bool scm::cfgVector::is_empty() const +{ + return (size == 0); +} + +bool scm::cfgVector::is_single() const +{ + return (size == 1); +} + +bool scm::cfgVector::is_name_empty() const +{ + return ((*name) == '\0'); +} + +bool scm::cfgVector::is_name_eq(const cfgVector& x) const +{ + return (!strcmp(name, x.name)); +} + +bool scm::cfgVector::is_name_eq(const char* _name) const +{ + if (_name == NULL) return false; + return (!strcmp(name, _name)); +} +// -------------------------------------------------------------------------------------------- // + +// * print * // +// -------------------------------------------------------------------------------------------- // +void scm::cfgVector::print() const +{ + printf(" > '%s'[%i] = ", name, get_size()); + + for (int k = 0; k < get_size(); k++) + { + value[k].print_typed(); + if (k < get_size() - 1) printf(", "); + } + printf("\n"); +} + +void scm::cfgVector::print_value() const +{ + if (size == 0) return; + if (size == 1) { + (*value).print(); + return; + } + + printf("["); + (*value).print(); + + for (int k = 1; k < get_size(); k++) + { + printf(", "); + value[k].print(); + } + printf("]"); +} +// -------------------------------------------------------------------------------------------- // + +// * operators * // +// -------------------------------------------------------------------------------------------- // +scm::cfgVector& scm::cfgVector::operator+=(const cfgVector& x) +{ + if (size == x.size) + { + for (int k = 0; k < size; k++) + value[k] += x.value[k]; + } + else + size = 0; // setting null vector + + return (*this); +} +scm::cfgVector& scm::cfgVector::operator-=(const cfgVector& x) +{ + if (size == x.size) + { + for (int k = 0; k < size; k++) + value[k] -= x.value[k]; + } + else + size = 0; // setting null vector + + return (*this); +} + +scm::cfgVector& scm::cfgVector::operator*=(const cfgVector& x) +{ + if (size == x.size) + { + for (int k = 0; k < size; k++) + value[k] *= x.value[k]; + } + else + size = 0; // setting null vector + + return (*this); +} + +scm::cfgVector& scm::cfgVector::operator/=(const cfgVector& x) +{ + if (size == x.size) + { + for (int k = 0; k < size; k++) + value[k] /= x.value[k]; + } + else + size = 0; // setting null vector + + return (*this); +} + +scm::cfgVector& scm::cfgVector::operator%=(const cfgVector& x) +{ + if (size == x.size) + { + for (int k = 0; k < size; k++) + value[k] %= x.value[k]; + } + else + size = 0; // setting null vector + + return (*this); +} + +scm::cfgVector& scm::cfgVector::operator^=(const cfgVector& x) +{ + if (size == x.size) + { + for (int k = 0; k < size; k++) + value[k] ^= x.value[k]; + } + else + size = 0; // setting null vector + + return (*this); +} + +const scm::cfgVector scm::cfgVector::operator+(const cfgVector& x) const +{ + return cfgVector(*this) += x; +} +const scm::cfgVector scm::cfgVector::operator-(const cfgVector& x) const +{ + return cfgVector(*this) -= x; +} +const scm::cfgVector scm::cfgVector::operator*(const cfgVector& x) const +{ + return cfgVector(*this) *= x; +} +const scm::cfgVector scm::cfgVector::operator/(const cfgVector& x) const +{ + return cfgVector(*this) /= x; +} +const scm::cfgVector scm::cfgVector::operator%(const cfgVector& x) const +{ + return cfgVector(*this) %= x; +} +const scm::cfgVector scm::cfgVector::operator^(const cfgVector& x) const +{ + return cfgVector(*this) ^= x; +} + +const scm::cfgVector scm::cfgVector::operator==(const cfgVector& x) const +{ + cfgVector res; + if (size == x.size) + { + res.set(cfgValue(), size); + for (int k = 0; k < size; k++) + res.value[k] = (value[k] == x.value[k]); + } + + return res; +} +const scm::cfgVector scm::cfgVector::operator!=(const cfgVector& x) const +{ + cfgVector res; + if (size == x.size) + { + res.set(cfgValue(), size); + for (int k = 0; k < size; k++) + res.value[k] = (value[k] != x.value[k]); + } + + return res; +} +const scm::cfgVector scm::cfgVector::operator<(const cfgVector& x) const +{ + cfgVector res; + if (size == x.size) + { + res.set(cfgValue(), size); + for (int k = 0; k < size; k++) + res.value[k] = (value[k] < x.value[k]); + } + + return res; +} +const scm::cfgVector scm::cfgVector::operator>(const cfgVector& x) const +{ + cfgVector res; + if (size == x.size) + { + res.set(cfgValue(), size); + for (int k = 0; k < size; k++) + res.value[k] = (value[k] > x.value[k]); + } + + return res; +} +const scm::cfgVector scm::cfgVector::operator<=(const cfgVector& x) const +{ + cfgVector res; + if (size == x.size) + { + res.set(cfgValue(), size); + for (int k = 0; k < size; k++) + res.value[k] = (value[k] <= x.value[k]); + } + + return res; +} +const scm::cfgVector scm::cfgVector::operator>=(const cfgVector& x) const +{ + cfgVector res; + if (size == x.size) + { + res.set(cfgValue(), size); + for (int k = 0; k < size; k++) + res.value[k] = (value[k] >= x.value[k]); + } + + return res; +} + +const scm::cfgVector scm::cfgVector::operator-() const +{ + cfgVector res((*this));; + for (int k = 0; k < size; k++) + res.value[k] = -value[k]; + + return res; +} +const scm::cfgVector scm::cfgVector::operator+() const +{ + cfgVector res((*this));; + for (int k = 0; k < size; k++) + res.value[k] = +value[k]; + + return res; +} + +const scm::cfgVector scm::cfgVector::logical_and(const cfgVector& x) const +{ + cfgVector res; + if (size == x.size) + { + res.set(cfgValue(), size); + for (int k = 0; k < size; k++) + res.value[k] = value[k].logical_and(x.value[k]); + } + + return res; +} + +const scm::cfgVector scm::cfgVector::logical_or(const cfgVector& x) const +{ + cfgVector res; + if (size == x.size) + { + res.set(cfgValue(), size); + for (int k = 0; k < size; k++) + res.value[k] = value[k].logical_or(x.value[k]); + } + + return res; +} +// -------------------------------------------------------------------------------------------- // + +// * functions * // +// -------------------------------------------------------------------------------------------- // +const scm::cfgVector +scm::cfgVector::cfg_sin(const cfgVector& x) +{ + cfgVector y; + y.set(cfgValue(), x.size); + + for (int k = 0; k < y.size; k++) + y.value[k] = cfgValue::cfg_sin(x.value[k]); + + return y; +} + +const scm::cfgVector +scm::cfgVector::cfg_cos(const cfgVector& x) +{ + cfgVector y; + y.set(cfgValue(), x.size); + + for (int k = 0; k < y.size; k++) + y.value[k] = cfgValue::cfg_cos(x.value[k]); + + return y; +} + +const scm::cfgVector +scm::cfgVector::cfg_tan(const cfgVector& x) +{ + cfgVector y; + y.set(cfgValue(), x.size); + + for (int k = 0; k < y.size; k++) + y.value[k] = cfgValue::cfg_tan(x.value[k]); + + return y; +} + +const scm::cfgVector +scm::cfgVector::cfg_log(const cfgVector& x) +{ + cfgVector y; + y.set(cfgValue(), x.size); + + for (int k = 0; k < y.size; k++) + y.value[k] = cfgValue::cfg_log(x.value[k]); + + return y; +} + +const scm::cfgVector +scm::cfgVector::cfg_sqrt(const cfgVector& x) +{ + cfgVector y; + y.set(cfgValue(), x.size); + + for (int k = 0; k < y.size; k++) + y.value[k] = cfgValue::cfg_sqrt(x.value[k]); + + return y; +} + +const scm::cfgVector +scm::cfgVector::cfg_abs(const cfgVector& x) +{ + cfgVector y; + y.set(cfgValue(), x.size); + + for (int k = 0; k < y.size; k++) + y.value[k] = cfgValue::cfg_abs(x.value[k]); + + return y; +} + +const scm::cfgVector +scm::cfgVector::cfg_to_string(const cfgVector& x) +{ + cfgVector y; + y.set(cfgValue(), x.size); + + for (int k = 0; k < y.size; k++) + y.value[k] = cfgValue::cfg_to_string(x.value[k]); + + return y; +} + +const scm::cfgVector +scm::cfgVector::cfg_vecmin(const cfgVector& x) +{ + if (x.size > 0) + { + cfgValue _min = x.value[0]; + for (int k = 1; k < x.size; k++) + { + cfgValue cmp = (x.value[k] < _min); + + bool is_less; + if (!cmp.get(&is_less)) return cfgVector(); + + if (is_less) _min = x.value[k]; + } + return cfgVector(_min); + } + else + return cfgVector(); +} + +const scm::cfgVector +scm::cfgVector::cfg_vecmax(const cfgVector& x) +{ + if (x.size > 0) + { + cfgValue _max = x.value[0]; + for (int k = 1; k < x.size; k++) + { + cfgValue cmp = (x.value[k] > _max); + + bool is_greater; + if (!cmp.get(&is_greater)) return cfgVector(); + + if (is_greater) _max = x.value[k]; + } + return cfgVector(_max); + } + else + return cfgVector(); +} + +const scm::cfgVector +scm::cfgVector::cfg_min(const cfgVector& a, const cfgVector& b) +{ + cfgVector _min; + if (a.size == b.size) + { + _min.set(cfgValue(), a.size); + for (int k = 0; k < _min.size; k++) + _min.value[k] = cfgValue::cfg_min(a.value[k], b.value[k]); + } + + return _min; +} + +const scm::cfgVector +scm::cfgVector::cfg_max(const cfgVector& a, const cfgVector& b) +{ + cfgVector _max; + if (a.size == b.size) + { + _max.set(cfgValue(), a.size); + for (int k = 0; k < _max.size; k++) + _max.value[k] = cfgValue::cfg_max(a.value[k], b.value[k]); + } + + return _max; +} + +const scm::cfgVector +scm::cfgVector::cfg_dot_product(const cfgVector& a, const cfgVector& b) +{ + if ((a.size == b.size) && (a.size > 0)) + { + cfgValue dp(0); + for (int k = 0; k < a.size; k++) + dp += a.value[k] * b.value[k]; + + return cfgVector(dp); + } + else + return cfgVector(); +} + +const scm::cfgVector +scm::cfgVector::cfg_l2norm(const cfgVector& x) +{ + if (x.size == 0) return cfgVector(); + + cfgValue norm((double)0); + for (int k = 0; k < x.size; k++) + norm += x.value[k] * x.value[k]; + + return cfgVector(cfgValue::cfg_sqrt(norm)); +} + +const scm::cfgVector +scm::cfgVector::cfg_cnorm(const cfgVector& x) +{ + if (x.size == 0) return cfgVector(); + + cfgValue norm(cfgValue::cfg_abs(x.value[0])); + for (int k = 1; k < x.size; k++) + { + cfgValue cfg_is_max = (cfgValue::cfg_abs(x.value[k]) > norm); + bool is_max; + if (!cfg_is_max.get(&is_max)) + return cfgVector(); + + if (is_max) norm = cfgValue::cfg_abs(x.value[k]); + } + + return cfgVector(norm); +} +// -------------------------------------------------------------------------------------------- // diff --git a/parser/cfg-vec.h b/parser/cfg-vec.h new file mode 100644 index 0000000..fe2d643 --- /dev/null +++ b/parser/cfg-vec.h @@ -0,0 +1,146 @@ +#pragma once + +#include "cfg-value.h" + +namespace scm +{ + class cfgVector + { + public: + + // set & add calls + // -------------------------------------------------------------------------------------------- // + void set(const cfgValue& value); + void set(const cfgValue& value, const int size); + + void set(const int* x, const int size); + void set(const float* x, const int size); + void set(const double* x, const int size); + void set(const long double* x, const int size); + + bool change(const int idx, const cfgValue& value); + void append(const cfgValue& value); + + void set_name(const char* name); + // *: name == NULL - not changing vector name + // -------------------------------------------------------------------------------------------- // + + // get calls + // -------------------------------------------------------------------------------------------- // + const cfgValue get(const int idx) const; + + bool get(const int idx, int* value) const; + bool get(const int idx, float* value) const; + bool get(const int idx, double* value) const; + bool get(const int idx, long double* value) const; + bool get(const int idx, char** c_str) const; + bool get(const int idx, std::string& value) const; + bool get(const int idx, bool* value) const; + + bool get_if_single(int* value) const; + bool get_if_single(float* value) const; + bool get_if_single(double* value) const; + bool get_if_single(long double* value) const; + bool get_if_single(char** c_str) const; + bool get_if_single(std::string& value) const; + bool get_if_single(bool* value) const; + + int get_size() const; + const char* get_name() const; + // -------------------------------------------------------------------------------------------- // + + // check calls + // -------------------------------------------------------------------------------------------- // + bool is_defined() const; + // *: size != 0 && all values defined + bool is_empty() const; + // *: size == 0 + bool is_name_empty() const; + // *: name = "\0"; + bool is_name_eq(const cfgVector& x) const; + bool is_name_eq(const char* name) const; + bool is_single() const; + // *: size == 1 + // -------------------------------------------------------------------------------------------- // + + // print + // -------------------------------------------------------------------------------------------- // + void print() const; + void print_value() const; + // -------------------------------------------------------------------------------------------- // + + // operators + // -------------------------------------------------------------------------------------------- // + cfgVector& operator+=(const cfgVector& x); + cfgVector& operator-=(const cfgVector& x); + cfgVector& operator*=(const cfgVector& x); + cfgVector& operator/=(const cfgVector& x); + cfgVector& operator%=(const cfgVector& x); + cfgVector& operator^=(const cfgVector& x); + + const cfgVector operator+(const cfgVector& x) const; + const cfgVector operator-(const cfgVector& x) const; + const cfgVector operator*(const cfgVector& x) const; + const cfgVector operator/(const cfgVector& x) const; + const cfgVector operator%(const cfgVector& x) const; + const cfgVector operator^(const cfgVector& x) const; + + const cfgVector operator==(const cfgVector& x) const; + const cfgVector operator!=(const cfgVector& x) const; + const cfgVector operator<(const cfgVector& x) const; + const cfgVector operator>(const cfgVector& x) const; + const cfgVector operator<=(const cfgVector& x) const; + const cfgVector operator>=(const cfgVector& x) const; + + const cfgVector operator-() const; + const cfgVector operator+() const; + + const cfgVector logical_and(const cfgVector& x) const; // no short-circuit + const cfgVector logical_or(const cfgVector& y) const; // no short-circuit + // -------------------------------------------------------------------------------------------- // + + // functions + // -------------------------------------------------------------------------------------------- // + static const cfgVector cfg_sin(const cfgVector& x); + static const cfgVector cfg_cos(const cfgVector& x); + static const cfgVector cfg_tan(const cfgVector& x); + static const cfgVector cfg_log(const cfgVector& x); + static const cfgVector cfg_sqrt(const cfgVector& x); + static const cfgVector cfg_abs(const cfgVector& x); + static const cfgVector cfg_to_string(const cfgVector& x); + static const cfgVector cfg_vecmin(const cfgVector& x); + static const cfgVector cfg_vecmax(const cfgVector& x); + + static const cfgVector cfg_min(const cfgVector& a, const cfgVector& b); + static const cfgVector cfg_max(const cfgVector& a, const cfgVector& b); + + static const cfgVector cfg_dot_product(const cfgVector& a, const cfgVector& b); + static const cfgVector cfg_l2norm(const cfgVector& x); + static const cfgVector cfg_cnorm(const cfgVector& x); + // -------------------------------------------------------------------------------------------- // + + // -------------------------------------------------------------------------------------------- // + cfgVector(); + cfgVector(const cfgValue& value); + ~cfgVector(); + + cfgVector(const cfgVector& x); + const cfgVector& operator=(cfgVector x); + void swap(cfgVector& x); + // -------------------------------------------------------------------------------------------- // + + private: + // data (private): + // -------------------------------------------------------------------------------------------- // + + int size; + int nalloc; + static const int c_nalloc_inc = 8; + + cfgValue *value; + + char* name; // default name = empty string = "\0" + size_t name_memsize; // memory handler for name string + }; +} + diff --git a/parser/config-parser.cpp b/parser/config-parser.cpp new file mode 100644 index 0000000..00e1dbe --- /dev/null +++ b/parser/config-parser.cpp @@ -0,0 +1,2382 @@ +#include "config-parser.h" + +#define _CRT_SECURE_NO_DEPRECATE +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <limits.h> + +#include <stack> + +#include "lexeme-parser.h" + +// -------------------------------------------------------------------------------------------- // + +// +// Implementation: helper classes +// +// ConfigParser::parserState +scm::ConfigParser::parserState::parserState() +{ + idx = 0; + + nalloc = c_alloc_init; + name_space = new char[c_alloc_init]; + *name_space = '\0'; + + name_buf_nalloc = 0; +} +scm::ConfigParser::parserState::parserState( + const parserState &state) +{ + idx = state.idx; + nalloc = state.nalloc; + + name_space = new char[nalloc]; + strcpy(name_space, state.name_space); + + name_buf_nalloc = state.name_buf_nalloc; + if (name_buf_nalloc > 0) + name_buf = new char[name_buf_nalloc]; +} +scm::ConfigParser::parserState::~parserState() +{ + delete[] name_space; + + if (name_buf_nalloc > 0) + delete[] name_buf; +} + +void scm::ConfigParser::parserState::truncate_name_space() +{ + char *ptr = strrchr(name_space, '.'); + if (ptr == NULL) + *name_space = '\0'; + else + *ptr = '\0'; +} + +void scm::ConfigParser::parserState::append_name_space( + const char *name) +{ + int ptr = (int)strlen(name_space); + int nsize = ptr + (int)strlen(name) + 2; + + if (nsize > nalloc) + { + nalloc = nsize; + + char *buf = new char[nalloc]; + strcpy(buf, name_space); + + delete[] name_space; + name_space = buf; + } + + if (ptr > 0) + { + name_space[ptr] = '.'; + name_space[ptr + 1] = '\0'; + } + strcat(name_space, name); +} + +const char *scm::ConfigParser::parserState::get_global_name(const char *varname) +{ + int ptr = (int)strlen(name_space); + int nsize = ptr + (int)strlen(varname) + 2; + + if (nsize > name_buf_nalloc) + { + if (name_buf_nalloc > 0) + delete[] name_buf; + name_buf_nalloc = nsize; + + name_buf = new char[name_buf_nalloc]; + } + + strcpy(name_buf, name_space); + if (ptr > 0) + { + name_buf[ptr] = '.'; + name_buf[ptr + 1] = '\0'; + } + strcat(name_buf, varname); + + return name_buf; +} +// -------------------------------------------------------------------------------------------- // + +// +// Implementation: ConfigureParser +// +scm::ConfigParser::ConfigParser() +{ + nvars = 0; + nalloc_vars = c_alloc_vars_init; + + var = new cfgVector[nalloc_vars]; +} + +scm::ConfigParser::~ConfigParser() +{ + nvars = 0; + nalloc_vars = 0; + + delete[] var; +} +// -------------------------------------------------------------------------------------------- // + +bool scm::ConfigParser::run(const char *filename) +{ + parserCallBack pcb; + return run(filename, pcb); +} + +bool scm::ConfigParser::run(const char *filename, + parserCallBack &pcb) +{ + // removing elements in config -- but keeping memory + nvars = 0; + + LexemeList lexeme_list; + + if (!LexemeParser::run(filename, lexeme_list)) + return false; + if (lexeme_list.get_size() == 0) + return true; // nothing to parse + + // --- preliminary check + if (!parse_syntax(lexeme_list, false, pcb)) + return false; + return parse_syntax(lexeme_list, true, pcb); +} + +// * get rpn expression form * // +// -------------------------------------------------------------------------------------------- // +bool scm::ConfigParser::get_rpn( + mem_buffer<int> &rpn, + mem_buffer<int> &rpn_key, + const LexemeList &lexeme_list, const int lex_beg, const int lex_end) const +{ + std::stack<int> narg_stack; + + rpn.reset(); + rpn_key.reset(); + + if ((lex_beg < 0) || (lex_end > lexeme_list.get_size() - 1)) + { + printf(" CONFIG:> incorrect expression range (%i, %i), lexeme list size = %i\n", + lex_beg, lex_end, lexeme_list.get_size()); + return false; + } + + std::stack<int> hstack; + Lexeme::TYPE lex_type; + + bool status = true; + enum YARD_STATE + { + EXPECT_OPERAND, + EXPECT_OPERATOR + } state = EXPECT_OPERAND; + + int idx = lex_beg; + while (idx <= lex_end) + { + lex_type = lexeme_list.get_type(idx); + // ----------------------------------------------------- // + + if ((Lexeme::is_value(lex_type)) || + (lex_type == Lexeme::IS_NAME)) + { + if (state != EXPECT_OPERAND) + { + printf(" CONFIG:> unexpected lexeme '%s' (line, %i)\n", + lexeme_list.get_token(idx), lexeme_list.get_tag(idx)); + status = false; + break; + } + + // --- adding value | variable reference to output + // but postpone variable check to evaluation step + rpn.append(idx); + // --- adding not a function key to number of arguments + rpn_key.append(-1); + + state = EXPECT_OPERATOR; + idx++; + + // --- processing index operator + if ((lex_type == Lexeme::IS_NAME) && (idx <= lex_end)) + { + if (lexeme_list.get_type(idx) == Lexeme::IS_BRACKET_OPEN) + { + // --- pushing '[' to stack + hstack.push(idx); + + state = EXPECT_OPERAND; + idx++; + } + } + + continue; // --> next iteration + } + // ----------------------------------------------------- // + + if ((Lexeme::is_function(lex_type)) || + (Lexeme::is_ctor(lex_type)) || + (lex_type == Lexeme::IS_COMMAND)) + { + if (state != EXPECT_OPERAND) + { + printf(" CONFIG:> unexpected lexeme '%s' (line, %i)\n", + lexeme_list.get_token(idx), lexeme_list.get_tag(idx)); + status = false; + break; + } + + // --- pushing function to stack + hstack.push(idx); + + // --- processing function opening parenthesis + idx++; + if (idx > lex_end) + { + printf(" CONFIG:> expecting function '%s' call (line, %i)\n", + lexeme_list.get_token(idx - 1), lexeme_list.get_tag(idx - 1)); + status = false; + break; + } + + if (lexeme_list.get_type(idx) != Lexeme::IS_PAREN_OPEN) + { + printf(" CONFIG:> expecting function '%s' call (line, %i)\n", + lexeme_list.get_token(idx - 1), lexeme_list.get_tag(idx - 1)); + printf(" CONFIG:> unexpected lexeme '%s' (line, %i)\n", + lexeme_list.get_token(idx), lexeme_list.get_tag(idx)); + status = false; + break; + } + + // --- pushing '(' to stack + hstack.push(idx); + + // --- checking for void function closing parenthesis + idx++; + if (idx > lex_end) + { + printf(" CONFIG:> expecting function '%s' call (line, %i)\n", + lexeme_list.get_token(idx - 2), lexeme_list.get_tag(idx - 2)); + status = false; + break; + } + + if (lexeme_list.get_type(idx) == Lexeme::IS_PAREN_CLOSE) + { + // --- removing function & '(' from stack + hstack.pop(); + hstack.pop(); + + // --- adding function to output + rpn.append(idx - 2); + + // --- adding 0 as number of arguments + rpn_key.append(0); + + state = EXPECT_OPERATOR; + idx++; + } + else + { + // --- adding 1 as number of expected arguments + narg_stack.push(1); + + state = EXPECT_OPERAND; + } + + continue; // --> next iteration + } + // ----------------------------------------------------- // + + if (lex_type == Lexeme::IS_PAREN_OPEN) + { + if (state != EXPECT_OPERAND) + { + printf(" CONFIG:> unexpected lexeme '%s' (line, %i)\n", + lexeme_list.get_token(idx), lexeme_list.get_tag(idx)); + status = false; + break; + } + + // --- pushing '(' to stack + hstack.push(idx); + + state = EXPECT_OPERAND; + idx++; + continue; // --> next iteration + } + // ----------------------------------------------------- // + + if (lex_type == Lexeme::IS_PAREN_CLOSE) + { + if (state != EXPECT_OPERATOR) + { + printf(" CONFIG:> unexpected lexeme '%s' (line, %i)\n", + lexeme_list.get_token(idx), lexeme_list.get_tag(idx)); + status = false; + break; + } + + // --- pop till '(' found & remove '(' from stack + int stack_idx; + bool flag = false; + while (!hstack.empty()) + { + stack_idx = hstack.top(); + if (lexeme_list.get_type(stack_idx) == Lexeme::IS_BRACKET_OPEN) + break; + + hstack.pop(); + if (lexeme_list.get_type(stack_idx) == Lexeme::IS_PAREN_OPEN) + { + flag = true; + break; + } + + rpn.append(stack_idx); + // --- adding not a function key to number of arguments + rpn_key.append(-1); + } + if (!flag) + { + printf(" CONFIG:> missing parenthesis '(' (line, %i)\n", + lexeme_list.get_tag(idx)); + status = false; + break; + } + + // --- checking if function is at the top of the stack + if (!hstack.empty()) + { + stack_idx = hstack.top(); + if ((lexeme_list.is_function(stack_idx)) || + (lexeme_list.is_ctor(stack_idx)) || + (lexeme_list.get_type(stack_idx) == Lexeme::IS_COMMAND)) + { + hstack.pop(); + rpn.append(stack_idx); + + // --- adding number of expected arguments from stack + int narg = narg_stack.top(); + narg_stack.pop(); + rpn_key.append(narg); + } + } + + state = EXPECT_OPERATOR; + idx++; + continue; // --> next iteration + } + // ----------------------------------------------------- // + + if (lex_type == Lexeme::IS_COMMA) + { + if (state != EXPECT_OPERATOR) + { + printf(" CONFIG:> unexpected lexeme '%s' (line, %i)\n", + lexeme_list.get_token(idx), lexeme_list.get_tag(idx)); + status = false; + break; + } + + // --- pop till '(' found & keep '(' on stack + int stack_idx; + bool flag = false; + while (!hstack.empty()) + { + stack_idx = hstack.top(); + + if (lexeme_list.get_type(stack_idx) == Lexeme::IS_BRACKET_OPEN) + break; + if (lexeme_list.get_type(stack_idx) == Lexeme::IS_PAREN_OPEN) + { + flag = true; + break; + } + + hstack.pop(); + rpn.append(stack_idx); + // --- adding not a function key to number of arguments + rpn_key.append(-1); + } + if (!flag) + { + printf(" CONFIG:> missing parenthesis '(' or misplaced ',' delimeter (line, %i)\n", + lexeme_list.get_tag(idx)); + status = false; + break; + } + + // --- checking if function is on top of the stack + + // --- temporary removing '(' + hstack.pop(); + if (hstack.empty()) + { + printf(" CONFIG:> misplaced ',' delimiter (line, %i)\n", + lexeme_list.get_tag(idx)); + status = false; + break; + } + if ((!lexeme_list.is_function(hstack.top())) && + (!lexeme_list.is_ctor(hstack.top())) && + (lexeme_list.get_type(hstack.top()) != Lexeme::IS_COMMAND)) + { + printf(" CONFIG:> misplaced ',' delimiter (line, %i)\n", + lexeme_list.get_tag(idx)); + status = false; + break; + } + // --- adding '(' back to stack + hstack.push(stack_idx); + + // --- increase number of expected arguments + int narg = narg_stack.top(); + narg_stack.pop(); + narg++; + narg_stack.push(narg); + + state = EXPECT_OPERAND; + idx++; + continue; // --> next iteration + } + // ----------------------------------------------------- // + + if (Lexeme::is_operator(lex_type)) + { + // --- handling operators + if (((is_operator_unary(lex_type)) && (state != EXPECT_OPERAND)) || + ((is_operator_binary(lex_type)) && (state != EXPECT_OPERATOR))) + { + printf(" CONFIG:> unexpected lexeme '%s' (line, %i)\n", + lexeme_list.get_token(idx), lexeme_list.get_tag(idx)); + status = false; + break; + } + + int stack_idx; + while (!hstack.empty()) + { + stack_idx = hstack.top(); + + if (lexeme_list.is_operator(stack_idx)) + { + Lexeme::TYPE stack_type = lexeme_list.get_type(stack_idx); + + if (((is_operator_assoc_left(lex_type)) && + (!operator_priority_lt(stack_type, lex_type))) || + ((is_operator_assoc_right(lex_type)) && + (operator_priority_lt(lex_type, stack_type)))) + { + hstack.pop(); + rpn.append(stack_idx); + // --- adding not a function key to number of arguments + rpn_key.append(-1); + continue; + } + } + + break; + } + hstack.push(idx); + + state = EXPECT_OPERAND; + idx++; + continue; // --> next iteration + } + // ----------------------------------------------------- // + + if (lex_type == Lexeme::IS_BRACKET_CLOSE) + { + if (state != EXPECT_OPERATOR) + { + printf(" CONFIG:> unexpected lexeme '%s' (line, %i)\n", + lexeme_list.get_token(idx), lexeme_list.get_tag(idx)); + status = false; + break; + } + + // --- pop till '[' found & remove '[' from stack & add '[' to output + int stack_idx; + bool flag = false; + while (!hstack.empty()) + { + stack_idx = hstack.top(); + if (lexeme_list.get_type(stack_idx) == Lexeme::IS_PAREN_OPEN) + break; + + hstack.pop(); + rpn.append(stack_idx); + // --- adding not a function key to number of arguments + rpn_key.append(-1); + + if (lexeme_list.get_type(stack_idx) == Lexeme::IS_BRACKET_OPEN) + { + flag = true; + break; + } + } + if (!flag) + { + printf(" CONFIG:> missing bracket '[' (line, %i)\n", + lexeme_list.get_tag(idx)); + status = false; + break; + } + + state = EXPECT_OPERATOR; + idx++; + continue; // --> next iteration + } + // ----------------------------------------------------- // + + printf(" CONFIG:> unexpected lexeme in expression: '%s' (line, %i)\n", + lexeme_list.get_token(idx), lexeme_list.get_tag(idx)); + status = false; + break; + } + + // --- removing elements until stack is empty or getting '(' + int stack_idx; + while (!hstack.empty()) + { + stack_idx = hstack.top(); + if (lexeme_list.get_type(stack_idx) == Lexeme::IS_PAREN_OPEN) + { + printf(" CONFIG:> missing bracket ')' (line, %i)\n", + lexeme_list.get_tag(stack_idx)); + status = false; + break; + } + if (lexeme_list.get_type(stack_idx) == Lexeme::IS_BRACKET_OPEN) + { + printf(" CONFIG:> missing bracket ']' (line, %i)\n", + lexeme_list.get_tag(stack_idx)); + status = false; + break; + } + + hstack.pop(); + rpn.append(stack_idx); + // --- adding not a function key to number of arguments + rpn_key.append(-1); + } + // ----------------------------------------------------- // + + return status && + (rpn.get_size() != 0) && (state == EXPECT_OPERATOR); +} +// -------------------------------------------------------------------------------------------- // + +// * evaluate rpn expression * // +// -------------------------------------------------------------------------------------------- // +bool scm::ConfigParser::evaluate_rpn( + std::stack<cfgVector> &dyn_expr, + const mem_buffer<int> &rpn, + const mem_buffer<int> &rpn_key, + const int rpn_begin, const int rpn_end, + const LexemeList &lexeme_list, const char *name_space, + const bool exe_cntrl) const +{ + Lexeme::TYPE lex_type; + int eidx; + + mem_buffer<char> arg_name_buf; + + for (int i = max(rpn_begin, 0); i <= min(rpn_end, rpn.get_size() - 1); i++) + { + eidx = rpn.get_value(i); + lex_type = lexeme_list.get_type(eidx); + // ----------------------------------------------------- // + + if (is_operator_binary(lex_type)) + { + if (dyn_expr.size() >= 2) + { + cfgVector a = dyn_expr.top(); + dyn_expr.pop(); + cfgVector b = dyn_expr.top(); + dyn_expr.pop(); + + bool arg_defined = ((a.is_defined()) && (b.is_defined())); + + if (lex_type == Lexeme::IS_OP_ADD) + b += a; + else if (lex_type == Lexeme::IS_OP_SUB) + b -= a; + else if (lex_type == Lexeme::IS_OP_MUL) + b *= a; + else if (lex_type == Lexeme::IS_OP_DIV) + b /= a; + else if (lex_type == Lexeme::IS_OP_MOD) + b %= a; + else if (lex_type == Lexeme::IS_OP_EXP) + b ^= a; + else if (lex_type == Lexeme::IS_OP_EQ) + b = (b == a); + else if (lex_type == Lexeme::IS_OP_NEQ) + b = (b != a); + else if (lex_type == Lexeme::IS_OP_LT) + b = (b < a); + else if (lex_type == Lexeme::IS_OP_GT) + b = (b > a); + else if (lex_type == Lexeme::IS_OP_LEQ) + b = (b <= a); + else if (lex_type == Lexeme::IS_OP_GEQ) + b = (b >= a); + else if (lex_type == Lexeme::IS_OP_LOGICAL_AND) + b = b.logical_and(a); + else if (lex_type == Lexeme::IS_OP_LOGICAL_OR) + b = b.logical_or(a); + else + { + printf(" CONFIG:> unknown binary operation: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + if ((exe_cntrl || arg_defined) && (!b.is_defined())) + { + printf(" CONFIG:> incorrect types of operands: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + dyn_expr.push(b); + } + else + { + printf(" CONFIG:> insufficient number of arguments: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + // --> next iteration + continue; + } + // ----------------------------------------------------- // + + if (lex_type == Lexeme::IS_BRACKET_OPEN) + { + // --- index operator + if (dyn_expr.size() >= 2) + { + cfgVector op = dyn_expr.top(); + dyn_expr.pop(); + cfgVector a = dyn_expr.top(); + dyn_expr.pop(); + + bool arg_defined = ((a.is_defined()) && (op.is_defined())); + + if (exe_cntrl || arg_defined) + { + int index; + if (!op.get_if_single(&index)) + { + printf(" CONFIG:> incorrect index value: '[]' (line, %i)\n", + lexeme_list.get_tag(eidx)); + return false; + } + + cfgVector value = cfgVector(a.get(index)); + if (!value.is_defined()) + { + printf(" CONFIG:> incorrect types of operands: '[]' (line, %i)\n", + lexeme_list.get_tag(eidx)); + return false; + } + dyn_expr.push(value); + } + else + { + dyn_expr.push(cfgVector()); + } + } + else + { + printf(" CONFIG:> insufficient number of arguments: '[]' (line, %i)\n", + lexeme_list.get_tag(eidx)); + return false; + } + + // --> next iteration + continue; + } + // ----------------------------------------------------- // + + if (is_operator_unary(lex_type)) + { + if (dyn_expr.size() >= 1) + { + cfgVector op = dyn_expr.top(); + dyn_expr.pop(); + cfgVector res; + + bool arg_defined = (op.is_defined()); + + if (lex_type == Lexeme::IS_OP_PLUS) + res = +op; + else if (lex_type == Lexeme::IS_OP_MINUS) + res = -op; + else + { + printf(" CONFIG:> unknown unary operation: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + if ((exe_cntrl || arg_defined) && (!res.is_defined())) + { + printf(" CONFIG:> incorrect type of operand: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + dyn_expr.push(res); + } + else + { + printf(" CONFIG:> insufficient number of arguments: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + // --> next iteration + continue; + } + // ----------------------------------------------------- // + + if (Lexeme::is_function(lex_type)) + { + if (rpn_key.get_value(i) != function_nargs(lex_type)) + { + printf(" CONFIG:> incorrect number (%i) of arguments in function: '%s' (line, %i)\n", + rpn_key.get_value(i), lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + if (function_nargs(lex_type) == 2) + { + if (dyn_expr.size() >= 2) + { + cfgVector op2 = dyn_expr.top(); + dyn_expr.pop(); + cfgVector op1 = dyn_expr.top(); + dyn_expr.pop(); + cfgVector res; + + bool arg_defined = ((op1.is_defined()) && (op2.is_defined())); + + if (lex_type == Lexeme::IS_MIN_FUNCTION) + res = cfgVector::cfg_min(op1, op2); + else if (lex_type == Lexeme::IS_MAX_FUNCTION) + res = cfgVector::cfg_max(op1, op2); + else if (lex_type == Lexeme::IS_DOT_PRODUCT_FUNCTION) + res = cfgVector::cfg_dot_product(op1, op2); + else if (lex_type == Lexeme::IS_UNIRAND_FUNCTION) + { + if (exe_cntrl || arg_defined) + { + double a, b; + if (!op1.get_if_single(&a)) + { + printf(" CONFIG:> incorrect type of operand: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + if (!op2.get_if_single(&b)) + { + printf(" CONFIG:> incorrect type of operand: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + double value = a + (rand() / (RAND_MAX / (b - a))); + res = cfgVector(cfgValue(value)); + } + else + { + res = cfgVector(); + } + } + else + { + printf(" CONFIG:> unknown function: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + if ((exe_cntrl || arg_defined) && (!res.is_defined())) + { + printf(" CONFIG:> incorrect type of operand: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + dyn_expr.push(res); + } + else + { + printf(" CONFIG:> insufficient number of arguments: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + // --> next iteration + continue; + } + + if (function_nargs(lex_type) == 1) + { + if (dyn_expr.size() >= 1) + { + cfgVector op = dyn_expr.top(); + dyn_expr.pop(); + cfgVector res; + + bool arg_defined = (op.is_defined()); + + if (lex_type == Lexeme::IS_VECMIN_FUNCTION) + res = cfgVector::cfg_vecmin(op); + else if (lex_type == Lexeme::IS_VECMAX_FUNCTION) + res = cfgVector::cfg_vecmax(op); + else if (lex_type == Lexeme::IS_SIN_FUNCTION) + res = cfgVector::cfg_sin(op); + else if (lex_type == Lexeme::IS_COS_FUNCTION) + res = cfgVector::cfg_cos(op); + else if (lex_type == Lexeme::IS_TAN_FUNCTION) + res = cfgVector::cfg_tan(op); + else if (lex_type == Lexeme::IS_LOG_FUNCTION) + res = cfgVector::cfg_log(op); + else if (lex_type == Lexeme::IS_SQRT_FUNCTION) + res = cfgVector::cfg_sqrt(op); + else if (lex_type == Lexeme::IS_ABS_FUNCTION) + res = cfgVector::cfg_abs(op); + else if (lex_type == Lexeme::IS_L2NORM_FUNCTION) + res = cfgVector::cfg_l2norm(op); + else if (lex_type == Lexeme::IS_CNORM_FUNCTION) + res = cfgVector::cfg_cnorm(op); + else if (lex_type == Lexeme::IS_TO_STRING_FUNCTION) + res = cfgVector::cfg_to_string(op); + else if (lex_type == Lexeme::IS_SIZE_FUNCTION) + res = cfgVector(cfgValue(op.get_size())); + else if (lex_type == Lexeme::IS_DEFINED_FUNCTION) + { + if (exe_cntrl || arg_defined) + { + std::string name; + if (!op.get_if_single(name)) + { + printf(" CONFIG:> incorrect type of operand: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + res = (is_varname(name.c_str())) ? cfgVector(cfgValue(true)) : cfgVector(cfgValue(false)); + } + else + { + res = cfgVector(); + } + } + else + { + printf(" CONFIG:> unknown function: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + if ((exe_cntrl || arg_defined) && (!res.is_defined())) + { + printf(" CONFIG:> incorrect type of operand: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + dyn_expr.push(res); + } + else + { + printf(" CONFIG:> insufficient number of arguments: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + // --> next iteration + continue; + } + + printf(" CONFIG:> unknown function: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + // ----------------------------------------------------- // + + if (Lexeme::is_ctor(lex_type)) + { + if (lex_type == Lexeme::IS_VECTOR_CTOR) + { + int narg = rpn_key.get_value(i); + if (narg < 0) + { + printf(" CONFIG:> incorrect number of arguments: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + cfgVector vec; + if (dyn_expr.size() >= (unsigned int)narg) + { + + std::stack<cfgValue> vec_arg; + for (int k = 0; k < narg; k++) + { + + cfgVector arg = dyn_expr.top(); + dyn_expr.pop(); + + if ((exe_cntrl) && (!arg.is_defined())) + { + printf(" CONFIG:> undefined argument: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + if ((exe_cntrl || (arg.is_defined())) && (!arg.is_single())) + { + printf(" CONFIG:> incorrect argument size > 1: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + vec_arg.push(arg.get(0)); + } + + cfgVector vec; + // --- using stack to append values in correct order + while (!vec_arg.empty()) + { + vec.append(vec_arg.top()); + vec_arg.pop(); + } + + dyn_expr.push(vec); + } + else + { + printf(" CONFIG:> insufficient number of arguments: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + // --> next iteration + continue; + } + + if (lex_type == Lexeme::IS_VECTOR_CONST_CTOR) + { + if (rpn_key.get_value(i) != 2) + { + printf(" CONFIG:> incorrect number (%i) of arguments in constructor: '%s' (line, %i)\n", + rpn_key.get_value(i), lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + if (dyn_expr.size() >= 2) + { + cfgVector vec_value = dyn_expr.top(); + dyn_expr.pop(); + cfgVector vec_size = dyn_expr.top(); + dyn_expr.pop(); + + bool arg_defined = ((vec_value.is_defined()) && + (vec_size.is_defined())); + + if (exe_cntrl || arg_defined) + { + int size; + if (!vec_size.get_if_single(&size)) + { + printf(" CONFIG:> incorrect size argument: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + if (size < 0) + { + printf(" CONFIG:> invalid size (%i) argument: '%s' (line, %i)\n", + size, lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + if (!vec_value.is_defined()) + { + printf(" CONFIG:> undefined argument: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + if (!vec_value.is_single()) + { + printf(" CONFIG:> incorrect argument size > 1: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + cfgVector vec; + vec.set(vec_value.get(0), size); + dyn_expr.push(vec); + } + else + { + dyn_expr.push(cfgVector()); + } + } + else + { + printf(" CONFIG:> insufficient number of arguments: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + // --> next iteration + continue; + } + + if (lex_type == Lexeme::IS_VECTOR_UNIRAND_CTOR) + { + if (rpn_key.get_value(i) != 3) + { + printf(" CONFIG:> incorrect number (%i) of arguments in constructor: '%s' (line, %i)\n", + rpn_key.get_value(i), lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + if (dyn_expr.size() >= 3) + { + cfgVector vec_b = dyn_expr.top(); + dyn_expr.pop(); + cfgVector vec_a = dyn_expr.top(); + dyn_expr.pop(); + cfgVector vec_size = dyn_expr.top(); + dyn_expr.pop(); + + bool arg_defined = ((vec_b.is_defined()) && + (vec_a.is_defined()) && + (vec_size.is_defined())); + + if (exe_cntrl || arg_defined) + { + int size; + if (!vec_size.get_if_single(&size)) + { + printf(" CONFIG:> incorrect size argument: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + if (size < 0) + { + printf(" CONFIG:> invalid size (%i) argument: '%s' (line, %i)\n", + size, lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + double a, b; + if (!vec_a.get_if_single(&a)) + { + printf(" CONFIG:> incorrect type of operand: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + if (!vec_b.get_if_single(&b)) + { + printf(" CONFIG:> incorrect type of operand: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + double value = (a == b) ? a : a + (rand() / (RAND_MAX / (b - a))); + cfgVector vec; + vec.set(cfgValue(value), size); + for (int k = 1; k < size; k++) + { + value = a + (rand() / (RAND_MAX / (b - a))); + vec.change(k, cfgValue(value)); + } + dyn_expr.push(vec); + } + else + { + dyn_expr.push(cfgVector()); + } + } + else + { + printf(" CONFIG:> insufficient number of arguments: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + // --> next iteration + continue; + } + + printf(" CONFIG:> unknown constructor: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + // ----------------------------------------------------- // + + if (Lexeme::is_value(lex_type)) + { + cfgVector vec(cfgValue::make_implicit(lexeme_list.get_token(eidx))); + + if (!vec.is_defined()) + { + printf(" CONFIG:> incorrect constant value: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + dyn_expr.push(vec); + + // --> next iteration + continue; + } + // ----------------------------------------------------- // + + if (lex_type == Lexeme::IS_NAME) + { + if (exe_cntrl) + { + cfgVector arg; + + arg_name_buf.reset(); + arg_name_buf.append(name_space, strlen(name_space)); + arg_name_buf.append('.'); + arg_name_buf.append(lexeme_list.get_token(eidx), strlen(lexeme_list.get_token(eidx))); + arg_name_buf.append('\0'); + + if (is_varname(arg_name_buf.get_ptr())) + arg = get_variable(arg_name_buf.get_ptr()); + else + { + if (is_varname(lexeme_list.get_token(eidx))) + { + arg = get_variable(lexeme_list.get_token(eidx)); + } + else + { + printf(" CONFIG:> reference to undefined variable: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + } + + dyn_expr.push(arg); + } + else + { + dyn_expr.push(cfgVector()); + } + + // --> next iteration + continue; + } + // ----------------------------------------------------- // + + printf(" CONFIG:> unexpected lexeme in expression: '%s' (line, %i)\n", + lexeme_list.get_token(eidx), lexeme_list.get_tag(eidx)); + return false; + } + + return true; +} + +bool scm::ConfigParser::evaluate_rpn( + cfgVector &res, + const mem_buffer<int> &rpn, + const mem_buffer<int> &rpn_key, + const LexemeList &lexeme_list, const char *name_space, + const bool exe_cntrl) const +{ + std::stack<cfgVector> dyn_expr; + + if (!evaluate_rpn(dyn_expr, rpn, rpn_key, + 0, rpn.get_size() - 1, lexeme_list, name_space, exe_cntrl)) + { + res = cfgVector(); + return false; + } + + if (dyn_expr.size() != 1) + { + res = cfgVector(); + printf(" CONFIG:> undefined expression (line, %i)\n", + lexeme_list.get_tag(rpn.get_value(0))); + return false; + } + + res = cfgVector(dyn_expr.top()); // delay res type checking [in add] + return true; +} +// -------------------------------------------------------------------------------------------- // + +bool scm::ConfigParser::set_command( + cfgCommand &command, + const mem_buffer<int> &rpn, + const mem_buffer<int> &rpn_key, + const LexemeList &lexeme_list, + const bool exe_cntrl) const +{ + const int rpn_size = rpn.get_size(); + std::stack<cfgVector> dyn_expr; + + command.reset(); + command.set_name(lexeme_list.get_token(rpn.get_value(rpn_size - 1))); + + if (!evaluate_rpn(dyn_expr, rpn, rpn_key, + 0, rpn_size - 2, lexeme_list, "", exe_cntrl)) + { + printf(" CONFIG:> undefined command arguments '%s' (line, %i)\n", + lexeme_list.get_token(rpn.get_value(rpn_size - 1)), + lexeme_list.get_tag(rpn.get_value(rpn_size - 1))); + return false; + } + + if (dyn_expr.size() != rpn_key.get_value(rpn_size - 1)) + { + printf(" CONFIG:> incorrect number (%i) of command '%s' arguments (line, %i)\n", + dyn_expr.size(), + lexeme_list.get_token(rpn.get_value(rpn_size - 1)), + lexeme_list.get_tag(rpn.get_value(rpn_size - 1))); + return false; + } + + // --- copy arguments in correct order + std::stack<cfgVector> dyn_expr_back; + + while (!dyn_expr.empty()) + { + dyn_expr_back.push(dyn_expr.top()); + dyn_expr.pop(); + } + + cfgVector arg; + while (!dyn_expr_back.empty()) + { + arg = dyn_expr_back.top(); + if (exe_cntrl || (arg.is_defined())) + if (!command.add_arg(arg)) + { + printf(" CONFIG:> undefined command arguments '%s' (line, %i)\n", + lexeme_list.get_token(rpn.get_value(rpn_size - 1)), + lexeme_list.get_tag(rpn.get_value(rpn_size - 1))); + return false; + } + dyn_expr_back.pop(); + } + // ----------------------------------------------------- // + + return true; // delay arg type checking [in add] +} +// -------------------------------------------------------------------------------------------- // + +// * syntax analysis * // +// -------------------------------------------------------------------------------------------- // +bool scm::ConfigParser::parse_syntax( + const LexemeList &lexeme_list, + const bool exe_cntrl, parserCallBack &pcb) +{ + const int nlexeme = lexeme_list.get_size(); + if (nlexeme == 0) + return true; + + parserState state; + if (!parse_block(state, lexeme_list, exe_cntrl, pcb)) + return false; + + if (state.idx < nlexeme) + { + printf(" CONFIG:> unexpected lexeme: '%s' (line, %i)\n", + lexeme_list.get_token(state.idx), lexeme_list.get_tag(state.idx)); + return false; + } + + return true; +} + +bool scm::ConfigParser::parse_block( + parserState &state, + const LexemeList &lexeme_list, + const bool exe_cntrl, parserCallBack &pcb) +{ + const int nlexeme = lexeme_list.get_size(); + + while (state.idx < nlexeme) + { + + if (lexeme_list.get_type(state.idx) == Lexeme::IS_COMMAND) + { + if (!parse_command(state, lexeme_list, exe_cntrl, pcb)) + return false; + continue; + } + if (lexeme_list.get_type(state.idx) == Lexeme::IS_KEY_WHILE) + { + if (!parse_while_statement(state, lexeme_list, exe_cntrl, pcb)) + return false; + continue; + } + if (lexeme_list.get_type(state.idx) == Lexeme::IS_KEY_IF) + { + if (!parse_if_statement(state, lexeme_list, exe_cntrl, pcb)) + return false; + continue; + } + if (lexeme_list.get_type(state.idx) == Lexeme::IS_NAME) + { + + if ((state.idx + 1 < nlexeme) && + (lexeme_list.get_type(state.idx + 1) == Lexeme::IS_BRACE_OPEN)) + { + if (!parse_name_space(state, lexeme_list, exe_cntrl, pcb)) + return false; + continue; + } + + if ((state.idx + 1 < nlexeme) && + (lexeme_list.get_type(state.idx + 1) == Lexeme::IS_ASSIGNMENT)) + { + if (!parse_assignment(state, lexeme_list, exe_cntrl, pcb)) + return false; + continue; + } + + if ((state.idx + 1 < nlexeme) && + (lexeme_list.get_type(state.idx + 1) == Lexeme::IS_BRACKET_OPEN)) + { + if (!parse_address_assignment(state, lexeme_list, exe_cntrl, pcb)) + return false; + continue; + } + + printf(" CONFIG:> expecting '=' or '{' for name: '%s' (line, %i)\n", + lexeme_list.get_token(state.idx), lexeme_list.get_tag(state.idx)); + return false; + } + + break; // unknown lexeme found + } + + return true; +} + +bool scm::ConfigParser::parse_command( + parserState &state, + const LexemeList &lexeme_list, + const bool exe_cntrl, parserCallBack &pcb) +{ + mem_buffer<int> rpn; + mem_buffer<int> rpn_key; + const int nlexeme = lexeme_list.get_size(); + int beg_idx = state.idx; + + if (strcmp(state.name_space, "")) + { + // --- nesting commands in namespaces is not allowed! + printf(" CONFIG:> nested command '%s' found (line, %i)\n", + lexeme_list.get_token(beg_idx), lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- setting pointer to first lexeme in expression + const int expr_begin = state.idx; + int expr_end; + + // --- matching end of expression + state.idx++; + bool is_closed = false; + while ((state.idx < nlexeme) && (!is_closed)) + { + if (lexeme_list.get_type(state.idx) == Lexeme::IS_SEMICOLON) + { + is_closed = true; + expr_end = state.idx - 1; + } + state.idx++; + } + if (!is_closed) + { + printf(" CONFIG:> unclosed command '%s' statement, missing ';' (line, %i)\n", + lexeme_list.get_token(beg_idx), lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- converting to postfix notation + if (!get_rpn(rpn, rpn_key, lexeme_list, expr_begin, expr_end)) + { + printf(" CONFIG:> failed to process command '%s' statement (line, %i)\n", + lexeme_list.get_token(beg_idx), lexeme_list.get_tag(beg_idx)); + return false; + } + if (rpn.get_value(rpn.get_size() - 1) != beg_idx) + { + printf(" CONFIG:> incorrect command '%s' expression (line, %i)\n", + lexeme_list.get_token(beg_idx), lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- evaluating command arguments + cfgCommand command; + if (!set_command(command, rpn, rpn_key, lexeme_list, exe_cntrl)) + { + printf(" CONFIG:> failed to set command '%s' (line, %i)\n", + lexeme_list.get_token(beg_idx), lexeme_list.get_tag(beg_idx)); + return false; + } + + if (!exe_cntrl) + return true; + + // --- calling command + bool status = pcb.call_back(command); + if (!status) + { + printf(" CONFIG:> command '%s' failed -- stop (line, %i)\n", + lexeme_list.get_token(beg_idx), lexeme_list.get_tag(beg_idx)); + } + return status; +} + +bool scm::ConfigParser::parse_name_space( + parserState &state, + const LexemeList &lexeme_list, + const bool exe_cntrl, parserCallBack &pcb) +{ + const int nlexeme = lexeme_list.get_size(); + int beg_idx = state.idx; + + // --- no dots allowed in namespace name at least for now + if (strchr(lexeme_list.get_token(state.idx), '.') != NULL) + { + printf(" CONFIG:> '.' not allowed in namespaces: '%s' (line, %i)\n", + lexeme_list.get_token(beg_idx), lexeme_list.get_tag(beg_idx)); + return false; + } + + state.append_name_space(lexeme_list.get_token(state.idx)); + state.idx += 2; + + if (!parse_block(state, lexeme_list, exe_cntrl, pcb)) + return false; + + // --- closing namespace [}] + if ((state.idx < nlexeme) && (lexeme_list.get_type(state.idx) == Lexeme::IS_BRACE_CLOSE)) + { + state.truncate_name_space(); + state.idx++; + return true; + } + + // --- unclosed namespace [}] + printf(" CONFIG:> unclosed namespace '%s', missing '}' (line, %i)\n", + lexeme_list.get_token(beg_idx), lexeme_list.get_tag(beg_idx)); + return false; +} + +bool scm::ConfigParser::parse_assignment( + parserState &state, + const LexemeList &lexeme_list, + const bool exe_cntrl, parserCallBack &pcb) +{ + mem_buffer<int> rpn; + mem_buffer<int> rpn_key; + const int nlexeme = lexeme_list.get_size(); + int beg_idx = state.idx; + const char *global_varname = state.get_global_name(lexeme_list.get_token(beg_idx)); + + // --- setting state at expression: NAME = EXPRESSION; + state.idx += 2; + + // --- setting pointer to first lexeme in expression + const int expr_begin = state.idx; + int expr_end; + + // --- matching end of expression + bool is_closed = false; + while ((state.idx < nlexeme) && (!is_closed)) + { + if (lexeme_list.get_type(state.idx) == Lexeme::IS_SEMICOLON) + { + is_closed = true; + expr_end = state.idx - 1; + } + + state.idx++; + } + if (!is_closed) + { + printf(" CONFIG:> unclosed assignment statement '%s = ', missing ';' (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- converting to postfix notation + if (!get_rpn(rpn, rpn_key, lexeme_list, expr_begin, expr_end)) + { + printf(" CONFIG:> failed to process expression for variable: '%s' (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- evaluating postfix expression (need namespace - not full variable name) + cfgVector value; + if (!evaluate_rpn(value, rpn, rpn_key, lexeme_list, state.name_space, exe_cntrl)) + { + printf(" CONFIG:> failed to evaluate expression for variable: '%s' (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + if ((exe_cntrl) && (!value.is_defined())) + { + printf(" CONFIG:> failed to evaluate expression for variable: '%s' (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- setting variable name + value.set_name(global_varname); + if (value.is_name_empty()) + { + printf(" CONFIG:> invalid variable name: '%s' (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- adding variable + if (exe_cntrl) + add_unsafe(value); + return true; +} + +bool scm::ConfigParser::parse_address_assignment( + parserState &state, + const LexemeList &lexeme_list, + const bool exe_cntrl, parserCallBack &pcb) +{ + mem_buffer<int> rpn; + mem_buffer<int> rpn_key; + const int nlexeme = lexeme_list.get_size(); + int beg_idx = state.idx; + const char *global_varname = state.get_global_name(lexeme_list.get_token(beg_idx)); + + // --- setting state at index: NAME[INDEX] = EXPRESSION; + state.idx += 2; + + // --- setting pointer to last lexeme in index + const int index_begin = state.idx; + int index_end; + + // --- matching end of index + bool is_closed = false; + while ((state.idx < nlexeme) && (!is_closed)) + { + if ((lexeme_list.get_type(state.idx) == Lexeme::IS_ASSIGNMENT) && + (lexeme_list.get_type(state.idx - 1) == Lexeme::IS_BRACKET_CLOSE)) + { + is_closed = true; + index_end = state.idx - 2; + } + + state.idx++; + } + if (!is_closed) + { + printf(" CONFIG:> unclosed index operator '%s[] = ', missing ']' (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + if (index_end < index_begin) + { + printf(" CONFIG:> no arguments in index operator '%s[] = ' (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- converting to postfix notation + if (!get_rpn(rpn, rpn_key, lexeme_list, index_begin, index_end)) + { + printf(" CONFIG:> failed to process expression for index of variable: '%s' (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- evaluating postfix expression (need namespace - not full variable name) + cfgVector vec_index; + if (!evaluate_rpn(vec_index, rpn, rpn_key, lexeme_list, state.name_space, exe_cntrl)) + { + printf(" CONFIG:> failed to evaluate index of variable: '%s' (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + + int index = 0; + if ((exe_cntrl | (vec_index.is_defined())) && (!vec_index.get_if_single(&index))) + { + printf(" CONFIG:> incorrect argument for index of variable: '%s' (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- setting pointer to first lexeme in expression + const int expr_begin = state.idx; + int expr_end; + + // --- matching end of expression + is_closed = false; + while ((state.idx < nlexeme) && (!is_closed)) + { + if (lexeme_list.get_type(state.idx) == Lexeme::IS_SEMICOLON) + { + is_closed = true; + expr_end = state.idx - 1; + } + + state.idx++; + } + if (!is_closed) + { + printf(" CONFIG:> unclosed assignment statement '%s = ', missing ';' (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- converting to postfix notation + if (!get_rpn(rpn, rpn_key, lexeme_list, expr_begin, expr_end)) + { + printf(" CONFIG:> failed to process expression for variable: '%s' (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- evaluating postfix expression (need namespace - not full variable name) + cfgVector value; + if (!evaluate_rpn(value, rpn, rpn_key, lexeme_list, state.name_space, exe_cntrl)) + { + printf(" CONFIG:> failed to evaluate expression for variable: '%s' (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + if ((exe_cntrl) && (!value.is_defined())) + { + printf(" CONFIG:> failed to evaluate expression for variable: '%s' (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + if ((exe_cntrl || (value.is_defined())) && (!value.is_single())) + { + printf(" CONFIG:> incorrect expression for variable: '%s' (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- setting variable name + value.set_name(global_varname); + if (value.is_name_empty()) + { + printf(" CONFIG:> invalid variable name: '%s' (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + + if (!exe_cntrl) + return true; + + // --- adding value only if vector is already allocated + for (int k = 0; k < nvars; k++) + { + if (var[k].is_name_eq(value)) + { + if ((index < 0) || (index >= var[k].get_size())) + { + printf(" CONFIG:> out of range index (%i) for vector(%i): '%s' (line, %i)\n", + index, var[k].get_size(), global_varname, lexeme_list.get_tag(beg_idx)); + return false; + } + + var[k].change(index, value.get(0)); + return true; + } + } + + printf(" CONFIG:> variable '%s' doesn't exist (line, %i)\n", + global_varname, lexeme_list.get_tag(beg_idx)); + return false; +} + +bool scm::ConfigParser::parse_if_statement( + parserState &state, + const LexemeList &lexeme_list, + const bool exe_cntrl, + parserCallBack &pcb) +{ + mem_buffer<int> rpn; + mem_buffer<int> rpn_key; + const int nlexeme = lexeme_list.get_size(); + int beg_idx = state.idx; + + // --- setting state at expression: IF EXPRESSION THEN ... + state.idx++; + + // --- setting pointer to first lexeme in expression + const int expr_begin = state.idx; + int expr_end; + + // --- matching end of expression + bool is_closed = false; + while ((state.idx < nlexeme) && (!is_closed)) + { + if (lexeme_list.get_type(state.idx) == Lexeme::IS_KEY_THEN) + { + is_closed = true; + expr_end = state.idx - 1; + } + state.idx++; + } + if (!is_closed) + { + printf(" CONFIG:> unclosed 'if' statement, missing 'then' (line, %i)\n", + lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- converting to postfix notation + if (!get_rpn(rpn, rpn_key, lexeme_list, expr_begin, expr_end)) + { + printf(" CONFIG:> failed to process 'if' statement expression (line, %i)\n", + lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- evaluating postfix expression + cfgVector value; + if (!evaluate_rpn(value, rpn, rpn_key, lexeme_list, state.name_space, exe_cntrl)) + { + printf(" CONFIG:> failed to evaluate 'if' statement expression, expecting bool value (line, %i)\n", + lexeme_list.get_tag(beg_idx)); + return false; + } + + bool if_cntrl = false; + if (exe_cntrl || (value.is_defined())) + { + if (!value.get_if_single(&if_cntrl)) + { + printf(" CONFIG:> failed to evaluate 'if' statement expression, expecting bool value (line, %i)\n", + lexeme_list.get_tag(beg_idx)); + return false; + } + } + + if (!parse_block(state, lexeme_list, (exe_cntrl && if_cntrl), pcb)) + return false; + + // --- processing 'else' case + if ((state.idx < nlexeme) && + (lexeme_list.get_type(state.idx) == Lexeme::IS_KEY_ELSE)) + { + state.idx++; + if (!parse_block(state, lexeme_list, (exe_cntrl && (!if_cntrl)), pcb)) + return false; + } + + if ((state.idx < nlexeme) && + (lexeme_list.get_type(state.idx) == Lexeme::IS_KEY_ENDIF)) + { + state.idx++; + return true; + } + + printf(" CONFIG:> unclosed 'if' statement, missing 'endif' (line, %i)\n", + lexeme_list.get_tag(beg_idx)); + return false; +} + +bool scm::ConfigParser::parse_while_statement( + parserState &state, + const LexemeList &lexeme_list, + const bool exe_cntrl, parserCallBack &pcb) +{ + const int c_max_iters = INT_MAX; // max iters to handle infinite cycles + + mem_buffer<int> rpn; + mem_buffer<int> rpn_key; + const int nlexeme = lexeme_list.get_size(); + int beg_idx = state.idx; + + // --- setting state at expression: WHILE EXPRESSION DO ... + state.idx++; + + // --- setting pointer to first lexeme in expression + const int expr_begin = state.idx; + int expr_end; + + // --- matching end of expression + bool is_closed = false; + while ((state.idx < nlexeme) && (!is_closed)) + { + if (lexeme_list.get_type(state.idx) == Lexeme::IS_KEY_DO) + { + is_closed = true; + expr_end = state.idx - 1; + } + state.idx++; + } + if (!is_closed) + { + printf(" CONFIG:> unclosed 'while' statement, missing 'do' (line, %i)\n", + lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- evaluating while condition + bool while_cntrl; + + // converting to postfix notation + if (!get_rpn(rpn, rpn_key, lexeme_list, expr_begin, expr_end)) + { + printf(" CONFIG:> failed to process 'while' statement expression (line, %i)\n", + lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- evaluating postfix expression + cfgVector value; + if (!evaluate_rpn(value, rpn, rpn_key, lexeme_list, state.name_space, exe_cntrl)) + { + printf(" CONFIG:> failed to evaluate 'while' statement expression, expecting bool value (line, %i)\n", + lexeme_list.get_tag(beg_idx)); + return false; + } + + while_cntrl = false; + if (exe_cntrl || (value.is_defined())) + { + if (!value.get_if_single(&while_cntrl)) + { + printf(" CONFIG:> failed to evaluate 'while' statement expression, expecting bool value (line, %i)\n", + lexeme_list.get_tag(beg_idx)); + return false; + } + } + + // --- pointer to do code beginning + const int do_beg_idx = state.idx; + // --- iterations counter + int iters = 0; + + while ( + (exe_cntrl && while_cntrl) || + (iters == 0)) // --- parsing at least iteration to check syntax and move state + { + // --- resetting state + state.idx = do_beg_idx; + + if (!parse_block(state, lexeme_list, (exe_cntrl && while_cntrl), pcb)) + return false; + + // --- checking 'while' statement closure + if ((state.idx < nlexeme) && + (lexeme_list.get_type(state.idx) == Lexeme::IS_KEY_ENDDO)) + { + state.idx++; + + // --- in case just checking syntax + if ((!exe_cntrl) || (!while_cntrl)) + break; + + // --- checking if infinite loop + iters++; + if (iters == c_max_iters) + { + printf(" CONFIG:> max allowed iterations ( = %i) reached for 'while' statement, aborting (line, %i)\n", + c_max_iters, lexeme_list.get_tag(beg_idx)); + return false; + } + + // --- evaluating while condition + + // --- evaluating postfix expression + cfgVector value; + if (!evaluate_rpn(value, rpn, rpn_key, lexeme_list, state.name_space, exe_cntrl)) + { + printf(" CONFIG:> failed to evaluate 'while' statement expression, expecting bool value (line, %i)\n", + lexeme_list.get_tag(beg_idx)); + return false; + } + + if (!value.get_if_single(&while_cntrl)) + { + printf(" CONFIG:> failed to evaluate 'while' statement expression, expecting bool value (line, %i)\n", + lexeme_list.get_tag(beg_idx)); + return false; + } + } + else + { + printf(" CONFIG:> unclosed 'while' statement, missing 'enddo' (line, %i)\n", + lexeme_list.get_tag(beg_idx)); + return false; + } + } + + return true; +} +// -------------------------------------------------------------------------------------------- // + +bool scm::ConfigParser::add(const cfgVector &ex) +{ + if (!ex.is_defined()) + return false; + if (!is_valid_name(ex.get_name())) + return false; + + return add_unsafe(ex); +} + +bool scm::ConfigParser::is_valid_name(const char *name) const +{ + int token_length = (int)strlen(name); + + if (token_length == 0) + return false; + if ((!isalpha(name[0])) && (name[0] != '_')) + return false; + + for (int i = 1; i < token_length; i++) + { + if ((!isalnum(name[i])) && + (name[i] != '_') && (name[i] != '.')) + return false; + } + if (name[token_length - 1] == '.') + return false; + + return true; +} + +bool scm::ConfigParser::add_unsafe(const cfgVector &ex) +{ + // --- just overwriting variable if already exists + for (int k = 0; k < nvars; k++) + { + if (var[k].is_name_eq(ex)) + { + var[k] = ex; + return true; + } + } + + if (nvars >= nalloc_vars) + { + cfgVector *hvar = new cfgVector[nalloc_vars + c_alloc_vars_init]; + for (int i = 0; i < nalloc_vars; i++) + { + hvar[i] = var[i]; + } + + delete[] var; + var = hvar; + + nalloc_vars += c_alloc_vars_init; + } + + var[nvars] = ex; + nvars++; + return true; +} +// -------------------------------------------------------------------------------------------- // + +int scm::ConfigParser::operator_priority( + const Lexeme::TYPE type) +{ + if ((type == Lexeme::IS_OP_LOGICAL_AND) || (type == Lexeme::IS_OP_LOGICAL_OR)) + return 1; + if ((type == Lexeme::IS_OP_EQ) || (type == Lexeme::IS_OP_NEQ)) + return 2; + if ((type == Lexeme::IS_OP_LT) || (type == Lexeme::IS_OP_GT) || + (type == Lexeme::IS_OP_LEQ) || (type == Lexeme::IS_OP_GEQ)) + return 3; + if ((type == Lexeme::IS_OP_ADD) || (type == Lexeme::IS_OP_SUB)) + return 4; + if ((type == Lexeme::IS_OP_MUL) || (type == Lexeme::IS_OP_DIV) || + (type == Lexeme::IS_OP_MOD)) + return 5; + if ((type == Lexeme::IS_OP_PLUS) || (type == Lexeme::IS_OP_MINUS)) + return 6; + if ((type == Lexeme::IS_OP_EXP)) + return 7; + + return 0; +} + +bool scm::ConfigParser::operator_priority_lt( + const Lexeme::TYPE typeA, const Lexeme::TYPE typeB) +{ + return (operator_priority(typeA) < operator_priority(typeB)); +} + +bool scm::ConfigParser::is_operator_binary(const Lexeme::TYPE type) +{ + return ( + (type == Lexeme::IS_OP_ADD) || (type == Lexeme::IS_OP_SUB) || + (type == Lexeme::IS_OP_MUL) || (type == Lexeme::IS_OP_DIV) || + (type == Lexeme::IS_OP_MOD) || + (type == Lexeme::IS_OP_EXP) || + (type == Lexeme::IS_OP_EQ) || (type == Lexeme::IS_OP_NEQ) || + (type == Lexeme::IS_OP_LOGICAL_AND) || (type == Lexeme::IS_OP_LOGICAL_OR) || + (type == Lexeme::IS_OP_LT) || (type == Lexeme::IS_OP_GT) || + (type == Lexeme::IS_OP_LEQ) || (type == Lexeme::IS_OP_GEQ)); +} + +bool scm::ConfigParser::is_operator_unary(const Lexeme::TYPE type) +{ + return ((type == Lexeme::IS_OP_PLUS) || (type == Lexeme::IS_OP_MINUS)); +} + +bool scm::ConfigParser::is_operator_assoc_right(const Lexeme::TYPE type) +{ + return ((type == Lexeme::IS_OP_EXP) || + (type == Lexeme::IS_OP_PLUS) || (type == Lexeme::IS_OP_MINUS)); +} + +bool scm::ConfigParser::is_operator_assoc_left(const Lexeme::TYPE type) +{ + return ( + (type == Lexeme::IS_OP_ADD) || (type == Lexeme::IS_OP_SUB) || + (type == Lexeme::IS_OP_MUL) || (type == Lexeme::IS_OP_DIV) || + (type == Lexeme::IS_OP_MOD) || + (type == Lexeme::IS_OP_EQ) || (type == Lexeme::IS_OP_NEQ) || + (type == Lexeme::IS_OP_LOGICAL_AND) || (type == Lexeme::IS_OP_LOGICAL_OR) || + (type == Lexeme::IS_OP_LT) || (type == Lexeme::IS_OP_GT) || + (type == Lexeme::IS_OP_LEQ) || (type == Lexeme::IS_OP_GEQ)); +} + +int scm::ConfigParser::function_nargs(const Lexeme::TYPE type) +{ + if ((type == Lexeme::IS_MIN_FUNCTION) || (type == Lexeme::IS_MAX_FUNCTION) || + (type == Lexeme::IS_DOT_PRODUCT_FUNCTION) || + (type == Lexeme::IS_UNIRAND_FUNCTION)) + return 2; + if ((type == Lexeme::IS_VECMIN_FUNCTION) || (type == Lexeme::IS_VECMAX_FUNCTION) || + (type == Lexeme::IS_SIN_FUNCTION) || (type == Lexeme::IS_COS_FUNCTION) || + (type == Lexeme::IS_TAN_FUNCTION) || + (type == Lexeme::IS_LOG_FUNCTION) || + (type == Lexeme::IS_SQRT_FUNCTION) || + (type == Lexeme::IS_ABS_FUNCTION) || + (type == Lexeme::IS_L2NORM_FUNCTION) || (type == Lexeme::IS_CNORM_FUNCTION) || + (type == Lexeme::IS_TO_STRING_FUNCTION) || + (type == Lexeme::IS_SIZE_FUNCTION) || + (type == Lexeme::IS_DEFINED_FUNCTION)) + return 1; + + return 0; +} +// -------------------------------------------------------------------------------------------- // + +// * get & check calls * // +// -------------------------------------------------------------------------------------------- // +bool scm::ConfigParser::is_varname(const char *name) const +{ + for (int i = 0; i < nvars; i++) + if (var[i].is_name_eq(name)) + return true; + + return false; +} + +const scm::cfgVector +scm::ConfigParser::get_variable(const int idx) const +{ + if ((idx < 0) || (idx >= nvars)) + return cfgVector(); + + return var[idx]; +} + +const scm::cfgVector +scm::ConfigParser::get_variable(const char *name) const +{ + for (int k = 0; k < nvars; k++) + { + if (var[k].is_name_eq(name)) + return var[k]; + } + + return cfgVector(); +} + +void scm::ConfigParser::print() const +{ + for (int i = 0; i < nvars; i++) + { + var[i].print(); + getc(stdin); + } +} + +bool scm::ConfigParser::get_value(const char *name, int *value) const +{ + cfgVector vec = get_variable(name); + if (vec.get_size() > 1) + { + printf(" CONFIG:> failed to set (int) variable: '%s' -- vector (size > 1)\n", name); + return false; + } + + cfgValue var = vec.get(0); + cfgValue::VAR_TYPE type = var.get_type(); + + if (type == cfgValue::IS_INT) + return var.get(value); + else if (type == cfgValue::IS_DOUBLE) + { + printf(" CONFIG:> failed to set (int) variable: '%s' - declared as double\n", + name); + return false; + } + else if (type == cfgValue::IS_STRING) + { + printf(" CONFIG:> failed to set (int) variable: '%s' - declared as string\n", + name); + return false; + } + else if (type == cfgValue::IS_BOOLEAN) + { + printf(" CONFIG:> failed to set (int) variable: '%s' - declared as boolean\n", + name); + return false; + } + + printf(" CONFIG:> failed to set (int) variable: '%s'\n", name); + return false; +} + +bool scm::ConfigParser::get_value(const char *name, float *value) const +{ + cfgVector vec = get_variable(name); + if (vec.get_size() > 1) + { + printf(" CONFIG:> failed to set (float) variable: '%s' -- vector (size > 1)\n", name); + return false; + } + + cfgValue var = vec.get(0); + cfgValue::VAR_TYPE type = var.get_type(); + + if (type == cfgValue::IS_INT) + return var.get(value); + else if (type == cfgValue::IS_DOUBLE) + return var.get(value); + else if (type == cfgValue::IS_STRING) + { + printf(" CONFIG:> failed to set (float) variable: '%s' - declared as string\n", + name); + return false; + } + else if (type == cfgValue::IS_BOOLEAN) + { + printf(" CONFIG:> failed to set (float) variable: '%s' - declared as boolean\n", + name); + return false; + } + + printf(" CONFIG:> failed to set (float) variable: '%s' - undefined\n", + name); + return false; +} + +bool scm::ConfigParser::get_value(const char *name, double *value) const +{ + cfgVector vec = get_variable(name); + if (vec.get_size() > 1) + { + printf(" CONFIG:> failed to set (double) variable: '%s' -- vector (size > 1)\n", name); + return false; + } + + cfgValue var = vec.get(0); + cfgValue::VAR_TYPE type = var.get_type(); + + if (type == cfgValue::IS_INT) + return var.get(value); + else if (type == cfgValue::IS_DOUBLE) + return var.get(value); + else if (type == cfgValue::IS_STRING) + { + printf(" CONFIG:> failed to set (double) variable: '%s' - declared as string\n", + name); + return false; + } + else if (type == cfgValue::IS_BOOLEAN) + { + printf(" CONFIG:> failed to set (double) variable: '%s' - declared as boolean\n", + name); + return false; + } + + printf(" CONFIG:> failed to set (double) variable: '%s' - undefined\n", + name); + return false; +} + +bool scm::ConfigParser::get_value(const char *name, long double *value) const +{ + cfgVector vec = get_variable(name); + if (vec.get_size() > 1) + { + printf(" CONFIG:> failed to set (double) variable: '%s' -- vector (size > 1)\n", name); + return false; + } + + cfgValue var = vec.get(0); + cfgValue::VAR_TYPE type = var.get_type(); + + if (type == cfgValue::IS_INT) + var.get(value); + else if (type == cfgValue::IS_DOUBLE) + var.get(value); + else if (type == cfgValue::IS_STRING) + { + printf(" CONFIG:> failed to set (double) variable: '%s' - declared as string\n", + name); + return false; + } + else if (type == cfgValue::IS_BOOLEAN) + { + printf(" CONFIG:> failed to set (double) variable: '%s' - declared as boolean\n", + name); + return false; + } + + printf(" CONFIG:> failed to set (double) variable: '%s' - undefined\n", + name); + return false; +} + +bool scm::ConfigParser::get_value(const char *name, char **value) const +{ + cfgVector vec = get_variable(name); + if (vec.get_size() > 1) + { + printf(" CONFIG:> failed to set (string) variable: '%s' -- vector (size > 1)\n", name); + return false; + } + + cfgValue var = vec.get(0); + cfgValue::VAR_TYPE type = var.get_type(); + + if (type == cfgValue::IS_INT) + { + printf(" CONFIG:> failed to set (string) variable: '%s' - declared as int\n", + name); + return false; + } + else if (type == cfgValue::IS_DOUBLE) + { + printf(" CONFIG:> failed to set (string) variable: '%s' - declared as double\n", + name); + return false; + } + else if (type == cfgValue::IS_STRING) + return var.get(value); + else if (type == cfgValue::IS_BOOLEAN) + { + printf(" CONFIG:> failed to set (string) variable: '%s' - declared as boolean\n", + name); + return false; + } + + printf(" CONFIG:> failed to set (string) variable: '%s' - undefined\n", + name); + return false; +} + +bool scm::ConfigParser::get_value(const char *name, std::string &value) const +{ + cfgVector vec = get_variable(name); + if (vec.get_size() > 1) + { + printf(" CONFIG:> failed to set (string) variable: '%s' -- vector (size > 1)\n", name); + return false; + } + + cfgValue var = vec.get(0); + cfgValue::VAR_TYPE type = var.get_type(); + + if (type == cfgValue::IS_INT) + { + printf(" CONFIG:> failed to set (string) variable: '%s' - declared as int\n", + name); + return false; + } + else if (type == cfgValue::IS_DOUBLE) + { + printf(" CONFIG:> failed to set (string) variable: '%s' - declared as double\n", + name); + return false; + } + else if (type == cfgValue::IS_STRING) + return var.get(value); + else if (type == cfgValue::IS_BOOLEAN) + { + printf(" CONFIG:> failed to set (string) variable: '%s' - declared as boolean\n", + name); + return false; + } + + printf(" CONFIG:> failed to set (string) variable: '%s' - undefined\n", + name); + return false; +} + +bool scm::ConfigParser::get_value(const char *name, bool *value) const +{ + cfgVector vec = get_variable(name); + if (vec.get_size() > 1) + { + printf(" CONFIG:> failed to set (bool) variable: '%s' -- vector (size > 1)\n", name); + return false; + } + + cfgValue var = vec.get(0); + cfgValue::VAR_TYPE type = var.get_type(); + + if (type == cfgValue::IS_INT) + { + printf(" CONFIG:> failed to set (bool) variable: '%s' - declared as int\n", + name); + return false; + } + else if (type == cfgValue::IS_DOUBLE) + { + printf(" CONFIG:> failed to set (bool) variable: '%s' - declared as double\n", + name); + return false; + } + else if (type == cfgValue::IS_STRING) + { + printf(" CONFIG:> failed to set (bool) variable: '%s' - declared as string\n", + name); + return false; + } + else if (type == cfgValue::IS_BOOLEAN) + return var.get(value); + + printf(" CONFIG:> failed to set (bool) variable: '%s'\n", name); + return false; +} +// -------------------------------------------------------------------------------------------- // diff --git a/parser/config-parser.h b/parser/config-parser.h new file mode 100644 index 0000000..7ae3494 --- /dev/null +++ b/parser/config-parser.h @@ -0,0 +1,191 @@ +#pragma once + +// [config-parser.h]: configuration file parser +// +// -------------------------------------------------------------------------------------------- // + +#include "cfg-value.h" +#include "cfg-cmd.h" +#include "cfg-vec.h" + +#include "lexeme-list.h" +#include "mem-buffer.h" + +#include <stack> + +namespace scm +{ + // call back default + // -------------------------------------------------------------------------------------------- // + class parserCallBack { + public: + + virtual bool call_back(const cfgCommand& cmd) { return true; } + + parserCallBack() {} + virtual ~parserCallBack() {} + }; + // -------------------------------------------------------------------------------------------- // + + class ConfigParser { + public: + + // -------------------------------------------------------------------------------------------- // + ConfigParser(); + ~ConfigParser(); + // -------------------------------------------------------------------------------------------- // + + // run + // -------------------------------------------------------------------------------------------- // + bool run(const char* filename); + bool run(const char* filename, parserCallBack& pcb); + // -------------------------------------------------------------------------------------------- // + + // get & check calls + // -------------------------------------------------------------------------------------------- // + bool is_varname(const char* name) const; + const cfgVector get_variable(const int idx) const; + const cfgVector get_variable(const char* name) const; + + bool get_value(const char* name, int* value) const; + bool get_value(const char* name, float* value) const; + bool get_value(const char* name, double* value) const; + bool get_value(const char* name, long double* value) const; + + bool get_value(const char* name, char** value) const; + bool get_value(const char* name, std::string& value) const; + + bool get_value(const char* name, bool* value) const; + // -------------------------------------------------------------------------------------------- // + + // adding variable + // -------------------------------------------------------------------------------------------- // + bool add(const cfgVector& rvalue); + + bool is_valid_name(const char* name) const; + // -------------------------------------------------------------------------------------------- // + + // print + // -------------------------------------------------------------------------------------------- // + void print() const; + // -------------------------------------------------------------------------------------------- // + + private: + // datatypes + // -------------------------------------------------------------------------------------------- // + + // --- helper struct to control parsing state + // -------------------------------------------------------------------------------------------- // + struct parserState { + + parserState(); + parserState(const parserState& state); + ~parserState(); + + void truncate_name_space(); + void append_name_space(const char* name); + + const char* get_global_name(const char* varname); + + int idx; // lexeme index + char *name_space; // current namespace + + private: // allocation data + int nalloc; + static const int c_alloc_init = 64; + + char *name_buf; + int name_buf_nalloc; + }; + // -------------------------------------------------------------------------------------------- // + + private: + // processing (private) + // -------------------------------------------------------------------------------------------- // + + // --- expression rpn evaluation + bool get_rpn( + mem_buffer<int>& rpn, + mem_buffer<int>& rpn_key, + const LexemeList& lexeme_list, + const int lex_beg, const int lex_end) const; + + bool evaluate_rpn( + std::stack<cfgVector>& dyn_expr, + const mem_buffer< int >& rpn, + const mem_buffer<int>& rpn_key, + const int rpn_beg, const int rpn_end, + const LexemeList& lexeme_list, + const char* name_space, + const bool exe_cntrl) const; + bool evaluate_rpn( + cfgVector& res, + const mem_buffer< int >& rpn, + const mem_buffer<int>& rpn_key, + const LexemeList& lexeme_list, + const char* name_space, + const bool exe_cntrl) const; + // -------------------------------------------------------------------------------------------- // + + // --- command setup + bool set_command( + cfgCommand& cmd, + const mem_buffer< int >& rpn, + const mem_buffer< int >& fun_narg, + const LexemeList& lexeme_list, + const bool exe_cntrl) const; + // -------------------------------------------------------------------------------------------- // + + // --- syntax analysis + bool parse_syntax(const LexemeList& lexeme_list, const bool exe_cntrl, parserCallBack& pcb); + + bool parse_block( + parserState& state, const LexemeList& lexeme_list, const bool exe_cntrl, parserCallBack& pcb); + bool parse_command( + parserState& state, const LexemeList& lexeme_list, const bool exe_cntrl, parserCallBack& pcb); + bool parse_if_statement( + parserState& state, const LexemeList& lexeme_list, const bool exe_cntrl, parserCallBack& pcb); + bool parse_while_statement( + parserState& state, const LexemeList& lexeme_list, const bool exe_cntrl, parserCallBack& pcb); + bool parse_name_space( + parserState& state, const LexemeList& lexeme_list, const bool exe_cntrl, parserCallBack& pcb); + bool parse_assignment( + parserState& state, const LexemeList& lexeme_list, const bool exe_cntrl, parserCallBack& pcb); + bool parse_address_assignment( + parserState& state, const LexemeList& lexeme_list, const bool exe_cntrl, parserCallBack& pcb); + // -------------------------------------------------------------------------------------------- // + + // --- add variable (no additional checks) + bool add_unsafe(const cfgVector& rvalue); + // -------------------------------------------------------------------------------------------- // + + private: + // static (private) + // -------------------------------------------------------------------------------------------- // + + // +,- [priority=1, assoc.=left] + // *,/,% [priority=2, assoc.=left] + // +,- [priority=3, assoc.=right] + // ^ [priority=4, assoc.=right] + static int operator_priority(const Lexeme::TYPE type); + static bool operator_priority_lt( + const Lexeme::TYPE typeA, const Lexeme::TYPE typeB); + + static int function_nargs(const Lexeme::TYPE type); + + static bool is_operator_binary(const Lexeme::TYPE type); + static bool is_operator_unary(const Lexeme::TYPE type); + static bool is_operator_assoc_left(const Lexeme::TYPE type); + static bool is_operator_assoc_right(const Lexeme::TYPE type); + + private: + // data (private) + // -------------------------------------------------------------------------------------------- // + + int nvars; + int nalloc_vars; + static const int c_alloc_vars_init = 64; + cfgVector *var; + }; + // -------------------------------------------------------------------------------------------- // +} diff --git a/parser/io-guts.cpp b/parser/io-guts.cpp new file mode 100644 index 0000000..d85ca8b --- /dev/null +++ b/parser/io-guts.cpp @@ -0,0 +1,152 @@ + +// [io-guts.cpp] +// -------------------------------------------------------------------------------------------- // +// input/output tech subroutines +// -------------------------------------------------------------------------------------------- // + +#define _CRT_SECURE_NO_DEPRECATE +#include "io-guts.h" + +#include <stdio.h> +#include <string.h> +#include <sstream> + +// --- including for directory operations +#ifdef _WIN32 +#include <direct.h> +#else +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#endif +#include <errno.h> + + +// -------------------------------------------------------------------------------------------- // +// * Implementation * +// -------------------------------------------------------------------------------------------- // + +// * append index * // +// -------------------------------------------------------------------------------------------- // +const std::string scm::append_index( + const std::string& name, const int index) +{ + std::ostringstream sidx; + sidx << index; + + const int ext_pos = name.find_last_of("."); + std::string app_name = name; + if (ext_pos == std::string::npos) + app_name.append(sidx.str()); + else + app_name.insert(ext_pos, sidx.str()); + + return app_name; +} +// -------------------------------------------------------------------------------------------- // + +// * create dir * // +// -------------------------------------------------------------------------------------------- // +bool scm::create_dir(const std::string& path) +{ + // empty path is OK [local DIR] + if (path.empty()) return true; + + char *c_path; + c_path = new char[path.length() + 1]; + strcpy(c_path, path.c_str()); + + int status; + char *ptr = c_path + 1; // not empty string + while (*ptr != '\0') + { + if (*ptr == '/') + { + *ptr = '\0'; +#ifdef _WIN32 + status = _mkdir(c_path); +#else + status = mkdir(c_path, S_IRWXU); // add group?: S_IRWXG +#endif + if (!((status == 0) || + ((status == -1) && (errno == EEXIST)))) + { + delete[] c_path; + return false; + } + + *ptr = '/'; + } + ptr++; + } + + +#ifdef _WIN32 + status = _mkdir(c_path); +#else + status = mkdir(c_path, S_IRWXU); // add group?: S_IRWXG +#endif + + delete[] c_path; + + return ((status == 0) || + ((status == -1) && (errno == EEXIST))); +} +// -------------------------------------------------------------------------------------------- // + +// * getline * // +// -------------------------------------------------------------------------------------------- // +char* scm::getline(char** buf, int* size, FILE* ptr) +{ + const int c_min_size = 512; + + if (*size < c_min_size) { + if (*size > 0) delete[](*buf); + + *size = c_min_size; + *buf = new char[*size]; + } + + if (fgets(&(*buf)[0], *size, ptr) == NULL) return NULL; + int bidx = strlen(*buf); + + while (!feof(ptr) && ((*buf)[bidx - 1] != '\n')) + { + // --- reading more ... + + // --- allocating additional memory + *size += c_min_size; + char *hbuf = new char[*size]; + strcpy(hbuf, *buf); + + // --- pointing buf to new memory + delete[](*buf); + *buf = hbuf; + + // --- reading & removing termination character + if (fgets(&(*buf)[bidx], *size - bidx, ptr) == NULL) { + if (!feof(ptr)) return NULL; + } + bidx = strlen(*buf); + } + + return *buf; +} +// -------------------------------------------------------------------------------------------- // + +// * convert to string * // +// -------------------------------------------------------------------------------------------- // +std::string scm::convert_to_string(const int value) +{ + std::ostringstream stream; + stream << value; + return stream.str(); +} + +std::string scm::convert_to_string(const double value) +{ + std::ostringstream stream; + stream << value; + return stream.str(); +} +// -------------------------------------------------------------------------------------------- // diff --git a/parser/io-guts.h b/parser/io-guts.h new file mode 100644 index 0000000..7075f43 --- /dev/null +++ b/parser/io-guts.h @@ -0,0 +1,39 @@ +#pragma once + +// [io-guts.h] +// -------------------------------------------------------------------------------------------- // +// input/output tech subroutines +// -------------------------------------------------------------------------------------------- // + +#include <string> + + + +namespace scm +{ + // append index to string before last '.' + // -------------------------------------------------------------------------------------------- // + const std::string append_index(const std::string& name, const int index); + // -------------------------------------------------------------------------------------------- // + + // create all directories in path + // --- returns <true> on create and if exists + // -------------------------------------------------------------------------------------------- // + bool create_dir(const std::string& path); + // -------------------------------------------------------------------------------------------- // + + + // fgets() for arbitrary line length + // --- <buf> - pointer to buffer memory (input/output) + // --- <size> - buffer memory size (input/output) + // -------------------------------------------------------------------------------------------- // + char* getline(char** buf, int* size, FILE* ptr); + // -------------------------------------------------------------------------------------------- // + + // convert int to string + // *: implemented due to problems with std::to_string on some gcc compilers + // -------------------------------------------------------------------------------------------- // + std::string convert_to_string(const int value); + std::string convert_to_string(const double value); + // -------------------------------------------------------------------------------------------- // +} diff --git a/parser/lexeme-list.cpp b/parser/lexeme-list.cpp new file mode 100644 index 0000000..76d1312 --- /dev/null +++ b/parser/lexeme-list.cpp @@ -0,0 +1,159 @@ +#include "lexeme-list.h" + +#include <string.h> + +#include "scm-mem.h" + +// -------------------------------------------------------------------------------------------- // +// * Implementation * +// -------------------------------------------------------------------------------------------- // + +scm::LexemeList::LexemeList() +{ + size = 0; + nalloc = 0; +} + +scm::LexemeList::~LexemeList() +{ + clear(); +} + +scm::LexemeList::LexemeList(const LexemeList& list) +{ + size = list.size; + + if (size > 0) { + lexeme = new Lexeme[size]; + for (int k = 0; k < size; k++) + lexeme[k] = list.lexeme[k]; + } + + nalloc = size; +} +// -------------------------------------------------------------------------------------------- // + +// * swap & assignment * // +// -------------------------------------------------------------------------------------------- // +const scm::LexemeList& scm::LexemeList::operator=(LexemeList list) +{ + swap(list); + return (*this); +} + +void scm::LexemeList::swap(LexemeList& list) +{ + scm::swap(lexeme, list.lexeme); + scm::swap(size, list.size); + scm::swap(nalloc, list.nalloc); +} +// -------------------------------------------------------------------------------------------- // + +// * add calls * // +// -------------------------------------------------------------------------------------------- // +void scm::LexemeList::add(const char* token, const Lexeme::TYPE type, const int tag) +{ + if (size == nalloc) + { + Lexeme *cp_list; + cp_list = new Lexeme[nalloc + c_nalloc_inc]; + + for (int k = 0; k < size; k++) + cp_list[k].swap(lexeme[k]); + + if (nalloc > 0) delete[] lexeme; + lexeme = cp_list; + + nalloc += c_nalloc_inc; + } + + lexeme[size].set(token, type, tag); + size++; +} + +void scm::LexemeList::add(const char* token, const Lexeme::TYPE type) +{ + add(token, type, 0); +} +// -------------------------------------------------------------------------------------------- // + +// * get calls * // +// -------------------------------------------------------------------------------------------- // +int scm::LexemeList::get_size() const +{ + return size; +} + +const scm::Lexeme scm::LexemeList::get_lexeme(const int idx) const +{ + if ((idx < 0) || (idx >= size)) return Lexeme(); + + return lexeme[idx]; +} + +const char* scm::LexemeList::get_token(const int idx) const +{ + if ((idx < 0) || (idx >= size)) return NULL; + + return lexeme[idx].get_token(); +} + +scm::Lexeme::TYPE scm::LexemeList::get_type(const int idx) const +{ + if ((idx < 0) || (idx >= size)) return Lexeme::IS_INVALID; + + return lexeme[idx].get_type(); +} + +int scm::LexemeList::get_tag(const int idx) const +{ + if ((idx < 0) || (idx >= size)) return 0; + + return lexeme[idx].get_tag(); +} +// -------------------------------------------------------------------------------------------- // + +// * check lexeme type * // +// -------------------------------------------------------------------------------------------- // +bool scm::LexemeList::is_operator(const int idx) const +{ + if ((idx < 0) || (idx >= size)) return false; + + return lexeme[idx].is_operator(); +} +bool scm::LexemeList::is_function(const int idx) const +{ + if ((idx < 0) || (idx >= size)) return false; + + return lexeme[idx].is_function(); +} +bool scm::LexemeList::is_ctor(const int idx) const +{ + if ((idx < 0) || (idx >= size)) return false; + + return lexeme[idx].is_ctor(); +} +bool scm::LexemeList::is_value(const int idx) const +{ + if ((idx < 0) || (idx >= size)) return false; + + return lexeme[idx].is_value(); +} +// -------------------------------------------------------------------------------------------- // + +// * clear & reset * // +// -------------------------------------------------------------------------------------------- // +void scm::LexemeList::clear() +{ + if (nalloc > 0) + delete[] lexeme; + + size = 0; + nalloc = 0; +} + +void scm::LexemeList::reset() +{ + size = 0; +} +// -------------------------------------------------------------------------------------------- // \ No newline at end of file diff --git a/parser/lexeme-list.h b/parser/lexeme-list.h new file mode 100644 index 0000000..f7c0883 --- /dev/null +++ b/parser/lexeme-list.h @@ -0,0 +1,71 @@ +#pragma once + +// [lexeme-list.h] +// -------------------------------------------------------------------------------------------- // +// lexeme list +// -------------------------------------------------------------------------------------------- // + +#include "lexeme.h" + + +namespace scm +{ + + class LexemeList { + public: + + // add calls + // -------------------------------------------------------------------------------------------- // + void add(const char* token, const Lexeme::TYPE type, const int tag); + void add(const char* token, const Lexeme::TYPE type); + // -------------------------------------------------------------------------------------------- // + + // get calls + // -------------------------------------------------------------------------------------------- // + int get_size() const; + + const Lexeme get_lexeme(const int idx) const; + + const char* get_token(const int idx) const; + Lexeme::TYPE get_type(const int idx) const; + int get_tag(const int idx) const; + // -------------------------------------------------------------------------------------------- // + + // check lexeme type + // -------------------------------------------------------------------------------------------- // + bool is_operator(const int idx) const; + bool is_function(const int idx) const; + bool is_ctor(const int idx) const; + bool is_value(const int idx) const; + // -------------------------------------------------------------------------------------------- // + + // clear & reset + // -------------------------------------------------------------------------------------------- // + void clear(); + void reset(); + // -------------------------------------------------------------------------------------------- // + + // swap & assignment + // -------------------------------------------------------------------------------------------- // + const LexemeList& operator=(LexemeList list); + void swap(LexemeList& list); + // -------------------------------------------------------------------------------------------- // + + // -------------------------------------------------------------------------------------------- // + LexemeList(); + LexemeList(const LexemeList& list); + ~LexemeList(); + // -------------------------------------------------------------------------------------------- // + + private: + // data (private): + // -------------------------------------------------------------------------------------------- // + + Lexeme *lexeme; + int size; + + int nalloc; + static const int c_nalloc_inc = 256; + }; +} +// -------------------------------------------------------------------------------------------- // diff --git a/parser/lexeme-parser.cpp b/parser/lexeme-parser.cpp new file mode 100644 index 0000000..c7a5330 --- /dev/null +++ b/parser/lexeme-parser.cpp @@ -0,0 +1,604 @@ +#include "lexeme-parser.h" + +#define _CRT_SECURE_NO_WARNINGS +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include "mem-buffer.h" + +// -------------------------------------------------------------------------------------------- // +// * Implementation * +// -------------------------------------------------------------------------------------------- // + +scm::LexemeParser::LexemeParser() +{ +} + +scm::LexemeParser::~LexemeParser() +{ +} +// -------------------------------------------------------------------------------------------- // + +// * run * // +// -------------------------------------------------------------------------------------------- // +bool scm::LexemeParser::run(const char* filename, LexemeList& list) +{ + // --- resetting list + list.reset(); + // ----------------------------------------------------- // + + // --- opening file + FILE *ptr = fopen(filename, "rt"); + if (ptr == NULL) { + printf(" LEX-PARSE:> failed to open file: '%s'\n", filename); + return false; + } + // ----------------------------------------------------- // + + // --- setting token buffer + mem_buffer< char > token_buf; + token_buf.reset(); + // ----------------------------------------------------- // + + int nline = 1, fsym; + STATE state = IS_NULL; + bool hold_sym = false; + bool status = true; + // ----------------------------------------------------- // + + // --- reading file + while (!feof(ptr)) + { + // --- reading char from file + if (!hold_sym) fsym = fgetc(ptr); + else + hold_sym = false; + + // --- processing null state + if (state == IS_NULL) + { + // --- EOF + if (fsym == EOF) continue; + // --- newline + if (fsym == '\n') { + nline++; + continue; + } + // --- spaces + if (isspace(fsym)) continue; + // --- comment line symbol + if (fsym == '#') { + state = IS_COMMENT_LINE; + continue; + } + // --- string + if (fsym == '"') { + state = IS_STRING; + token_buf.append(fsym); + continue; + } + // --- '=' + if (fsym == '=') { + state = IS_ASSIGNMENT; + token_buf.append(fsym); + continue; + } + // --- '!' + if (fsym == '!') { + state = IS_NOT_EQUAL; + token_buf.append(fsym); + continue; + } + // --- '&' + if (fsym == '&') { + state = IS_LOGICAL_AND; + token_buf.append(fsym); + continue; + } + // --- '|' + if (fsym == '|') { + state = IS_LOGICAL_OR; + token_buf.append(fsym); + continue; + } + // --- '<' + if (fsym == '<') { + state = IS_LESS_THAN; + token_buf.append(fsym); + continue; + } + // --- '>' + if (fsym == '>') { + state = IS_GREATER_THAN; + token_buf.append(fsym); + continue; + } + // --- '{','}' + if (fsym == '{') { + list.add("{", Lexeme::IS_BRACE_OPEN, nline); + continue; + } + if (fsym == '}') { + list.add("}", Lexeme::IS_BRACE_CLOSE, nline); + continue; + } + // --- '(', ')' + if (fsym == '(') { + list.add("(", Lexeme::IS_PAREN_OPEN, nline); + continue; + } + if (fsym == ')') { + list.add(")", Lexeme::IS_PAREN_CLOSE, nline); + continue; + } + // --- '[', ']' + if (fsym == '[') { + list.add("[", Lexeme::IS_BRACKET_OPEN, nline); + continue; + } + if (fsym == ']') { + list.add("]", Lexeme::IS_BRACKET_CLOSE, nline); + continue; + } + // --- ';' + if (fsym == ';') { + list.add(";", Lexeme::IS_SEMICOLON, nline); + continue; + } + // --- ',' + if (fsym == ',') { + list.add(",", Lexeme::IS_COMMA, nline); + continue; + } + // --- '+' + if (fsym == '+') { + // --- checking for unary '+' + if (list.get_size() == 0) list.add("+", Lexeme::IS_OP_PLUS, nline); + else + { + if ((list.is_value(list.get_size() - 1)) || + (list.get_type(list.get_size() - 1) == Lexeme::IS_NAME) || + (list.get_type(list.get_size() - 1) == Lexeme::IS_PAREN_CLOSE) || + (list.get_type(list.get_size() - 1) == Lexeme::IS_BRACKET_CLOSE)) + { + list.add("+", Lexeme::IS_OP_ADD, nline); + } + else + list.add("+", Lexeme::IS_OP_PLUS, nline); + } + continue; + } + // --- '-' + if (fsym == '-') { + // --- checking for unary '-' + if (list.get_size() == 0) list.add("-", Lexeme::IS_OP_MINUS, nline); + else + { + if ((list.is_value(list.get_size() - 1)) || + (list.get_type(list.get_size() - 1) == Lexeme::IS_NAME) || + (list.get_type(list.get_size() - 1) == Lexeme::IS_PAREN_CLOSE) || + (list.get_type(list.get_size() - 1) == Lexeme::IS_BRACKET_CLOSE)) + { + list.add("-", Lexeme::IS_OP_SUB, nline); + } + else + list.add("-", Lexeme::IS_OP_MINUS, nline); + } + continue; + } + // --- '*' + if (fsym == '*') { + list.add("*", Lexeme::IS_OP_MUL, nline); + continue; + } + // --- '/' + if (fsym == '/') { + list.add("/", Lexeme::IS_OP_DIV, nline); + continue; + } + // --- '%' + if (fsym == '%') { + list.add("%", Lexeme::IS_OP_MOD, nline); + continue; + } + // --- '^' + if (fsym == '^') { + list.add("^", Lexeme::IS_OP_EXP, nline); + continue; + } + // --- name + if (isalpha(fsym) || fsym == '_') + { + state = IS_NAME; + token_buf.append(fsym); + continue; + } + // --- number + if (isdigit(fsym)) + { + state = IS_NUMBER; + token_buf.append(fsym); + continue; + } + + // --- unknown symbol + printf(" PARSE:> invalid symbol: '%c' (line, %i)\n", fsym, nline); + status = false; + break; + } + // ----------------------------------------------------- // + + // --- assignment || comparsion (==) + if (state == IS_ASSIGNMENT) + { + if (fsym == '=') { + // found '==' + token_buf.append(fsym); + token_buf.append('\0'); + list.add(token_buf.get_ptr(), Lexeme::IS_OP_EQ, nline); + } + else { + // found '=' + token_buf.append('\0'); + list.add(token_buf.get_ptr(), Lexeme::IS_ASSIGNMENT, nline); + + hold_sym = true; + } + + token_buf.reset(); + + state = IS_NULL; + continue; + } + // ----------------------------------------------------- // + + // --- comparison (!=) + if (state == IS_NOT_EQUAL) + { + if (fsym == '=') { + // found '!=' + token_buf.append(fsym); + token_buf.append('\0'); + list.add(token_buf.get_ptr(), Lexeme::IS_OP_NEQ, nline); + + token_buf.reset(); + state = IS_NULL; + continue; + } + + // --- unknown symbol + printf(" PARSE:> invalid symbol: '%c', expecting '=' (line, %i)\n", fsym, nline); + status = false; + break; + } + // ----------------------------------------------------- // + + // --- logical (&&) + if (state == IS_LOGICAL_AND) + { + if (fsym == '&') { + // found '&&' + token_buf.append(fsym); + token_buf.append('\0'); + list.add(token_buf.get_ptr(), Lexeme::IS_OP_LOGICAL_AND, nline); + + token_buf.reset(); + state = IS_NULL; + continue; + } + + // --- unknown symbol + printf(" PARSE:> invalid symbol: '%c', expecting '&' (line, %i)\n", fsym, nline); + status = false; + break; + } + // ----------------------------------------------------- // + + // --- logical (||) + if (state == IS_LOGICAL_OR) + { + if (fsym == '|') { + // found '||' + token_buf.append(fsym); + token_buf.append('\0'); + list.add(token_buf.get_ptr(), Lexeme::IS_OP_LOGICAL_OR, nline); + + token_buf.reset(); + state = IS_NULL; + continue; + } + + // --- unknown symbol + printf(" PARSE:> invalid symbol: '%c', expecting '|' (line, %i)\n", fsym, nline); + status = false; + break; + } + // ----------------------------------------------------- // + + // --- comparison (<) || (<=) + if (state == IS_LESS_THAN) + { + if (fsym == '=') { + // found '<=' + token_buf.append(fsym); + token_buf.append('\0'); + list.add(token_buf.get_ptr(), Lexeme::IS_OP_LEQ, nline); + } + else { + // found '<' + token_buf.append('\0'); + list.add(token_buf.get_ptr(), Lexeme::IS_OP_LT, nline); + + hold_sym = true; + } + + token_buf.reset(); + + state = IS_NULL; + continue; + } + // ----------------------------------------------------- // + + // --- comparison (>) || (>=) + if (state == IS_GREATER_THAN) + { + if (fsym == '=') { + // found '>=' + token_buf.append(fsym); + token_buf.append('\0'); + list.add(token_buf.get_ptr(), Lexeme::IS_OP_GEQ, nline); + } + else { + // found '>' + token_buf.append('\0'); + list.add(token_buf.get_ptr(), Lexeme::IS_OP_GT, nline); + + hold_sym = true; + } + + token_buf.reset(); + + state = IS_NULL; + continue; + } + // ----------------------------------------------------- // + + // --- processing comment line + if (state == IS_COMMENT_LINE) + { + // --- EOF + if (fsym == EOF) { + state = IS_NULL; + continue; + } + // --- new line + if (fsym == '\n') { + nline++; + state = IS_NULL; + continue; + } + + // --- skipping all symbols + continue; + } + // ----------------------------------------------------- // + + // --- processing string + if (state == IS_STRING) + { + // --- EOF + if (fsym == EOF) { + // --- unknown symbol + token_buf.append('\0'); + printf(" PARSE:> missing closing quotation mark (\") in string: '%s' (line, %i)\n", + token_buf.get_ptr(), nline); + status = false; + break; + } + // --- adding all symbols + token_buf.append(fsym); + // --- closing string + if (fsym == '"') + { + token_buf.append('\0'); + + list.add(token_buf.get_ptr(), Lexeme::IS_STRING, nline); + token_buf.reset(); + state = IS_NULL; + } + continue; + } + // ----------------------------------------------------- // + + // --- processing name + if (state == IS_NAME) + { + // --- adding alpha, numerals, '_' and '.' + if (isalnum(fsym) || (fsym == '_') || (fsym == '.')) { + token_buf.append(fsym); + continue; + } + // --- checking if last element is dot + if (token_buf.get_value(token_buf.get_size() - 1) == '.') + { + token_buf.append('\0'); + printf(" PARSE:> invalid name ending with '.': '%s' (line, %i)\n", + token_buf.get_ptr(), nline); + status = false; + break; + } + // --- closing name + token_buf.append('\0'); + + if ((!strcmp(token_buf.get_ptr(), "true")) || + (!strcmp(token_buf.get_ptr(), "false"))) + { + list.add(token_buf.get_ptr(), Lexeme::IS_BOOL, nline); + } + else if (!strcmp(token_buf.get_ptr(), "if")) + list.add(token_buf.get_ptr(), Lexeme::IS_KEY_IF, nline); + else if (!strcmp(token_buf.get_ptr(), "then")) + list.add(token_buf.get_ptr(), Lexeme::IS_KEY_THEN, nline); + else if (!strcmp(token_buf.get_ptr(), "else")) + list.add(token_buf.get_ptr(), Lexeme::IS_KEY_ELSE, nline); + else if (!strcmp(token_buf.get_ptr(), "endif")) + list.add(token_buf.get_ptr(), Lexeme::IS_KEY_ENDIF, nline); + else if (!strcmp(token_buf.get_ptr(), "while")) + list.add(token_buf.get_ptr(), Lexeme::IS_KEY_WHILE, nline); + else if (!strcmp(token_buf.get_ptr(), "do")) + list.add(token_buf.get_ptr(), Lexeme::IS_KEY_DO, nline); + else if (!strcmp(token_buf.get_ptr(), "enddo")) + list.add(token_buf.get_ptr(), Lexeme::IS_KEY_ENDDO, nline); + else if (!strcmp(token_buf.get_ptr(), "__sin")) + list.add(token_buf.get_ptr(), Lexeme::IS_SIN_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__cos")) + list.add(token_buf.get_ptr(), Lexeme::IS_COS_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__tan")) + list.add(token_buf.get_ptr(), Lexeme::IS_TAN_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__log")) + list.add(token_buf.get_ptr(), Lexeme::IS_LOG_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__sqrt")) + list.add(token_buf.get_ptr(), Lexeme::IS_SQRT_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__min")) + list.add(token_buf.get_ptr(), Lexeme::IS_MIN_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__max")) + list.add(token_buf.get_ptr(), Lexeme::IS_MAX_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__vecmin")) + list.add(token_buf.get_ptr(), Lexeme::IS_VECMIN_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__vecmax")) + list.add(token_buf.get_ptr(), Lexeme::IS_VECMAX_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__abs")) + list.add(token_buf.get_ptr(), Lexeme::IS_ABS_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__unirand")) + list.add(token_buf.get_ptr(), Lexeme::IS_UNIRAND_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__dot")) + list.add(token_buf.get_ptr(), Lexeme::IS_DOT_PRODUCT_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__l2norm")) + list.add(token_buf.get_ptr(), Lexeme::IS_L2NORM_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__cnorm")) + list.add(token_buf.get_ptr(), Lexeme::IS_CNORM_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__to_string")) + list.add(token_buf.get_ptr(), Lexeme::IS_TO_STRING_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__size")) + list.add(token_buf.get_ptr(), Lexeme::IS_SIZE_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__defined")) + list.add(token_buf.get_ptr(), Lexeme::IS_DEFINED_FUNCTION, nline); + else if (!strcmp(token_buf.get_ptr(), "__vector")) + list.add(token_buf.get_ptr(), Lexeme::IS_VECTOR_CTOR, nline); + else if (!strcmp(token_buf.get_ptr(), "__vector_const")) + list.add(token_buf.get_ptr(), Lexeme::IS_VECTOR_CONST_CTOR, nline); + else if (!strcmp(token_buf.get_ptr(), "__vector_unirand")) + list.add(token_buf.get_ptr(), Lexeme::IS_VECTOR_UNIRAND_CTOR, nline); + else + { + if (!strncmp(token_buf.get_ptr(), "__", 2)) { + list.add(token_buf.get_ptr(), Lexeme::IS_COMMAND, nline); + } + else + list.add(token_buf.get_ptr(), Lexeme::IS_NAME, nline); + } + + token_buf.reset(); + state = IS_NULL; + hold_sym = true; + continue; + } + // ----------------------------------------------------- // + + // --- processing number + if (state == IS_NUMBER) + { + // --- adding digits + if (isdigit(fsym)) { + token_buf.append(fsym); + continue; + } + // --- changing state to fractional part + if (fsym == '.') { + token_buf.append(fsym); + state = IS_FRAC_NUMBER; + continue; + } + // --- changing state to exponent + if ((fsym == 'e') || (fsym == 'E')) { + token_buf.append(fsym); + state = IS_EXP_NUMBER; + continue; + } + + // --- closing integer + token_buf.append('\0'); + list.add(token_buf.get_ptr(), Lexeme::IS_INTEGER, nline); + + token_buf.reset(); + state = IS_NULL; + hold_sym = true; + continue; + } + // ----------------------------------------------------- // + + // --- processing fractional part + if (state == IS_FRAC_NUMBER) + { + // --- adding digits + if (isdigit(fsym)) { + token_buf.append(fsym); + continue; + } + // --- changing state to exponent + if ((fsym == 'e') || (fsym == 'E')) { + token_buf.append(fsym); + state = IS_EXP_NUMBER; + continue; + } + // --- closing floating point + token_buf.append('\0'); + list.add(token_buf.get_ptr(), Lexeme::IS_FLOAT, nline); + + token_buf.reset(); + state = IS_NULL; + hold_sym = true; + continue; + } + + // --- processing exponent + if (state == IS_EXP_NUMBER) + { + // --- adding digits + if (isdigit(fsym)) { + token_buf.append(fsym); + continue; + } + // --- handing exponent sign + if (((fsym == '+') || (fsym == '-')) && + ((token_buf.get_value(token_buf.get_size() - 1) == 'e') || + (token_buf.get_value(token_buf.get_size() - 1) == 'E'))) + { + token_buf.append(fsym); + continue; + } + // --- closing floating point + token_buf.append('\0'); + list.add(token_buf.get_ptr(), Lexeme::IS_FLOAT, nline); + + token_buf.reset(); + state = IS_NULL; + hold_sym = true; + continue; + } + + // unknown state + token_buf.append('\0'); + printf(" PARSE:> invalid parser state: '%s' (line, %i)\n", + token_buf.get_ptr(), nline); + status = false; + break; + } + + + fclose(ptr); + return status; +} +// -------------------------------------------------------------------------------------------- // diff --git a/parser/lexeme-parser.h b/parser/lexeme-parser.h new file mode 100644 index 0000000..0bdc0e4 --- /dev/null +++ b/parser/lexeme-parser.h @@ -0,0 +1,49 @@ +#pragma once + +// [lexeme-parser.h] +// -------------------------------------------------------------------------------------------- // +// lexeme parser static class +// -------------------------------------------------------------------------------------------- // + +#include "lexeme-list.h" + + +namespace scm +{ + + class LexemeParser { + public: + + // run --> get lexeme list + // -------------------------------------------------------------------------------------------- // + static bool run(const char* filename, LexemeList& list); + // -------------------------------------------------------------------------------------------- // + + private: + + // parser state + // -------------------------------------------------------------------------------------------- // + enum STATE { + IS_NULL, + IS_COMMENT_LINE, + IS_STRING, + IS_NAME, + IS_NUMBER, + IS_FRAC_NUMBER, + IS_EXP_NUMBER, + IS_ASSIGNMENT, + IS_LESS_THAN, + IS_GREATER_THAN, + IS_NOT_EQUAL, + IS_LOGICAL_AND, + IS_LOGICAL_OR, + }; + // -------------------------------------------------------------------------------------------- // + + // -------------------------------------------------------------------------------------------- // + LexemeParser(); + ~LexemeParser(); + // -------------------------------------------------------------------------------------------- // + }; +} +// -------------------------------------------------------------------------------------------- // diff --git a/parser/lexeme.cpp b/parser/lexeme.cpp new file mode 100644 index 0000000..08f781c --- /dev/null +++ b/parser/lexeme.cpp @@ -0,0 +1,173 @@ +#include "lexeme.h" + +#define _CRT_SECURE_NO_WARNINGS +#include <string.h> + +#include "scm-mem.h" + +// -------------------------------------------------------------------------------------------- // +// * Implementation * // +// -------------------------------------------------------------------------------------------- // + +scm::Lexeme::Lexeme() +{ + token = NULL; + type = IS_INVALID; + tag = 0; +} + +scm::Lexeme::~Lexeme() +{ + clear(); +} + +scm::Lexeme::Lexeme(const Lexeme& lexeme) +{ + if (lexeme.token == NULL) token = NULL; + else + { + token = new char[strlen(lexeme.token) + 1]; + strcpy(token, lexeme.token); + } + + type = lexeme.type; + tag = lexeme.tag; +} +// -------------------------------------------------------------------------------------------- // + +// * swap & assignment * // +// -------------------------------------------------------------------------------------------- // +const scm::Lexeme& scm::Lexeme::operator=(Lexeme lexeme) +{ + swap(lexeme); + return (*this); +} + +void scm::Lexeme::swap(Lexeme& lexeme) +{ + scm::swap(token, lexeme.token); + scm::swap(type, lexeme.type); + scm::swap(tag, lexeme.tag); +} +// -------------------------------------------------------------------------------------------- // + +// * set calls * // +// -------------------------------------------------------------------------------------------- // +void scm::Lexeme::set(const char* _token, const TYPE _type, const int _tag) +{ + clear(); + if ((_token == NULL) || (_type == IS_INVALID)) return; + + token = new char[strlen(_token) + 1]; + strcpy(token, _token); + + type = _type; + tag = _tag; +} + +void scm::Lexeme::set(const char* _token, const TYPE _type) +{ + set(_token, _type, 0); +} +// -------------------------------------------------------------------------------------------- // + +// * get calls * // +// -------------------------------------------------------------------------------------------- // +const char* scm::Lexeme::get_token() const +{ + return token; +} + +scm::Lexeme::TYPE scm::Lexeme::get_type() const +{ + return type; +} + +int scm::Lexeme::get_tag() const +{ + return tag; +} +// -------------------------------------------------------------------------------------------- // + +// * clear * // +// -------------------------------------------------------------------------------------------- // +void scm::Lexeme::clear() +{ + if (token != NULL) delete[] token; + + token = NULL; + type = IS_INVALID; + tag = 0; +} +// -------------------------------------------------------------------------------------------- // + +// * check lexeme type * // +// -------------------------------------------------------------------------------------------- // +bool scm::Lexeme::is_operator() const +{ + return is_operator(type); +} + +bool scm::Lexeme::is_function() const +{ + return is_function(type); +} + +bool scm::Lexeme::is_ctor() const +{ + return is_ctor(type); +} + +bool scm::Lexeme::is_value() const +{ + return is_value(type); +} + +bool scm::Lexeme::is_operator(const Lexeme::TYPE type) +{ + return ( + (type == IS_OP_ADD) || (type == IS_OP_SUB) || + (type == IS_OP_MUL) || (type == IS_OP_DIV) || (type == IS_OP_MOD) || + (type == IS_OP_PLUS) || (type == IS_OP_MINUS) || + (type == IS_OP_EXP) || + (type == IS_OP_EQ) || (type == IS_OP_NEQ) || + (type == IS_OP_LOGICAL_AND) || (type == IS_OP_LOGICAL_OR) || + (type == IS_OP_LT) || (type == IS_OP_GT) || + (type == IS_OP_LEQ) || (type == IS_OP_GEQ) + ); +} + +bool scm::Lexeme::is_function(const Lexeme::TYPE type) +{ + return ( + (type == IS_SIN_FUNCTION) || (type == IS_COS_FUNCTION) || + (type == IS_TAN_FUNCTION) || (type == IS_LOG_FUNCTION) || + (type == IS_SQRT_FUNCTION) || + (type == IS_MIN_FUNCTION) || (type == IS_MAX_FUNCTION) || + (type == IS_VECMIN_FUNCTION) || (type == IS_VECMAX_FUNCTION) || + (type == IS_ABS_FUNCTION) || (type == IS_UNIRAND_FUNCTION) || + (type == IS_DOT_PRODUCT_FUNCTION) || + (type == IS_L2NORM_FUNCTION) || (type == IS_CNORM_FUNCTION) || + (type == IS_TO_STRING_FUNCTION) || + (type == IS_SIZE_FUNCTION) || (type == IS_DEFINED_FUNCTION) + ); +} + +bool scm::Lexeme::is_ctor(const Lexeme::TYPE type) +{ + return ( + (type == IS_VECTOR_CTOR) || + (type == IS_VECTOR_CONST_CTOR) || + (type == IS_VECTOR_UNIRAND_CTOR)) + ; +} + +bool scm::Lexeme::is_value(const Lexeme::TYPE type) +{ + return ( + (type == IS_INTEGER) || (type == IS_FLOAT) || + (type == IS_BOOL) || + (type == IS_STRING) + ); +} +// -------------------------------------------------------------------------------------------- // diff --git a/parser/lexeme.h b/parser/lexeme.h new file mode 100644 index 0000000..60da98d --- /dev/null +++ b/parser/lexeme.h @@ -0,0 +1,112 @@ +#pragma once + +// [lexeme.h] +// -------------------------------------------------------------------------------------------- // +// lexeme data class +// -------------------------------------------------------------------------------------------- // + +namespace scm +{ + class Lexeme { + public: + + // lexeme types + // -------------------------------------------------------------------------------------------- // + enum TYPE { + IS_INVALID, + IS_NAME, // + IS_ASSIGNMENT, // = + IS_BRACE_OPEN, IS_BRACE_CLOSE, // {} + IS_PAREN_OPEN, IS_PAREN_CLOSE, // () + IS_BRACKET_OPEN, IS_BRACKET_CLOSE, // [] + IS_SEMICOLON, // ; + IS_COMMA, // , + IS_INTEGER, IS_FLOAT, IS_BOOL, // + IS_STRING, // + IS_OP_ADD, IS_OP_SUB, // +,- + IS_OP_MUL, IS_OP_DIV, IS_OP_MOD, // *,/,% + IS_OP_PLUS, IS_OP_MINUS, // +,- + IS_OP_EXP, // ^ + IS_OP_EQ, IS_OP_NEQ, // ==, != + IS_OP_LT, IS_OP_GT, // <, > + IS_OP_LEQ, IS_OP_GEQ, // <=, >= + IS_OP_LOGICAL_AND, IS_OP_LOGICAL_OR, // &&, || + IS_SIN_FUNCTION, IS_COS_FUNCTION, // __sin, __cos + IS_TAN_FUNCTION, // __tan + IS_LOG_FUNCTION, // __log + IS_SQRT_FUNCTION, // __sqrt + IS_MIN_FUNCTION, IS_MAX_FUNCTION, // __min, __max + IS_VECMIN_FUNCTION, IS_VECMAX_FUNCTION, // __vecmin, __vecmax + IS_ABS_FUNCTION, // __abs + IS_UNIRAND_FUNCTION, // __unirand + IS_DOT_PRODUCT_FUNCTION, // __dot + IS_L2NORM_FUNCTION, IS_CNORM_FUNCTION, // __l2norm, __cnorm + IS_TO_STRING_FUNCTION, // __to_string + IS_SIZE_FUNCTION, // __size + IS_DEFINED_FUNCTION, // __defined + IS_COMMAND, // __$ + IS_VECTOR_CTOR, // __vector + IS_VECTOR_CONST_CTOR, // __vector_const + IS_VECTOR_UNIRAND_CTOR, // __vector_unirand + IS_KEY_IF, IS_KEY_THEN, // 'if', 'then' + IS_KEY_ELSE, IS_KEY_ENDIF, // 'else', 'endif' + IS_KEY_WHILE, // 'while' + IS_KEY_DO, IS_KEY_ENDDO // 'do', 'enddo' + }; + // -------------------------------------------------------------------------------------------- // + + public: + + // set calls + // -------------------------------------------------------------------------------------------- // + void set(const char* _token, const TYPE _type, const int _tag); + void set(const char* _token, const TYPE _type); + // -------------------------------------------------------------------------------------------- // + + // get calls + // -------------------------------------------------------------------------------------------- // + const char* get_token() const; + TYPE get_type() const; + int get_tag() const; + // -------------------------------------------------------------------------------------------- // + + // check lexeme type + // -------------------------------------------------------------------------------------------- // + bool is_operator() const; + bool is_function() const; + bool is_ctor() const; + bool is_value() const; + + static bool is_operator(const Lexeme::TYPE type); + static bool is_function(const Lexeme::TYPE type); + static bool is_ctor(const Lexeme::TYPE type); + static bool is_value(const Lexeme::TYPE type); + // -------------------------------------------------------------------------------------------- // + + // clear + // -------------------------------------------------------------------------------------------- // + void clear(); + // -------------------------------------------------------------------------------------------- // + + // swap & assignment + // -------------------------------------------------------------------------------------------- // + const Lexeme& operator=(Lexeme lexeme); + void swap(Lexeme& lexeme); + // -------------------------------------------------------------------------------------------- // + + // -------------------------------------------------------------------------------------------- // + Lexeme(); + Lexeme(const Lexeme& lexeme); + ~Lexeme(); + // -------------------------------------------------------------------------------------------- // + + private: + // data (private): + // -------------------------------------------------------------------------------------------- // + + char *token; + TYPE type; + int tag; + }; + // -------------------------------------------------------------------------------------------- // +} diff --git a/parser/mem-buffer.h b/parser/mem-buffer.h new file mode 100644 index 0000000..042e7b0 --- /dev/null +++ b/parser/mem-buffer.h @@ -0,0 +1,148 @@ +#pragma once + +// [mem-buffer.h] +// -------------------------------------------------------------------------------------------- // +// fast memory buffer for c primary data types +// -------------------------------------------------------------------------------------------- // + +#include "scm-mem.h" + +#include <string.h> + +namespace scm +{ + template< typename T > + class mem_buffer { + public: + + // append value + // -------------------------------------------------------------------------------------------- // + void append(const T value); + void append(const T* value, const int n); + // -------------------------------------------------------------------------------------------- // + + // reset + // -------------------------------------------------------------------------------------------- // + void reset(); + // -------------------------------------------------------------------------------------------- // + + // get calls + // -------------------------------------------------------------------------------------------- // + const T* get_ptr() const; + T get_value(const int idx) const; + int get_size() const; + // -------------------------------------------------------------------------------------------- // + + // -------------------------------------------------------------------------------------------- // + mem_buffer(); + ~mem_buffer(); + // -------------------------------------------------------------------------------------------- // + + private: + // data (private): + // -------------------------------------------------------------------------------------------- // + + T *buf; + int size; + int nalloc; + + static const int c_nalloc_inc = 256; + }; +} +// -------------------------------------------------------------------------------------------- // + +// -------------------------------------------------------------------------------------------- // +// * Implementation * +// -------------------------------------------------------------------------------------------- // + +template< typename T > +scm::mem_buffer< T >::mem_buffer() +{ + size = 0; + nalloc = 0; +} + +template< typename T > +scm::mem_buffer< T >::~mem_buffer() +{ + if (nalloc > 0) + deallocate(buf); + + nalloc = 0; + size = 0; +} +// -------------------------------------------------------------------------------------------- // + +// * append * // +// -------------------------------------------------------------------------------------------- // +template< typename T > +void scm::mem_buffer< T >::append(const T value) +{ + if (size == nalloc) { + T *lbuf; + allocate(&lbuf, nalloc + c_nalloc_inc); + if (size > 0) { + memcpy(lbuf, buf, size * sizeof(T)); + deallocate(buf); + } + + buf = lbuf; + nalloc += c_nalloc_inc; + } + + buf[size] = value; + size++; +} + +template< typename T > +void scm::mem_buffer< T >::append(const T* value, const int n) +{ + if ((size - 1) + n >= nalloc) { + T *lbuf; + allocate(&lbuf, nalloc + max(c_nalloc_inc, size + n - nalloc)); + if (size > 0) { + memcpy(lbuf, buf, size * sizeof(T)); + deallocate(buf); + } + + buf = lbuf; + nalloc += max(c_nalloc_inc, size + n - nalloc); + } + + memcpy(&buf[size], value, n); + size += n; +} +// -------------------------------------------------------------------------------------------- // + +// * reset * // +// -------------------------------------------------------------------------------------------- // +template< typename T > +void scm::mem_buffer< T >::reset() +{ + size = 0; +} +// -------------------------------------------------------------------------------------------- // + +// * get calls * // +// -------------------------------------------------------------------------------------------- // +template< typename T > +const T* scm::mem_buffer< T >::get_ptr() const +{ + return buf; +} + +template< typename T > +T scm::mem_buffer< T >::get_value(const int idx) const +{ + if ((idx >= 0) && (idx < size)) + return buf[idx]; + + return (T)0; +} + +template< typename T > +int scm::mem_buffer< T >::get_size() const +{ + return size; +} +// -------------------------------------------------------------------------------------------- // diff --git a/parser/scm-mem.h b/parser/scm-mem.h new file mode 100644 index 0000000..f80e349 --- /dev/null +++ b/parser/scm-mem.h @@ -0,0 +1,523 @@ +#pragma once + +// [scm-mem.h] +// -------------------------------------------------------------------------------------------- // +// memory handling, array ops & simple math +// -------------------------------------------------------------------------------------------- // + + +#include <stdlib.h> +#include <math.h> +#if defined(_OPENMP) +#include <omp.h> +#endif +#include <time.h> +#include "scm-sys.h" + + +namespace scm +{ + // * memory (de)allocation * // + // -------------------------------------------------------------------------------------------- // + template< typename T > + bool allocate(T** x, const int n); + template< typename T > + bool allocate(T** x, T** y, const int n); + template< typename T > + bool allocate(T** x, T** y, T** z, const int n); + + template< typename T > + void deallocate(T* x); + template< typename T > + void deallocate(T* x, T* y); + template< typename T > + void deallocate(T* x, T* y, T* z); + + template< typename T > + bool allocate_preset(T** x, const T value, const int n); + template< typename T > + bool allocate_preset(T** x, T** y, const T value, const int n); + template< typename T > + bool allocate_preset(T** x, T** y, T** z, const T value, const int n); + // -------------------------------------------------------------------------------------------- // + + // * swap * // + template< typename T > + void swap(T& a, T& b); + // -------------------------------------------------------------------------------------------- // + + // * math & vector operations * // + // -------------------------------------------------------------------------------------------- // + template< typename T > + T min(const T a, const T b); + template< typename T > + T max(const T a, const T b); + template< typename T > + T min(const T a, const T b, const T c); + template< typename T > + T max(const T a, const T b, const T c); + template< typename T > + T min(const T a, const T b, const T c, const T d); + template< typename T > + T max(const T a, const T b, const T c, const T d); + + template< typename T > + T sgn(const T a); + + template< typename T > + void assign(T* _RESTRICT x, const T value, const int n); + template< typename T > + void null(T* _RESTRICT x, const int n); + template< typename T > + void null(T* _RESTRICT x, T* _RESTRICT y, const int n); + template< typename T > + void null(T* _RESTRICT x, T* _RESTRICT y, T* _RESTRICT z, const int n); + + template< typename T > + T max(const T* _RESTRICT x, const int n); + template< typename T > + T min(const T* _RESTRICT x, const int n); + template< typename T > + T avg(const T* _RESTRICT x, const int n); + template< typename T > + T intsum(const T* _RESTRICT f, const T* _RESTRICT dx, const int n); + + template< typename T > + T interp(const T* _RESTRICT X, const T* _RESTRICT z, const int n, const T pz); + // -------------------------------------------------------------------------------------------- // + + // * vector checks * // + // -------------------------------------------------------------------------------------------- // + template< typename T > + bool is_finite(const T* _RESTRICT x, const int n); + // -------------------------------------------------------------------------------------------- // + + // * timer * // + // -------------------------------------------------------------------------------------------- // + double get_sys_time(); + // -------------------------------------------------------------------------------------------- // +} + + +// -------------------------------------------------------------------------------------------- // +// * Implementation * +// -------------------------------------------------------------------------------------------- // + +// * memory (de)allocation * // +// -------------------------------------------------------------------------------------------- // +template< typename T > +inline bool scm::allocate( + T** x, const int n) +{ +#ifndef ALIGN_ALLOCATION + (*x) = new T[n]; +#else +#if defined(__INTEL_COMPILER) + (*x) = (T*)_mm_malloc(n * sizeof(T), ALIGN_ALLOCATION); + if (*x == NULL) return false; + +#elif defined(_MSC_VER) + (*x) = (T*)_aligned_malloc(n * sizeof(T), ALIGN_ALLOCATION); + if (*x == NULL) return false; + +#else // die or use posix // + if (posix_memalign((void**)x, ALIGN_ALLOCATION, n * sizeof(T)) != 0) + return false; +#endif +#endif + + return true; +} + +template< typename T > +inline bool scm::allocate( + T** x, T** y, const int n) +{ + if (!allocate(x, n)) return false; + if (!allocate(y, n)) { + deallocate(*x); + return false; + } + + return true; +} + +template< typename T > +inline bool scm::allocate( + T** x, T** y, T** z, const int n) +{ + if (!allocate(x, n)) return false; + if (!allocate(y, n)) { + deallocate(*x); + return false; + } + if (!allocate(z, n)) { + deallocate(*x); + deallocate(*y); + return false; + } + + return true; +} + +template< typename T > +inline void scm::deallocate( + T* x) +{ +#ifndef ALIGN_ALLOCATION + delete[] x; +#else +#if defined(__INTEL_COMPILER) + _mm_free((void*)x); +#elif defined(_MSC_VER) + _aligned_free((void*)x); +#else // die or use posix // + free((void*)x); +#endif +#endif +} + +template< typename T > +inline void scm::deallocate( + T* x, T* y) +{ + deallocate(x); + deallocate(y); +} + +template< typename T > +inline void scm::deallocate( + T* x, T* y, T* z) +{ + deallocate(x); + deallocate(y); + deallocate(z); +} + +template< typename T > +inline bool scm::allocate_preset( + T** x, const T value, const int n) +{ + if (!allocate(x, n)) return false; + + assign((*x), value, n); + return true; +} + +template< typename T > +inline bool scm::allocate_preset( + T** x, T** y, const T value, const int n) +{ + if (!allocate(x, y, n)) return false; + + assign((*x), value, n); + assign((*y), value, n); + return true; +} + +template< typename T > +inline bool scm::allocate_preset( + T** x, T** y, T** z, const T value, const int n) +{ + if (!allocate(x, y, z, n)) return false; + + assign((*x), value, n); + assign((*y), value, n); + assign((*z), value, n); + return true; +} +// -------------------------------------------------------------------------------------------- // + +// * swap * // +// -------------------------------------------------------------------------------------------- // +template< typename T > +inline void scm::swap(T& a, T& b) +{ + T c = a; a = b; b = c; +} +// -------------------------------------------------------------------------------------------- // + +// * math & vector operations * // +// -------------------------------------------------------------------------------------------- // +template< typename T > +inline T scm::min( + const T a, const T b) +{ + return (a < b) ? a : b; +} + +template< typename T > +inline T scm::max( + const T a, const T b) +{ + return (a > b) ? a : b; +} + +template< typename T > +inline T scm::min( + const T a, const T b, const T c) +{ + return (a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c); +} + +template< typename T > +inline T scm::max( + const T a, const T b, const T c) +{ + return (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c); +} + +template< typename T > +inline T scm::min( + const T a, const T b, const T c, const T d) +{ + return min(min(a, b, c), d); +} + +template< typename T > +inline T scm::max( + const T a, const T b, const T c, const T d) +{ + return max(max(a, b, c), d); +} + +template< typename T > +inline T scm::sgn( + const T a) +{ + if (a < (T)0) return (T)-1.0; + if (a > (T)0) return (T)1.0; + + return (T)0; +} + +template< typename T > +inline void scm::assign( + T* _RESTRICT x, const T value, const int n) +{ +#pragma omp parallel shared( x ) + { + int i; + +#pragma omp for nowait + for (i = 0; i < n - (n % 4); i += 4) { + x[i] = value; + x[i + 1] = value; + x[i + 2] = value; + x[i + 3] = value; + } + +#pragma omp single nowait + for (i = n - (n % 4); i < n; i++) + x[i] = value; + } +} + +template< typename T > +inline void scm::null( + T* _RESTRICT x, const int n) +{ +#pragma omp parallel shared( x ) + { + int i; + +#pragma omp for nowait + for (i = 0; i < n - (n % 4); i += 4) { + x[i] = (T)0; + x[i + 1] = (T)0; + x[i + 2] = (T)0; + x[i + 3] = (T)0; + } + +#pragma omp single nowait + for (i = n - (n % 4); i < n; i++) + x[i] = (T)0; + } +} + +template< typename T > +inline void scm::null( + T* _RESTRICT x, T* _RESTRICT y, const int n) +{ + null(x, n); + null(y, n); +} + +template< typename T > +inline void scm::null( + T* _RESTRICT x, T* _RESTRICT y, T* _RESTRICT z, const int n) +{ + null(x, n); + null(y, n); + null(z, n); +} + +template< typename T > +inline T scm::min( + const T* _RESTRICT const x, const int n) +{ + if (n <= 0) return (T)0; + + int i; + T _min = (T)(*x); + + T _min_local = (T)(*x); + +#pragma omp parallel firstprivate(_min_local) private(i) shared(_min) + { +#pragma omp for nowait + for (i = 1; i < n; i++) { + if (x[i] < _min_local) _min_local = x[i]; + } + +#pragma omp critical + { + if (_min_local < _min) _min = _min_local; + } + } + + return _min; +} + +template< typename T > +inline T scm::max( + const T* _RESTRICT const x, const int n) +{ + if (n <= 0) return (T)0; + + int i; + T _max = (T)(*x); + + T _max_local = (T)(*x); + +#pragma omp parallel firstprivate(_max_local) private(i) shared(_max) + { +#pragma omp for nowait + for (i = 1; i < n; i++) { + if (x[i] > _max_local) _max_local = x[i]; + } + +#pragma omp critical + { + if (_max_local > _max) _max = _max_local; + } + } + + return _max; +} + +template< typename T > +inline T scm::avg( + const T* _RESTRICT const x, const int n) +{ + if (n <= 0) return (T)0; + + int i; + T _sum = (T)0; + +#pragma omp parallel for private( i ) reduction( + : _sum ) + for (i = 0; i < n - (n % 4); i += 4) { + _sum += x[i] + x[i + 1] + x[i + 2] + x[i + 3]; + } + + for (i = n - (n % 4); i < n; i++) + _sum += x[i]; + + return _sum / n; +} + +template< typename T > +inline T scm::intsum( + const T* _RESTRICT const f, + const T* _RESTRICT const dx, + const int n) +{ + if (n <= 0) return (T)0; + + int i; + T _sum = (T)0; + +#pragma omp parallel for private( i ) reduction( + : _sum ) + for (i = 0; i < n - (n % 4); i += 4) { + _sum += + f[i] * dx[i] + f[i + 1] * dx[i + 1] + + f[i + 2] * dx[i + 2] + f[i + 3] * dx[i + 3]; + } + + for (i = n - (n % 4); i < n; i++) + _sum += f[i] * dx[i]; + + return _sum; +} + +template< typename T > +inline T scm::interp( + const T* _RESTRICT X, + const T* _RESTRICT z, const int n, + const T pz) +{ + if (n == 0) return (T)0; + if (n == 1) return X[0]; + + int k; + + k = 0; + if (pz < z[k]) { + // --- extrapolation, [zpos, zpos + dz/2): + T alpha = (z[k + 1] - pz) / (z[k + 1] - z[k]); + return alpha * X[k] + ((T)1.0 - alpha) * X[k + 1]; + } + + k = n - 1; + if (pz > z[k]) { + // --- extrapolation, (zpos + height - dz/2, zpos + height] + T alpha = (z[k] - pz) / (z[k] - z[k - 1]); + return alpha * X[k - 1] + ((T)1.0 - alpha) * X[k]; + } + + for (k = 0; k < n - 1; k++) { + if ((pz >= z[k]) && (pz <= z[k + 1])) + { + T alpha = (z[k + 1] - pz) / (z[k + 1] - z[k]); + return alpha * X[k] + ((T)1.0 - alpha) * X[k + 1]; + } + } + + return (T)0; +} +// -------------------------------------------------------------------------------------------- // + +// * vector checks * // +// -------------------------------------------------------------------------------------------- // +template< typename T > +inline bool scm::is_finite( + const T* _RESTRICT x, const int n) +{ + int i; + int num_inf = 0; + +#pragma omp parallel for private( i ) reduction( + : num_inf ) + for (i = 0; i < n - (n % 4); i += 4) { + if ((!isfinite(x[i])) || (!isfinite(x[i + 1])) || + (!isfinite(x[i + 2])) || (!isfinite(x[i + 3]))) num_inf++; + } + + for (i = n - (n % 4); i < n; i++) + if (!isfinite(x[i])) num_inf++; + + return (num_inf == 0); +} +// -------------------------------------------------------------------------------------------- // + +// * timer * // +// -------------------------------------------------------------------------------------------- // +inline double scm::get_sys_time() +{ +#if defined(_OPENMP) + return omp_get_wtime(); +#else + return ((double)clock() / CLOCKS_PER_SEC); +#endif +} +// -------------------------------------------------------------------------------------------- // + diff --git a/parser/scm-sys.h b/parser/scm-sys.h new file mode 100644 index 0000000..2a982ba --- /dev/null +++ b/parser/scm-sys.h @@ -0,0 +1,50 @@ +#pragma once + +// [scm-sys.h] +// -------------------------------------------------------------------------------------------- // +// system definitions +// -------------------------------------------------------------------------------------------- // + + +// : data type +// -------------------------------------------------------------------------------------------- // +#define Real double +// -------------------------------------------------------------------------------------------- // + +// : enable 'restrict' keyword +// -------------------------------------------------------------------------------------------- // +#define USE_RESTRICT_KEY +// -------------------------------------------------------------------------------------------- // + +// : aligned allocation, alignment defined in bytes (2^n values) +// -------------------------------------------------------------------------------------------- // +#define ALIGN_ALLOCATION 64 +// -------------------------------------------------------------------------------------------- // + +// : force number of OpenMP threads +// : else number of threads is determined by OMP_NUM_THREADS +// -------------------------------------------------------------------------------------------- // +#define SET_OPENMP_THREADS 1 +// -------------------------------------------------------------------------------------------- // + +// : NaN & Inf checks +// -------------------------------------------------------------------------------------------- // +#define SCM_CHECK_FINITE +// -------------------------------------------------------------------------------------------- // + +// _RESTRICT definition +// -------------------------------------------------------------------------------------------- // +#if defined(USE_RESTRICT_KEY) +#if defined(__INTEL_COMPILER) +#define _RESTRICT restrict +#elif defined(__GNUC__) && !defined(_WIN32) && !defined(_CYGWIN32__) +#define _RESTRICT __restrict__ +#elif defined(_MSC_VER) +#define _RESTRICT __restrict +#else +#define _RESTRICT +#endif +#else +#define _RESTRICT +#endif +// -------------------------------------------------------------------------------------------- // -- GitLab