From c825c85878975e785393851394db3938791452b7 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Mon, 29 Oct 2018 23:50:10 +0000 Subject: [PATCH] start working on a 'program mode' a new syntax for simple scripting git-svn-id: svn://ttmath.org/publicrep/ezc/trunk@1134 e52654a7-88a9-db11-a3e9-0013d4bc506e --- src/Makefile.dep | 5 + src/expressionparser.h | 68 ++++++++++++++ src/generator.h | 100 ++++++++++++++++++-- src/item.cpp | 3 +- src/item.h | 4 +- src/patternparser.cpp | 205 +++++++++++++++++++++++++++++++++++++---- src/patternparser.h | 8 ++ 7 files changed, 366 insertions(+), 27 deletions(-) create mode 100644 src/expressionparser.h diff --git a/src/Makefile.dep b/src/Makefile.dep index 6b0e710..5cf9617 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep @@ -9,3 +9,8 @@ pattern.o: pattern.h item.h cache.h functions.h ../../pikotools/utf8/utf8.h pattern.o: funinfo.h objects.h blocks.h patternparser.o: patternparser.h blocks.h item.h cache.h functions.h patternparser.o: ../../pikotools/utf8/utf8.h funinfo.h objects.h pattern.h +patternparser.o: ../../pikotools/convert/convert.h +patternparser.o: ../../pikotools/convert/inttostr.h +patternparser.o: ../../pikotools/convert/strtoint.h +patternparser.o: ../../pikotools/convert/text.h +patternparser.o: ../../pikotools/convert/misc.h diff --git a/src/expressionparser.h b/src/expressionparser.h new file mode 100644 index 0000000..b39706e --- /dev/null +++ b/src/expressionparser.h @@ -0,0 +1,68 @@ +/* + * This file is a part of EZC -- Easy templating in C++ library + * and is distributed under the BSD 3-Clause licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2018, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef headerfile_ezc_expressionparser +#define headerfile_ezc_expressionparser + + +namespace Ezc +{ + + + +class ExpressionParser +{ +public: + + ExpressionParser() {}; + virtual ~ExpressionParser() {}; + + // temporarily + + + virtual bool Parse(const std::wstring & str) = 0; + virtual bool LastResultToBool() = 0; + virtual std::wstring LastResult() = 0; + + + +}; + +} + +#endif diff --git a/src/generator.h b/src/generator.h index 0ebaf04..7395e7a 100644 --- a/src/generator.h +++ b/src/generator.h @@ -47,6 +47,7 @@ #include #include #include +#include "expressionparser.h" namespace Ezc @@ -111,6 +112,11 @@ public: // true by default void CanUseVars(bool can_use_variables); + void SetProgramMode(bool program_mode); + + void SetExpressionParser(ExpressionParser * expression_parser); + + // the main methods for generating void Generate(StreamType & out); void Generate(StreamType & out, OutStreams & out_streams); @@ -209,6 +215,11 @@ private: bool can_use_vars; bool can_find_in_cache; + bool program_mode; + + ExpressionParser * expression_parser; + + void ResizeStreamStack(std::vector & stream_tab, size_t stream_tab_max_size); void ResizeFilterTab(); @@ -305,6 +316,8 @@ private: void CreateUnknownMsg(const std::wstring & fun); bool LimitAchieved(); + void EvaluateProgramNode(Item & item); + void MakeTextIf_go(Item & item, bool result); void MakeTextIf(Item & item); void MakeTextFor(Item & item); @@ -349,6 +362,7 @@ Generator::Generator() : empty_stream() ezc_out_stack_size = 16; can_find_in_cache = true; can_use_vars = true; + expression_parser = nullptr; } @@ -381,6 +395,7 @@ Generator & Generator::operator=(const Generator::CanUseVars(bool can_use_variables) can_use_vars = can_use_variables; } +template +void Generator::SetProgramMode(bool set_program_mode) +{ + this->program_mode = set_program_mode; +} + +template +void Generator::SetExpressionParser(ExpressionParser * expression_parser) +{ + this->expression_parser = expression_parser; +} + @@ -1415,6 +1442,41 @@ void Generator::CreateUnknownMsg(const std::wstring & fun) +template +void Generator::EvaluateProgramNode(Item & item) +{ + if( output_stream ) + { + if( item.type == Item::item_function ) + *output_stream << " expression: " << item.text << "\n"; + + if( item.type == Item::item_if ) + *output_stream << " if: " << item.text << "\n"; + + if( item.type == Item::item_for ) + *output_stream << " for: " << item.text << "\n"; + } + + last_res = false; + + if( expression_parser ) + { + if( expression_parser->Parse(item.text) ) + { + last_res = expression_parser->LastResultToBool(); + } + else + { + if( output_stream ) + { + *output_stream << " syntax error when evaluating expression\n"; + } + } + } + +} + + template void Generator::MakeItemText(Item & item) @@ -1448,14 +1510,21 @@ void Generator::MakeTextNormal(Item & item) { is_generating_normal = true; - if( output_stream ) + if( program_mode ) { - Call(item.function, *output_stream, false, empty_stream); + EvaluateProgramNode(item); } else { - Call(item.function, stream_temp1, false, empty_stream); - ClearStream(stream_temp1); + if( output_stream ) + { + Call(item.function, *output_stream, false, empty_stream); + } + else + { + Call(item.function, stream_temp1, false, empty_stream); + ClearStream(stream_temp1); + } } } @@ -1484,8 +1553,15 @@ void Generator::MakeTextIf(Item & item) { is_generating_if = true; - if( !Call(item.function) ) - return; + if( program_mode ) + { + EvaluateProgramNode(item); + } + else + { + if( !Call(item.function) ) + return; + } MakeTextIf_go(item, last_res); } @@ -1510,13 +1586,21 @@ void Generator::MakeTextFor(Item & item) // is_generating_for will be changed by next call to MakeText() // so we should set it in each iterations is_generating_for = true; - Call(item.function, stream_temp1, true, empty_stream); + + if( program_mode ) + { + EvaluateProgramNode(item); + } + else + { + Call(item.function, stream_temp1, true, empty_stream); + } if( !last_res ) break; if( !item.item_tab.empty() ) - MakeText( *item.item_tab[0] ); // should be only one item - item_container + MakeText( *item.item_tab[0] ); // should be only one item } } diff --git a/src/item.cpp b/src/item.cpp index 36299cb..f6adfff 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2007-2015, Tomasz Sowa + * Copyright (c) 2007-2018, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -120,6 +120,7 @@ void Item::DeleteLastItem() Item::Item() { type = item_none; + has_function = false; } diff --git a/src/item.h b/src/item.h index 741c44c..c2fb49a 100644 --- a/src/item.h +++ b/src/item.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2007-2016, Tomasz Sowa + * Copyright (c) 2007-2018, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,7 +66,7 @@ struct Item std::wstring postfix; // a function can have an additional postfix in its name // e.g. [my_function:my_postfix] std::vector parameters; // if is_function is true then it is a function and can have 'parameters' - // if is_functino is empty then 'parameters' is empty too + // if is_function is empty then 'parameters' is empty too void * fun_cache; // only valid if is_function is true Item * item_block; void * base_obj; diff --git a/src/patternparser.cpp b/src/patternparser.cpp index 32e6df5..e85f520 100644 --- a/src/patternparser.cpp +++ b/src/patternparser.cpp @@ -37,6 +37,7 @@ #include "patternparser.h" +#include "convert/convert.h" #ifdef EZC_USE_WINIX_LOGGER #include "core/log.h" @@ -155,6 +156,11 @@ void PatternParser::SetCommentary(const std::wstring & com_start, const std::wst } +void PatternParser::SetProgramMode(bool program_mode) +{ + this->program_mode = program_mode; +} + void PatternParser::CreateMsg(std::wstring & out, const wchar_t * type, const wchar_t * arg) { @@ -186,6 +192,7 @@ void PatternParser::ParseFile(const char * file_name, Pattern & pattern) pat = &pattern; PT::UTF8ToWide(file_name, pat->item_root.file_name); include_level = 0; + CreateTreeReadIncludeSkipAllowFlag(pat->item_root); } @@ -232,6 +239,10 @@ void PatternParser::ParseString(const wchar_t * str, Pattern & pattern) pat = &pattern; itext = str; include_level = 0; + + pat->item_root.Clear(); + pat->item_root.type = Item::item_container; + CreateTree(pat->item_root); } @@ -875,21 +886,142 @@ int c; } +void PatternParser::CreateTreeReadDirectiveExpression(Item & item, wchar_t starting_terminator, wchar_t ending_terminator) +{ + long terminator_counter = 1; + + while( *itext ) + { + wchar_t c = *itext; + + if( c == 10 || c == 13 ) + c = ' '; + + if( c == starting_terminator ) + { + terminator_counter += 1; + } + + if( c == ending_terminator ) + { + terminator_counter -= 1; + + if( terminator_counter == 0 ) + { + itext += 1; + return; // end of expression; + } + } + + if( !IsWhite(c) || item.text.empty() || !IsWhite(item.text.back()) ) + item.text += c; + + itext += 1; + } +} + + +bool PatternParser::CreateTreeCheckProgramDirective(Item & item) +{ + if( PT::IsSubStringNoCasep(L"if", itext) ) + { + itext += 2; + SkipWhite(); + + if( *itext == '(' ) + { + itext += 1; + item.type = Item::item_if; + return true; + } + else + { + item.type = Item::item_err; + return false; + } + } + + if( PT::IsSubStringNoCasep(L"while", itext) ) + { + itext += 5; + SkipWhite(); + + if( *itext == '(' ) + { + itext += 1; + item.type = Item::item_for; + return true; + } + else + { + item.type = Item::item_err; + return false; + } + } + + return false; +} + + +bool PatternParser::CreateTreeReadExpression(Item & item) +{ + SkipWhite(); + + if( *itext == 0 ) + return false; + + if( *itext == '{' ) + { + item.type = Item::item_container; + itext += 1; + return true; + } + + if( *itext == '}' ) + { + item.type = Item::item_end; + itext += 1; + return true; + } + + if( CreateTreeCheckProgramDirective(item) ) + { + CreateTreeReadDirectiveExpression(item, '(', ')'); + } + else + { + if( item.type == Item::item_err ) + return false; + + item.type = Item::item_function; + CreateTreeReadDirectiveExpression(item, 0, ';'); + } + + return true; +} + bool PatternParser::CreateTreeReadItem(Item & item) { item.Clear(); - if( *itext == '[' ) + if( program_mode ) { - CreateTreeReadItemDirective(item); - return true; + return CreateTreeReadExpression(item); } else - if( *itext ) { - CreateTreeReadItemText(item); - return true; + if( *itext == '[' ) + { + CreateTreeReadItemDirective(item); + return true; + } + else + if( *itext ) + { + CreateTreeReadItemText(item); + return true; + } } // the end of the string @@ -931,7 +1063,11 @@ void PatternParser::CreateTreeReadIncludeSkipAllowFlag(Item & item) const wchar_t * itext_old = itext; itext = file_text.c_str(); + + item.Clear(); + item.type = Item::item_container; CreateTree(item); + itext = itext_old; --include_level; } @@ -941,14 +1077,35 @@ void PatternParser::CreateTreeReadIncludeSkipAllowFlag(Item & item) void PatternParser::CreateTreeReadIf(Item & item) { Item * pitem = item.AddItem(); + pitem->Clear(); + + if( program_mode ) + pitem->type = Item::item_none; + else + pitem->type = Item::item_container; + CreateTree(*pitem); - if( pitem->LastItemType() == Item::item_else ) + if( program_mode ) { - pitem->DeleteLastItem(); + SkipWhite(); - pitem = item.AddItem(); - CreateTree(*pitem); + if( PT::IsSubStringNoCasep(L"else", itext) ) + { + itext += 4; + pitem = item.AddItem(); + CreateTree(*pitem); + } + } + else + { + if( pitem->LastItemType() == Item::item_else ) + { + pitem->DeleteLastItem(); + + pitem = item.AddItem(); + CreateTree(*pitem); + } } if( pitem->LastItemType() == Item::item_end ) @@ -961,6 +1118,9 @@ void PatternParser::CreateTreeReadBlock(Item & item) { Item item_block; + item_block.Clear(); + item_block.type = Item::item_container; + CreateTree(item_block); if( item_block.LastItemType() == Item::item_end ) @@ -976,6 +1136,13 @@ Item item_block; void PatternParser::CreateTreeReadFor(Item & item) { Item * pitem = item.AddItem(); + pitem->Clear(); + + if( program_mode ) + pitem->type = Item::item_none; + else + pitem->type = Item::item_container; + CreateTree(*pitem); if( pitem->LastItemType() == Item::item_end ) @@ -986,18 +1153,22 @@ void PatternParser::CreateTreeReadFor(Item & item) void PatternParser::CreateTree(Item & item) { - item.Clear(); - item.type = Item::item_container; - - while( true ) + do { - Item * pitem = item.AddItem(); + Item * pitem; + + if( item.type != Item::item_container ) + pitem = &item; + else + pitem = item.AddItem(); do { if( !CreateTreeReadItem(*pitem) ) { - item.DeleteLastItem(); + if( item.type == Item::item_container ) + item.DeleteLastItem(); + return; } @@ -1021,6 +1192,8 @@ void PatternParser::CreateTree(Item & item) if( pitem->type == Item::item_include ) CreateTreeReadInclude(*pitem); } + while( item.type == Item::item_container ); + } diff --git a/src/patternparser.h b/src/patternparser.h index caabfb3..ee67f9a 100644 --- a/src/patternparser.h +++ b/src/patternparser.h @@ -86,6 +86,8 @@ public: void SetCommentary(const wchar_t * com_start, const wchar_t * com_stop); void SetCommentary(const std::wstring & com_start, const std::wstring & com_stop); + void SetProgramMode(bool program_mode); + private: // the output object @@ -131,6 +133,8 @@ private: Blocks * pblocks; + bool program_mode; + void CreateMsg(std::wstring & out, const wchar_t * type, const wchar_t * arg = 0); void ReadFile(const std::wstring & name, std::wstring & result); @@ -173,6 +177,10 @@ private: void ReadDirectiveReturn(Item & item); void ReadNormalStatement(Item & item); + void CreateTreeReadDirectiveExpression(Item & item, wchar_t starting_terminator, wchar_t ending_terminator); + bool CreateTreeCheckProgramDirective(Item & item); + bool CreateTreeReadExpression(Item & item); + void CreateTreeReadItemDirectiveCheckEnding(Item & item); void CreateTreeReadItemDirective(Item & item); void CreateTreeReadItemText(Item & item);