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
This commit is contained in:
Tomasz Sowa 2018-10-29 23:50:10 +00:00
parent 54387e43bb
commit c825c85878
7 changed files with 366 additions and 27 deletions

View File

@ -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

68
src/expressionparser.h Normal file
View File

@ -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 <t.sowa@ttmath.org>
*/
/*
* 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

View File

@ -47,6 +47,7 @@
#include <sstream>
#include <fstream>
#include <vector>
#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<StreamType> & 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<StreamType*> & 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<StreamType>::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<StreamType> & Generator<StreamType>::operator=(const Generator<StreamT
stack_size = n.stack_size;
block_stack_size = n.block_stack_size;
ezc_out_stack_size = n.ezc_out_stack_size;
expression_parser = n.expression_parser;
// vars doesn't have to be copied
@ -487,6 +502,18 @@ void Generator<StreamType>::CanUseVars(bool can_use_variables)
can_use_vars = can_use_variables;
}
template<class StreamType>
void Generator<StreamType>::SetProgramMode(bool set_program_mode)
{
this->program_mode = set_program_mode;
}
template<class StreamType>
void Generator<StreamType>::SetExpressionParser(ExpressionParser * expression_parser)
{
this->expression_parser = expression_parser;
}
@ -1415,6 +1442,41 @@ void Generator<StreamType>::CreateUnknownMsg(const std::wstring & fun)
template<class StreamType>
void Generator<StreamType>::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<class StreamType>
void Generator<StreamType>::MakeItemText(Item & item)
@ -1448,14 +1510,21 @@ void Generator<StreamType>::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<StreamType>::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<StreamType>::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
}
}

View File

@ -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;
}

View File

@ -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<Function*> 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;

View File

@ -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 );
}

View File

@ -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);