You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1197 lines
38 KiB
1197 lines
38 KiB
//=============================================================================
|
|
//
|
|
// File : kvi_kvs_parser_lside.cpp
|
|
// Creation date : Thu 03 Nov 2003 13.11 CEST by Szymon Stefanek
|
|
//
|
|
// This file is part of the KVirc irc client distribution
|
|
// Copyright (C) 2003 Szymon Stefanek (pragma at kvirc dot net)
|
|
//
|
|
// This program is FREE software. You can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License
|
|
// as published by the Free Software Foundation; either version 2
|
|
// of the License, or (at your opinion) any later version.
|
|
//
|
|
// This program is distributed in the HOPE that it will be USEFUL,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
// See the GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, write to the Free Software Foundation,
|
|
// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
//
|
|
//=============================================================================
|
|
|
|
#define __KVIRC__
|
|
|
|
|
|
#include "kvi_kvs_parser.h"
|
|
|
|
#include "kvi_kvs_treenode.h"
|
|
|
|
#include "kvi_kvs_report.h"
|
|
#include "kvi_kvs_kernel.h"
|
|
|
|
#include "kvi_kvs_parser_macros.h"
|
|
|
|
#include "kvi_locale.h"
|
|
|
|
|
|
/*
|
|
@doc: operators
|
|
@title:
|
|
Operators
|
|
@keyterms:
|
|
operator,operators,assignment,assign
|
|
@type:
|
|
language
|
|
@short:
|
|
Variable operators , assignments & co.
|
|
@body:
|
|
Operator constructs are commands just like the other ones.
|
|
All the operators work on local or global variables and dictionaries.[br]
|
|
The generic operator syntax is:[br]
|
|
[br]
|
|
[b]<left_operand> <operator> [right_operand][/b][br]
|
|
[br]
|
|
where <left_operand> and [right_operand] depend on the <operator>.[br]
|
|
Some operators have no [right_operand] and these are called [b]unary operators[/b]:
|
|
they operate directly on <left_operand>.[br]
|
|
|
|
[br]
|
|
[big]= (Assignment)[/big][br]
|
|
[br]
|
|
|
|
The assignment is the "plainest" of the binary operators: it works just like in any other programming language.[br]
|
|
[br]
|
|
If the <left_operand> is a variable, then the <right_operand> is assigned to it;
|
|
if the variable doesn't exists yet , it is created.[br]
|
|
If <right_operand> evaluates to an empty value then the variable is unset.[br]
|
|
[example]
|
|
[comment]# Assigning a constant to the global variable %Tmp[/comment]
|
|
%Tmp = 1
|
|
[comment]# Assigning a string constant to the global variable %Tmp[/comment]
|
|
%Tmp = some string
|
|
[comment]# Assigning a string constant to the local variable %tmp[/comment]
|
|
%tmp = "some string with whitespace preserved"
|
|
[comment]# Assigning a variable to another variable copies its contents[/comment]
|
|
%tmp = %somevariable
|
|
[comment]# Assigning a variable string to the global variable %Z[/comment]
|
|
%Z = my eyes are %color
|
|
[comment]# Assigning a variable string (with a function call inside) to the local variable %x[/comment]
|
|
%x = the system os is [fnc]$system.osname[/fnc]
|
|
[comment]# Assigning an empty string to the local variable %y unsets %y[/comment]
|
|
%y =
|
|
[comment]# This is equivalent to the above[/comment]
|
|
%y = ""
|
|
[comment]# This is equivalent too, if $function evalutates to an empty string[/comment]
|
|
%y = $function()
|
|
[/example]
|
|
[br]
|
|
If the <left_operand> is a dictionary/array entry, then the <right_operand> is assigned to it;
|
|
if the dictionary/array entry doesn't exist (or the whole dictionary/array doesn't exists) it is created.[br]
|
|
If <right_operand> evaluates to an empty value then the dictionary/array entry (and eventually the whole
|
|
dictionary/array, if there are no other entries) is unset.[br]
|
|
[example]
|
|
[comment]# Assigning a variable string to a global dictionary entry[/comment]
|
|
%Dict[key] = [fnc]$system.osname[/fnc]\ian
|
|
[comment]# Unsetting a local dictionary entry[/comment]
|
|
%mydict[23] = ""
|
|
[/example]
|
|
[br]
|
|
If the <left_operand> is an array reference then the semantics depend on the <right_operand> type.
|
|
If <right_operand> is an array reference then its contents are copied to the <left_operand>.[br]
|
|
If <right_operand> is a dictionary (keys) reference then its values are copied to to <left_operand>.[br]
|
|
If <right_operand> is a scalar then the value is assigned to every entry of <left_operand>.[br]
|
|
This is an easy way of unsetting a whole array: just assign an empty string.[br]
|
|
If the <left_operand> is a dictionary reference then the semantics depend on the <right_operand> type.
|
|
If <right_operand> is a dictionary reference then its contents are copied to the <left_operand>.[br]
|
|
If <right_operand> is an array reference then its contents are copied to to <left_operand> using
|
|
the array indexes as keys.[br]
|
|
If <right_operand> is a dictionary key reference then the keys are copied to the <left_operand>
|
|
using numeric indexes starting from 0 as keys.[br]
|
|
If <right_operand> is a scalar then the value is assigned to every key of <left_operand>.[br]
|
|
This is an easy way of unsetting a whole dictionary: just assign an empty string to all its keys.[br]
|
|
(If you play with huge dictionaries/arrays it might be a good idea to unset them when no longer needed)
|
|
[example]
|
|
[comment]# Assigning a dictionary to another: %mydict[] becomes a copy of %anotherdict[][/comment]
|
|
%mydict[] = %anotherdict[]
|
|
[comment]# %mydict[] gets the values of the dict returned by $features[/comment]
|
|
%mydict[] = [fnc]$features[/fnc]
|
|
[comment]# Assigning a string to ALL the keys of %mydict[/comment]
|
|
%mydict[] = "some default value"
|
|
[comment]# Unsetting a whole dictionary[/comment]
|
|
%mydict[] =
|
|
%AnotherGlobalDict[] = ""
|
|
[/example]
|
|
|
|
|
|
[br]
|
|
[big]=~ (Binding operator)[/big][br]
|
|
[br]
|
|
|
|
This operator is a really ugly, poor and clueless attempt to reach at least 1% of the
|
|
power of the perl =~ operator :D[br]
|
|
It allows some complex string operations to be performed efficently by operating directly
|
|
on the left operand (in fact this is a lot faster in KVIrc since at least one step of parsing is skipped).[br]
|
|
Its basic syntax is:[br]
|
|
[b]<left_operand> =~ <operation>[parameters][/b][br]
|
|
Where <operation> may be one of 't','s' and parameters depend on it.[br]
|
|
<left_operand> is the target of the <operation>.[br]
|
|
If <left_operand> is an array or dictionary, the <operation> is executed on each item they contain.[br]
|
|
Operation 't' is the transliteration.[br]
|
|
The complete syntax with parameters is:[br]
|
|
[b]<left_operand> =~ t/<search characters>/<replacement characters>/[/b][br]
|
|
where <search characters> is a string of characters that are replaced with the corresponding
|
|
characters in <replacement characters>.[br]
|
|
This operation can be also named 'y' or 'tr' (to preserve some compatibility with other languages).[br]
|
|
[example]
|
|
%A=This is a test string
|
|
echo %A
|
|
%A=~ tr/abcdefghi/ABCDEFGHI/
|
|
echo %A
|
|
[/example]
|
|
Operation 's' is the substitution.[br]
|
|
The complete syntax with parameters is:[br]
|
|
[b]<left_operand> =~ s/<search pattern>/<replacement pattern>/[flags][/b][br]
|
|
where <search pattern> is an extended regular expression to be matched in the <left_operand>
|
|
and <replacement string> is a special pattern that will replace any occurence found.[br]
|
|
<search pattern> may contain parentheses to capture parts of the matched text.
|
|
<replacement string> can contain the escape sequences \\N where N is a number between 1 and 9
|
|
to be replaced by the captured text.[br]
|
|
(We use \\N because KVIrc will first unquote the string when parsing...)[br]
|
|
\\0 is a special escape that will be replaced by the entire match (is always valid!).[br]
|
|
WARNING: the "capture-text" feature is not available if KVIrc has been compiled
|
|
with qt older than 3.0.0. You can find out if the feature is available by
|
|
looking for the string "TQt3" in the array returned by [fnc]$features[/fnc].[br]
|
|
[flags] may be a combination of the letters 'g','i' and 'w'.[br]
|
|
'g' causes the search to be global and not stop after the first occurence of <search pattern>.[br]
|
|
'i' causes the search to be case insensitive.[br]
|
|
'w' causes the search pattern to be interpreted as a simple wildcard regular expression.[br]
|
|
'm' causes the matching to be "minimal" instead of "greedy" (default). Greedy matches
|
|
find the longest possible match in the string while minimal (non-greedy) matches the shortest possible.[br]
|
|
[example]
|
|
%A=This is a test string
|
|
echo %A
|
|
%A=~ s/([a-z])i([a-z])/\\1I\\2/
|
|
echo %A
|
|
%A=~ s/([a-z])i([a-z])/\\1@\\2/gi
|
|
echo %A
|
|
[/example]
|
|
|
|
[br]
|
|
[big]X= (Arithmetic Self-operators)[/big][br]
|
|
[br]
|
|
|
|
The general syntax is:[br]
|
|
[b]<left_operand> <operation> <right_operand>[/b][br]
|
|
Where <left_operand> and <right_operand> must evaluate to numbers.[br]
|
|
All these operators perform the operation on <left_operand> and <right_operand> and then
|
|
store the result in <left_operand> (which therefore must be a variable, an array entry or a dictionary entry).[br]
|
|
<operation> may be one of:[br]
|
|
+= : sums the <right_operand> to <left_operand>[br]
|
|
-= : subtracts <right_operand> from <left_operand>[br]
|
|
*= : multiplies <left_operand> by <right_operand>[br]
|
|
%= : calculates <left_operand> modulus <right_operand>[br]
|
|
|= : calculates <left_operand> bitwise-or <right_operand>[br]
|
|
&= : calculates <left_operand> bitwise-and <right_operand>[br]
|
|
/= : divides <left_operand> by <right_operand>[br]
|
|
|
|
[br]
|
|
[big]++ and -- (Increment and Decrement)[/big][br]
|
|
[br]
|
|
|
|
These two operators work only on numeric operands.[br]
|
|
The general syntax is:[br]
|
|
[b]<left_operand> <operator>[/b][br]
|
|
There is no <right_operand>.[br]
|
|
++ increments <left_operand> by one, -- decrements <left_operand> by one.[br]
|
|
These are equivalent to += 1 and -= 1.[br]
|
|
|
|
[br]
|
|
[big].= , << , <+ , <, (String concatenation operators)[/big][br]
|
|
[br]
|
|
|
|
All these operators work also on whole arrays and dictionaries.[br]
|
|
Operator [b].=[/b] : APPENDS the <right_operand> to the <left_operand>[br]
|
|
Operator [b]<+[/b] is a synonim for .= (backward compatibility)[br]
|
|
Operator [b]<<[/b] : appends <right_operand> to <left_operand>
|
|
separating the two strings by a single space if and only if <left_operand> and <right_operand>
|
|
are non-empty.[br]
|
|
Operator [b]<,[/b] : is similar to '<<' ; appends , separating with a single ',' with the same condition.[br]
|
|
|
|
@examples:
|
|
First set the variable %var
|
|
[example]
|
|
%var = Ciao ciao
|
|
[/example]
|
|
Then append a nickname...
|
|
[example]
|
|
%var << Pragma
|
|
[/example]
|
|
%var now contains "Ciao ciao Pragma"[br]
|
|
Append a '!' character
|
|
[example]
|
|
%var <+ !
|
|
[/example]
|
|
%var now contains "Ciao ciao Pragma!"
|
|
Now reset it.
|
|
[example]
|
|
%var =
|
|
[/example]
|
|
Now %var is unset.[br]
|
|
Reset it with a comma separated list of items
|
|
[example]
|
|
%var = Pragma,Diabl0,Arter|o
|
|
%var <, MalboroLi
|
|
[/example]
|
|
%var now contains "Pragma,Diabl0,Arter|o,MalboroLi"[br]
|
|
[br]
|
|
Now a longer example.
|
|
[example]
|
|
%var = l
|
|
[cmd]echo[/cmd] It's name starts with the letter %var!
|
|
%var <+ inux
|
|
[cmd]echo[/cmd] Yes , it is %var!
|
|
%var << OS
|
|
[cmd]echo[/cmd] Use %var!
|
|
%var <, Mac OS
|
|
[cmd]echo[/cmd] There are two items in this list : %var
|
|
%var = [fnc]$strlen[/fnc](%var)
|
|
[cmd]echo[/cmd] And it is %var characters long (including the comma)
|
|
%var--
|
|
[cmd]echo[/cmd] Excluding the comma : %var
|
|
%var+=%var
|
|
[cmd]echo[/cmd] Now it is doubled : %var
|
|
%var =
|
|
[cmd]echo[/cmd] Now the var is unset (empty): (%var) !
|
|
[/example]
|
|
*/
|
|
|
|
|
|
KviKvsTreeNodeData * KviKvsParser::parseOperationRightSide(bool bPreferNumeric)
|
|
{
|
|
KviPointerList<KviKvsTreeNodeData> * l = new KviPointerList<KviKvsTreeNodeData>();
|
|
l->setAutoDelete(true);
|
|
|
|
const TQChar * pBegin = KVSP_curCharPointer;
|
|
|
|
for(;;)
|
|
{
|
|
switch(KVSP_curCharUnicode)
|
|
{
|
|
case 0:
|
|
goto end_of_the_param;
|
|
break;
|
|
case '\n':
|
|
case '\r':
|
|
case ';':
|
|
KVSP_skipChar;
|
|
goto end_of_the_param;
|
|
break;
|
|
case ' ':
|
|
case '\t':
|
|
skipSpaces();
|
|
if(KVSP_curCharIsEndOfCommand)
|
|
{
|
|
goto end_of_the_param;
|
|
} else {
|
|
// separate by single spaces
|
|
bPreferNumeric = false; // this can't be a number
|
|
l->append(new KviKvsTreeNodeConstantData(KVSP_curCharPointer,new KviKvsVariant(TQString(" "))));
|
|
}
|
|
break;
|
|
default:
|
|
// anything else is a parameter
|
|
KviKvsTreeNodeData * p = parseCommandParameter(bPreferNumeric);
|
|
if(!p)
|
|
{
|
|
// this is an error
|
|
delete l;
|
|
return 0;
|
|
}
|
|
l->append(p);
|
|
break;
|
|
}
|
|
}
|
|
|
|
end_of_the_param:
|
|
if(l->count() > 1)
|
|
{
|
|
// complex parameter needed
|
|
return new KviKvsTreeNodeCompositeData(pBegin,l);
|
|
} else {
|
|
if(l->count() > 0)
|
|
{
|
|
// a single parameter in the list
|
|
l->setAutoDelete(false);
|
|
KviKvsTreeNodeData * p = l->first();
|
|
delete l;
|
|
return p;
|
|
} else {
|
|
// empty (this should NEVER happen anyway)
|
|
delete l;
|
|
return new KviKvsTreeNodeConstantData(pBegin,new KviKvsVariant(TQString("")));
|
|
}
|
|
}
|
|
// never reached
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
@doc: assignment
|
|
@title:
|
|
Assignment operation
|
|
@keyterms:
|
|
assignment
|
|
@type:
|
|
language
|
|
@short:
|
|
Assignment operation
|
|
@body:
|
|
The assignment is the "plainest" of the operators: it works just like in any other programming language.[br]
|
|
The syntax is:[br]
|
|
[br]
|
|
[b]<target> = <source>[/b]
|
|
[br]
|
|
<target> must be a variable, <source> can be any parameter.[br]
|
|
If the <target> variable doesn't exist, it is created.
|
|
If it already exists, it is eventually converted to the type of <souce> (scalar, hash or array).[br]
|
|
If <source> evaluates to an empty value then the <target> variable is unset.[br]
|
|
[example]
|
|
[comment]# Assigning a constant to the variable %Tmp[/comment]
|
|
%Tmp = 1
|
|
[cmd]echo[/cmd] %Tmp
|
|
[comment]# Assigning a string constant to the variable %Tmp[/comment]
|
|
%Tmp = some string
|
|
[cmd]echo[/cmd] %Tmp
|
|
[comment]# Assigning a string constant to the variable %Tmp[/comment]
|
|
%Tmp = "some string with whitespace preserved"
|
|
[cmd]echo[/cmd] %Tmp
|
|
[comment]# Assigning a variable to another variable copies its contents[/comment]
|
|
%Someothervariable = "Contents"
|
|
%Tmp = %Someothervariable
|
|
[cmd]echo[/cmd] %Tmp
|
|
[comment]# Assigning a variable string to the variable %z[/comment]
|
|
%color = blue
|
|
%z = my eyes are %color
|
|
[cmd]echo[/cmd] %z
|
|
[comment]# Assigning a variable string (with a function call inside) to the variable %x[/comment]
|
|
%x = the system os is [fnc]$system.osname[/fnc]
|
|
[cmd]echo[/cmd] %x
|
|
[comment]# Assigning an empty string to the local variable %y unsets %y[/comment]
|
|
%x =
|
|
[cmd]echo[/cmd] %y
|
|
[comment]# This is equivalent to the above[/comment]
|
|
%y = ""
|
|
[comment]# This is equivalent too, if $function evalutates to an empty string[/comment]
|
|
%y = $function()
|
|
[comment]# Assigning a variable string to a hash entry[/comment]
|
|
%Dict{key} = [fnc]$system.osname[/fnc]\ian
|
|
[comment]# Unsetting an array entry[/comment]
|
|
%mydict[23] = ""
|
|
[comment]# Assigning a hash to another: %mydict[] becomes a copy of %anotherdict[][/comment]
|
|
%anotherdict{"The key"} = "Some dummy value"
|
|
%mydict = %anotherdict
|
|
[cmd]echo[/cmd]%mydict{"The key"}
|
|
[comment]# This will convert %mydict to be a scalar variable (deleting all the %mydict contents!)[/comment]
|
|
%mydict = "some default value"
|
|
[comment]# Unsetting a whole hash[/comment]
|
|
%anotherdict =
|
|
[/example]
|
|
[/p]
|
|
*/
|
|
|
|
|
|
/*
|
|
@doc: incrementdecrement
|
|
@title:
|
|
Increment and decrement operations
|
|
@keyterms:
|
|
increment, decrement
|
|
@type:
|
|
language
|
|
@short:
|
|
Increment and decrement operations
|
|
@body:
|
|
These two operators work only on numeric operands.[br]
|
|
The syntax is:[br]
|
|
[br]
|
|
[b]<target>++[/b][br]
|
|
[b]<target>--[/b][br]
|
|
[br]
|
|
++ increments <target> by one, -- decrements <target> by one.[br]
|
|
These are equivalent to += 1 and -= 1.[br]
|
|
<target> must be an existing variable and contain an integer value.[br]
|
|
If <target> contains a real value then the real is truncated to the nearest
|
|
integer and then incremented or decremented.[br]
|
|
@examples:
|
|
[example]
|
|
%a=10
|
|
[cmd]echo[/cmd] "Incrementing"
|
|
[cmd]while[/cmd](%a < 20)
|
|
{
|
|
[cmd]echo[/cmd] %a
|
|
[b]%a++[/b]
|
|
}
|
|
[cmd]echo[/cmd] "Decrementing"
|
|
[cmd]while[/cmd](%a > 10)
|
|
{
|
|
[cmd]echo[/cmd] %a
|
|
[b]%a--[/b]
|
|
}
|
|
[cmd]echo[/cmd] "Testing for loop"
|
|
[cmd]for[/cmd](%a=0;%a < 10;[b]%a++[/b])
|
|
{
|
|
[cmd]echo[/cmd] %a
|
|
}
|
|
[example]
|
|
@seealso:
|
|
[doc:operators]Operators[/doc]
|
|
*/
|
|
|
|
|
|
/*
|
|
@doc: selfarithmetic
|
|
@title:
|
|
Arithmetic self-operators
|
|
@type:
|
|
language
|
|
@short:
|
|
Arithmetic self-operators
|
|
@body:
|
|
These operators work only on numeric operands.[br]
|
|
The syntax is:[br]
|
|
[br]
|
|
[b]<target> += <right_operand>[/b][br]
|
|
[b]<target> -= <right_operand>[/b][br]
|
|
[b]<target> *= <right_operand>[/b][br]
|
|
[b]<target> /= <right_operand>[/b][br]
|
|
[b]<target> %= <right_operand>[/b][br]
|
|
[br]
|
|
<target> must be an existing variable and contain a numeric value.
|
|
<right_operand> must evaluate to a numeric value.
|
|
Note that if you want <right_operand> to be a result of an expression, you must
|
|
enclose it in the $(*) expression evaluation call.[br]
|
|
Operator += sums the <right_operand> value to the <target> value and stores the result in <target>.[br]
|
|
Operator -= subtracts <right_operand> from <target> and stores the result in <target>.[br]
|
|
Operator *= multiplies <target> by <right_operand> and stores the result in <target>.[br]
|
|
Operator /= divides <target> by <right_operand> and stores the result in <target>.[br]
|
|
Operator %= computes <target> modulus <right_operand> and stores the result in <target>.[br]
|
|
The division and modulus operators fail with an error if <right_operand> is 0.[br]
|
|
If both <target> and <right_operand> are integer values then the results of the division
|
|
and modulus are integers (truncated for the division).[br]
|
|
If <target> or <right_operand> or both are floating point values then the result is a floating point value.[br]
|
|
@examples:
|
|
[example]
|
|
%a=10
|
|
[cmd]echo[/cmd] %a
|
|
%a+=20
|
|
[cmd]echo[/cmd] %a
|
|
%a-=$(%a - 1)
|
|
[cmd]echo[/cmd] %a
|
|
%a *= 10
|
|
[cmd]echo[/cmd] %a
|
|
%a /= 21
|
|
[cmd]echo[/cmd] %a
|
|
%a *= 20
|
|
[cmd]echo[/cmd] %a
|
|
%a /= 21.0
|
|
[cmd]echo[/cmd] %a
|
|
%b = 10.0
|
|
%a %= %b
|
|
[cmd]echo[/cmd] %a
|
|
%a = 10
|
|
%b = 3
|
|
[comment]# nice trick[/comment]
|
|
%a /= %b.0
|
|
[cmd]echo[/cmd] %a
|
|
[example]
|
|
@seealso:
|
|
[doc:operators]Operators[/doc]
|
|
*/
|
|
|
|
|
|
/*
|
|
@doc: selfbitwise
|
|
@title:
|
|
Bitwise self-operators
|
|
@type:
|
|
language
|
|
@short:
|
|
Bitwise self-operators
|
|
@body:
|
|
These operators work only on integer operands.[br]
|
|
The syntax is:[br]
|
|
[br]
|
|
[b]<target> |= <right_operand>[/b][br]
|
|
[b]<target> &= <right_operand>[/b][br]
|
|
[b]<target> ^= <right_operand>[/b][br]
|
|
[b]<target> >>= <right_operand>[/b][br]
|
|
[b]<target> <<= <right_operand>[/b][br]
|
|
[br]
|
|
<target> must be an existing variable and contain a numeric value.
|
|
<right_operand> must evaluate to a numeric value.
|
|
If <target> or <right_operand> are floating point values then they are truncated
|
|
and converted to integers.[br]
|
|
Note that if you want <right_operand> to be a result of an expression, you must
|
|
enclose it in the $(*) expression evaluation call.[br]
|
|
Operator |= computes <target> bitwise-or <right_operand> and stores the result in <target>.[br]
|
|
Operator &= computes <target> bitwise-and <right_operand> and stores the result in <target>.[br]
|
|
Operator ^= computes <target> bitwise-xor <right_operand> and stores the result in <target>.[br]
|
|
Operator >>= shifts <target> <right_operand> bits to the right and stores the result int <target>.[br]
|
|
Operator <<= shifts <target> <right_operand> bits to the left and stores the result int <target>.[br]
|
|
Note that "!=" is not available. You must use %a = $(!%b) to implement it.[br]
|
|
For operators >>= and <<= <right_operand> must be a positive integer.[br]
|
|
@examples:
|
|
[example]
|
|
%a = 1
|
|
[cmd]echo[/cmd] %a
|
|
%a |= 2
|
|
[cmd]echo[/cmd] %a
|
|
%a &= 2
|
|
[cmd]echo[/cmd] %a
|
|
%a ^= 1
|
|
[cmd]echo[/cmd] %a
|
|
%a >>= 2
|
|
[cmd]echo[/cmd] %a
|
|
%a <<= 1
|
|
[cmd]echo[/cmd] %a
|
|
[example]
|
|
@seealso:
|
|
[doc:operators]Operators[/doc]
|
|
*/
|
|
|
|
|
|
/*
|
|
@doc: stringconcatenation
|
|
@title:
|
|
String concatenation operators
|
|
@type:
|
|
language
|
|
@short:
|
|
String concatenation operators
|
|
@body:
|
|
These operators concatenate strings.
|
|
The syntax is:[br]
|
|
[br]
|
|
[b]<target> .= <right_operand>[/b][br]
|
|
[b]<target> << <right_operand>[/b][br]
|
|
[b]<target> <, <right_operand>[/b][br]
|
|
[br]
|
|
Operator .= appends <right_operand> to <target>.
|
|
Operator << appends a space followed by <right_operand> to <target> if <target> is non empty,
|
|
otherwise sets <target> to <right_operand>.
|
|
Operator <, is similar to << but uses a comma to separate the two variable contents.
|
|
The last two operators are useful in creating space-separated or comma-separated lists.
|
|
@examples:
|
|
[example]
|
|
%a = ""
|
|
%a << free
|
|
[cmd]echo[/cmd] %a
|
|
%a .= bsd
|
|
[cmd]echo[/cmd] %a
|
|
%a << rox
|
|
[cmd]echo[/cmd] %a
|
|
%a <, but linux is better!
|
|
[cmd]echo[/cmd] %a
|
|
[example]
|
|
@seealso:
|
|
[doc:operators]Operators[/doc]
|
|
*/
|
|
|
|
|
|
/*
|
|
@doc: arrayconcatenation
|
|
@title:
|
|
Array concatenation operator
|
|
@type:
|
|
language
|
|
@short:
|
|
Array concatenation operator
|
|
@body:
|
|
This operator concatenates arrays
|
|
The syntax is:[br]
|
|
[br]
|
|
[b]<target> <+ <right_operand>[/b][br]
|
|
[br]
|
|
If <target> is not an array, it is converted to one first.
|
|
After that, if <right_operand> is a scalar then it is appended
|
|
to the end of the <target> array. If <right_operand> is an array
|
|
then all of its items are appended to the end of the <target> array.
|
|
If <right_operand> is a hash then all of its value items
|
|
are appended to the end of the <target> array.
|
|
@seealso:
|
|
[doc:operators]Operators[/doc]
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
@doc: binding
|
|
@title:
|
|
Binding operator
|
|
@type:
|
|
language
|
|
@short:
|
|
Binding operator
|
|
@body:
|
|
This operator is a really ugly, poor and clueless attempt to reach at least 1% of the
|
|
power of the perl =~ operator :D[br]
|
|
It allows some complex string operations to be performed efficently by operating directly
|
|
on the left operand (in fact this is a lot faster in KVIrc since at least one step of parsing is skipped).[br]
|
|
Its basic syntax is:[br]
|
|
[b]<left_operand> =~ <operation>[parameters][/b][br]
|
|
Where <operation> may be one of 't','s' and parameters depend on it.[br]
|
|
<left_operand> is the target of the <operation>.[br]
|
|
If <left_operand> is an array or dictionary, the <operation> is executed on each item they contain.[br]
|
|
Operation 't' is the transliteration.[br]
|
|
The complete syntax with parameters is:[br]
|
|
[b]<left_operand> =~ t/<search characters>/<replacement characters>/[/b][br]
|
|
where <search characters> is a string of characters that are replaced with the corresponding
|
|
characters in <replacement characters>.[br]
|
|
This operation can be also named 'y' or 'tr' (to preserve some compatibility with other languages).[br]
|
|
[example]
|
|
%A=This is a test string
|
|
echo %A
|
|
%A=~ tr/abcdefghi/ABCDEFGHI/
|
|
echo %A
|
|
[/example]
|
|
Operation 's' is the substitution.[br]
|
|
The complete syntax with parameters is:[br]
|
|
[b]<left_operand> =~ s/<search pattern>/<replacement pattern>/[flags][/b][br]
|
|
where <search pattern> is an extended regular expression to be matched in the <left_operand>
|
|
and <replacement string> is a special pattern that will replace any occurence found.[br]
|
|
<search pattern> may contain parentheses to capture parts of the matched text.
|
|
<replacement string> can contain the escape sequences \\N where N is a number between 1 and 9
|
|
to be replaced by the captured text.[br]
|
|
(We use \\N because KVIrc will first unquote the string when parsing...)[br]
|
|
\\0 is a special escape that will be replaced by the entire match (is always valid!).[br]
|
|
[flags] may be a combination of the letters 'g','i' and 'w'.[br]
|
|
'g' causes the search to be global and not stop after the first occurence of <search pattern>.[br]
|
|
'i' causes the search to be case insensitive.[br]
|
|
'w' causes the search pattern to be interpreted as a simple wildcard regular expression.[br]
|
|
[example]
|
|
%A=This is a test string
|
|
echo %A
|
|
%A=~ s/([a-z])i([a-z])/\\1I\\2/
|
|
echo %A
|
|
%A=~ s/([a-z])i([a-z])/\\1@\\2/gi
|
|
echo %A
|
|
[/example]
|
|
@examples:
|
|
[example]
|
|
%a = ""
|
|
%a << free
|
|
[cmd]echo[/cmd] %a
|
|
%a .= bsd
|
|
[cmd]echo[/cmd] %a
|
|
%a << rox
|
|
[cmd]echo[/cmd] %a
|
|
%a <, but linux is better!
|
|
[cmd]echo[/cmd] %a
|
|
[example]
|
|
@seealso:
|
|
[doc:operators]Operators[/doc]
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
@doc: operators
|
|
@title:
|
|
Operators
|
|
@keyterms:
|
|
operator,operators,assignment
|
|
@type:
|
|
language
|
|
@short:
|
|
Variable operators , assignments & co.
|
|
@body:
|
|
[p]
|
|
Operator constructs are commands just like the other ones.
|
|
All the operators work on local or global variables.[br]
|
|
The generic operator syntax is:[br]
|
|
[br]
|
|
[b]<left_operand> <operator> [right_operand][/b][br]
|
|
[br]
|
|
where <left_operand> is a variable and [right_operand] is a variable , a constant or a complex expression.[br]
|
|
Some operators do not use [right_operand] and do their job directly on <left_operand>[br]
|
|
[/p]
|
|
|
|
[table]
|
|
[tr][td]Operator[/td][td]document[/td][/td]
|
|
[tr][td]=[/td][td][doc:assignment]assignment operator[/doc][/td][/tr]
|
|
[tr][td]++[/td][td][doc:incrementdecrement]Increment and decrement operators[/doc][/td][/tr]
|
|
[tr][td]--[/td][td][doc:incrementdecrement]Increment and decrement operators[/doc][/td][/tr]
|
|
[tr][td]+=[/td][td][doc:selfarithmetic]Arithmetic self-operators[/doc][/td][/tr]
|
|
[tr][td]-=[/td][td][doc:selfarithmetic]Arithmetic self-operators[/doc][/td][/tr]
|
|
[tr][td]*=[/td][td][doc:selfarithmetic]Arithmetic self-operators[/doc][/td][/tr]
|
|
[tr][td]/=[/td][td][doc:selfarithmetic]Arithmetic self-operators[/doc][/td][/tr]
|
|
[tr][td]%=[/td][td][doc:selfarithmetic]Arithmetic self-operators[/doc][/td][/tr]
|
|
[tr][td]|=[/td][td][doc:selfbitwise]Bitwise self-operators[/doc][/td][/tr]
|
|
[tr][td]&=[/td][td][doc:selfbitwise]Bitwise self-operators[/doc][/td][/tr]
|
|
[tr][td]^=[/td][td][doc:selfbitwise]Bitwise self-operators[/doc][/td][/tr]
|
|
[tr][td]<<=[/td][td][doc:selfbitwise]Bitwise self-operators[/doc][/td][/tr]
|
|
[tr][td]>>=[/td][td][doc:selfbitwise]Bitwise self-operators[/doc][/td][/tr]
|
|
[tr][td].=[/td][td][doc:stringconcatenation]String concatenation operators[/doc][/td][/tr]
|
|
[tr][td]<<[/td][td][doc:stringconcatenation]String concatenation operators[/doc][/td][/tr]
|
|
[tr][td]<,[/td][td][doc:stringconcatenation]String concatenation operators[/doc][/td][/tr]
|
|
[tr][td]<+[/td][td][doc:arrayconcatenation]Array concatenation[/doc][/td][/tr]
|
|
[tr][td]=~[/td][td][doc:binding]Binding operator[/doc][/td][/tr]
|
|
[/table]
|
|
*/
|
|
|
|
KviKvsTreeNodeData * KviKvsParser::parseBindingOperationParameter()
|
|
{
|
|
KviPointerList<KviKvsTreeNodeData> * l = new KviPointerList<KviKvsTreeNodeData>;
|
|
l->setAutoDelete(true);
|
|
|
|
const TQChar * pBegin = KVSP_curCharPointer;
|
|
|
|
for(;;)
|
|
{
|
|
switch(KVSP_curCharUnicode)
|
|
{
|
|
case 0:
|
|
case '/':
|
|
case '\n':
|
|
case '\r':
|
|
// not a part of a parameter
|
|
goto end_of_function_parameter;
|
|
break;
|
|
case '$':
|
|
case '%':
|
|
{
|
|
// this may be a data reference
|
|
KviKvsTreeNodeData * p = parseParameterPercentOrDollar();
|
|
if(!p)
|
|
{
|
|
// this is an error
|
|
delete l;
|
|
return 0;
|
|
}
|
|
l->append(p);
|
|
}
|
|
break;
|
|
case '"':
|
|
{
|
|
// this is a string
|
|
KviKvsTreeNodeData * p = parseStringParameter();
|
|
if(!p)
|
|
{
|
|
// this is an error
|
|
delete l;
|
|
return 0;
|
|
}
|
|
l->append(p);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
// anything else is a literal
|
|
l->append(parseBindingOperationLiteralParameter());
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
end_of_function_parameter:
|
|
if(l->count() > 1)
|
|
{
|
|
// complex parameter needed
|
|
return new KviKvsTreeNodeCompositeData(pBegin,l);
|
|
} else {
|
|
// a single parameter in the list or empty list at all
|
|
l->setAutoDelete(false);
|
|
KviKvsTreeNodeData * p = l->first();
|
|
delete l;
|
|
if(!p)p = new KviKvsTreeNodeConstantData(KVSP_curCharPointer,new KviKvsVariant(TQString("")));
|
|
return p;
|
|
}
|
|
// never reached
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
KviKvsTreeNodeOperation * KviKvsParser::parseBindingOperation()
|
|
{
|
|
// t or tr or y
|
|
// s
|
|
const TQChar * pBegin = KVSP_curCharPointer;
|
|
|
|
while(KVSP_curCharIsLetter)KVSP_skipChar;
|
|
|
|
TQString szOp = TQString(pBegin,KVSP_curCharPointer - pBegin).lower();
|
|
|
|
skipSpaces();
|
|
|
|
if(KVSP_curCharUnicode != '/')
|
|
{
|
|
error(KVSP_curCharPointer,__tr2qs("Found character '%q' (unicode %x) where a slash '/' was expected"),KVSP_curCharPointer,KVSP_curCharUnicode);
|
|
return 0;
|
|
}
|
|
|
|
KVSP_skipChar;
|
|
|
|
KviKvsTreeNodeData * pFirst = parseBindingOperationParameter();
|
|
if(!pFirst)return 0;
|
|
|
|
if(KVSP_curCharIsEndOfCommand)
|
|
{
|
|
error(KVSP_curCharPointer,__tr2qs("Unexpected end of command in binding operation, at least two slashes are missing"));
|
|
delete pFirst;
|
|
return 0;
|
|
}
|
|
|
|
if(KVSP_curCharUnicode != '/')
|
|
{
|
|
error(KVSP_curCharPointer,__tr2qs("Found character '%q' (unicode %x) where a slash '/' was expected"),KVSP_curCharPointer,KVSP_curCharUnicode);
|
|
delete pFirst;
|
|
return 0;
|
|
}
|
|
|
|
KVSP_skipChar;
|
|
|
|
KviKvsTreeNodeData * pSecond = parseBindingOperationParameter();
|
|
if(!pSecond)
|
|
{
|
|
delete pFirst;
|
|
return 0;
|
|
}
|
|
|
|
if(KVSP_curCharIsEndOfCommand)
|
|
{
|
|
error(KVSP_curCharPointer,__tr2qs("Unexpected end of command in binding operation, at least one slash is missing"));
|
|
delete pFirst;
|
|
return 0;
|
|
}
|
|
|
|
if(KVSP_curCharUnicode != '/')
|
|
{
|
|
error(KVSP_curCharPointer,__tr2qs("Found character '%q' (unicode %x) where a slash '/' was expected"),KVSP_curCharPointer,KVSP_curCharUnicode);
|
|
delete pFirst;
|
|
return 0;
|
|
}
|
|
|
|
KVSP_skipChar;
|
|
|
|
KviKvsTreeNodeData * pThird = parseCommandParameter();
|
|
if(!pThird)
|
|
{
|
|
if(error())
|
|
{
|
|
delete pFirst;
|
|
delete pSecond;
|
|
return 0;
|
|
}
|
|
|
|
pThird = new KviKvsTreeNodeConstantData(KVSP_curCharPointer,new KviKvsVariant(TQString("")));
|
|
}
|
|
|
|
while(!KVSP_curCharIsEndOfCommand)KVSP_skipChar;
|
|
if(!KVSP_curCharIsEndOfBuffer)KVSP_skipChar;
|
|
|
|
if((szOp == "t") || (szOp == "tr") || (szOp == "y"))
|
|
{
|
|
// transliteration tr/szFirst/szSecond/szFlags
|
|
return new KviKvsTreeNodeOperationStringTransliteration(pBegin,pFirst,pSecond,pThird);
|
|
} else if(szOp == "s")
|
|
{
|
|
// regexp substitution s/szFirst/szSecond/szFlags
|
|
return new KviKvsTreeNodeOperationStringSubstitution(pBegin,pFirst,pSecond,pThird);
|
|
}
|
|
|
|
error(KVSP_curCharPointer,__tr2qs("Unknown binding operation '%Q'"),&szOp);
|
|
return 0;
|
|
}
|
|
|
|
|
|
KviKvsTreeNodeOperation * KviKvsParser::parseOperation()
|
|
{
|
|
// find the operator
|
|
const TQChar * pBegin = KVSP_curCharPointer;
|
|
|
|
switch(KVSP_curCharUnicode)
|
|
{
|
|
case '=':
|
|
{
|
|
KVSP_skipChar;
|
|
if(KVSP_curCharUnicode == '~')
|
|
{
|
|
KVSP_skipChar;
|
|
skipSpaces();
|
|
if(KVSP_curCharIsEndOfCommand)
|
|
{
|
|
error(KVSP_curCharPointer,__tr2qs("Missing right side operand for the binding operator '=~'"));
|
|
return 0;
|
|
}
|
|
return parseBindingOperation();
|
|
} else {
|
|
skipSpaces();
|
|
KviKvsTreeNodeData * d = parseOperationRightSide(true);
|
|
if(!d)return 0; // error
|
|
return new KviKvsTreeNodeOperationAssignment(pBegin,d);
|
|
}
|
|
}
|
|
break;
|
|
case '+':
|
|
KVSP_skipChar;
|
|
switch(KVSP_curCharUnicode)
|
|
{
|
|
case '+':
|
|
// operator ++
|
|
KVSP_skipChar;
|
|
skipSpaces();
|
|
if(!KVSP_curCharIsEndOfCommand)
|
|
{
|
|
warning(KVSP_curCharPointer,__tr2qs("Trailing garbage ignored after operator '++'"));
|
|
}
|
|
while(!KVSP_curCharIsEndOfCommand)KVSP_skipChar;
|
|
if(!KVSP_curCharIsEndOfBuffer)KVSP_skipChar;
|
|
return new KviKvsTreeNodeOperationIncrement(pBegin);
|
|
break;
|
|
case '=':
|
|
// operator +=
|
|
KVSP_skipChar;
|
|
skipSpaces();
|
|
if(KVSP_curCharIsEndOfCommand)
|
|
{
|
|
error(KVSP_curCharPointer,__tr2qs("Missing right operand for operator '+='"));
|
|
return 0;
|
|
}
|
|
KviKvsTreeNodeData * d = parseOperationRightSide(true);
|
|
if(!d)return 0; // error
|
|
return new KviKvsTreeNodeOperationSelfSum(pBegin,d);
|
|
break;
|
|
}
|
|
break;
|
|
case '-':
|
|
KVSP_skipChar;
|
|
switch(KVSP_curCharUnicode)
|
|
{
|
|
case '-':
|
|
KVSP_skipChar;
|
|
// operator --
|
|
skipSpaces();
|
|
if(!KVSP_curCharIsEndOfCommand)
|
|
{
|
|
warning(KVSP_curCharPointer,__tr2qs("Trailing garbage ignored after operator '--'"));
|
|
}
|
|
while(!KVSP_curCharIsEndOfCommand)KVSP_skipChar;
|
|
if(!KVSP_curCharIsEndOfBuffer)KVSP_skipChar;
|
|
return new KviKvsTreeNodeOperationDecrement(pBegin);
|
|
break;
|
|
case '>':
|
|
warning(KVSP_curCharPointer,__tr2qs("This looks a lot like an object handle dereferencing operator '->' but in fact it isn't. Maybe you forgot a '$' just after ?"));
|
|
break;
|
|
case '=':
|
|
// operator -=
|
|
KVSP_skipChar;
|
|
skipSpaces();
|
|
if(KVSP_curCharIsEndOfCommand)
|
|
{
|
|
error(KVSP_curCharPointer,__tr2qs("Missing right operand for operator '-='"));
|
|
return 0;
|
|
}
|
|
KviKvsTreeNodeData * d = parseOperationRightSide(true);
|
|
if(!d)return 0; // error
|
|
return new KviKvsTreeNodeOperationSelfSubtraction(pBegin,d);
|
|
break;
|
|
}
|
|
break;
|
|
case '<':
|
|
KVSP_skipChar;
|
|
switch(KVSP_curCharUnicode)
|
|
{
|
|
case '<':
|
|
KVSP_skipChar;
|
|
if(KVSP_curCharUnicode == '=')
|
|
{
|
|
KVSP_skipChar;
|
|
skipSpaces();
|
|
if(KVSP_curCharIsEndOfCommand)
|
|
{
|
|
error(KVSP_curCharPointer,__tr2qs("Missing right operand for operator '<<='"));
|
|
return 0;
|
|
}
|
|
KviKvsTreeNodeData * d = parseOperationRightSide(true);
|
|
if(!d)return 0; // error
|
|
return new KviKvsTreeNodeOperationSelfShl(pBegin,d);
|
|
} else {
|
|
skipSpaces();
|
|
if(KVSP_curCharIsEndOfCommand)
|
|
{
|
|
error(KVSP_curCharPointer,__tr2qs("Missing right operand for operator '<<'"));
|
|
return 0;
|
|
}
|
|
KviKvsTreeNodeData * d = parseOperationRightSide();
|
|
if(!d)return 0; // error
|
|
return new KviKvsTreeNodeOperationStringAppendWithSpace(pBegin,d);
|
|
}
|
|
break;
|
|
case ',':
|
|
{
|
|
KVSP_skipChar;
|
|
skipSpaces();
|
|
if(KVSP_curCharIsEndOfCommand)
|
|
{
|
|
error(KVSP_curCharPointer,__tr2qs("Missing right operand for operator '<,'"));
|
|
return 0;
|
|
}
|
|
KviKvsTreeNodeData * d = parseOperationRightSide();
|
|
if(!d)return 0; // error
|
|
return new KviKvsTreeNodeOperationStringAppendWithComma(pBegin,d);
|
|
}
|
|
break;
|
|
case '+':
|
|
{
|
|
KVSP_skipChar;
|
|
skipSpaces();
|
|
if(KVSP_curCharIsEndOfCommand)
|
|
{
|
|
error(KVSP_curCharPointer,__tr2qs("Missing right operand for operator '<+'"));
|
|
return 0;
|
|
}
|
|
KviKvsTreeNodeData * d = parseOperationRightSide();
|
|
if(!d)return 0; // error
|
|
return new KviKvsTreeNodeOperationArrayAppend(pBegin,d);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case '>':
|
|
KVSP_skipChar;
|
|
switch(KVSP_curCharUnicode)
|
|
{
|
|
case '>':
|
|
KVSP_skipChar;
|
|
if(KVSP_curCharUnicode == '=')
|
|
{
|
|
KVSP_skipChar;
|
|
skipSpaces();
|
|
if(KVSP_curCharIsEndOfCommand)
|
|
{
|
|
error(KVSP_curCharPointer,__tr2qs("Missing right operand for operator '>>='"));
|
|
return 0;
|
|
}
|
|
KviKvsTreeNodeData * d = parseOperationRightSide(true);
|
|
if(!d)return 0; // error
|
|
return new KviKvsTreeNodeOperationSelfShr(pBegin,d);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case '.':
|
|
KVSP_skipChar;
|
|
switch(KVSP_curCharUnicode)
|
|
{
|
|
case '=':
|
|
KVSP_skipChar;
|
|
skipSpaces();
|
|
if(KVSP_curCharIsEndOfCommand)
|
|
{
|
|
error(KVSP_curCharPointer,__tr2qs("Missing right operand for operator '.='"));
|
|
return 0;
|
|
}
|
|
KviKvsTreeNodeData * d = parseOperationRightSide();
|
|
if(!d)return 0; // error
|
|
return new KviKvsTreeNodeOperationStringAppend(pBegin,d);
|
|
break;
|
|
}
|
|
break;
|
|
#define SELF_OPERATOR(__opchar,__opstr,__class) \
|
|
case __opchar: \
|
|
KVSP_skipChar; \
|
|
switch(KVSP_curCharUnicode) \
|
|
{ \
|
|
case '=': \
|
|
KVSP_skipChar; \
|
|
skipSpaces(); \
|
|
if(KVSP_curCharIsEndOfCommand) \
|
|
{ \
|
|
error(KVSP_curCharPointer,__tr2qs("Missing right operand for operator '" __opstr "='")); \
|
|
return 0; \
|
|
} \
|
|
KviKvsTreeNodeData * d = parseOperationRightSide(true); \
|
|
if(!d)return 0; \
|
|
return new __class(pBegin,d); \
|
|
break; \
|
|
} \
|
|
break;
|
|
SELF_OPERATOR('*',"*",KviKvsTreeNodeOperationSelfMultiplication)
|
|
SELF_OPERATOR('/',"/",KviKvsTreeNodeOperationSelfDivision)
|
|
SELF_OPERATOR('%',"%",KviKvsTreeNodeOperationSelfModulus)
|
|
SELF_OPERATOR('|',"|",KviKvsTreeNodeOperationSelfOr)
|
|
SELF_OPERATOR('&',"&",KviKvsTreeNodeOperationSelfAnd)
|
|
SELF_OPERATOR('^',"^",KviKvsTreeNodeOperationSelfXor)
|
|
}
|
|
|
|
error(pBegin,__tr2qs("Unknown operator"));
|
|
return 0;
|
|
}
|
|
|
|
KviKvsTreeNodeInstruction * KviKvsParser::parseVoidFunctionCallOrOperation()
|
|
{
|
|
KVSP_ASSERT((KVSP_curCharUnicode == '$') || (KVSP_curCharUnicode == '%') || (KVSP_curCharUnicode == '@'));
|
|
|
|
const TQChar * pBegin = KVSP_curCharPointer;
|
|
|
|
KviKvsTreeNodeData * r = parsePercentOrDollar();
|
|
|
|
if(!r)
|
|
{
|
|
// must be an error
|
|
return 0;
|
|
}
|
|
|
|
skipSpaces();
|
|
|
|
if(KVSP_curCharIsEndOfCommand)
|
|
{
|
|
// the end of the command
|
|
if(!r->isFunctionCall())
|
|
{
|
|
if(r->isReadOnly())
|
|
{
|
|
warning(pBegin,__tr2qs("Unexpected (and senseless) read-only data evaluation"));
|
|
error(KVSP_curCharPointer,__tr2qs("Syntax error: confused by earlier errors: bailing out"));
|
|
} else {
|
|
error(KVSP_curCharPointer,__tr2qs("Unexpected end of script after a variable reference: expected operator"));
|
|
}
|
|
delete r;
|
|
return 0;
|
|
} else {
|
|
if(!KVSP_curCharIsEndOfBuffer)KVSP_skipChar;
|
|
return new KviKvsTreeNodeVoidFunctionCall(r->location(),(KviKvsTreeNodeFunctionCall *)r);
|
|
}
|
|
}
|
|
|
|
// not the end of a command : an operation
|
|
if(r->isReadOnly())
|
|
{
|
|
// must be followed by the end of a command
|
|
if(r->isFunctionCall())
|
|
{
|
|
error(KVSP_curCharPointer,__tr2qs("Unexpected character '%q' (unicode %x) after a void function call: end of instruction expected"),KVSP_curCharPointer,KVSP_curCharUnicode);
|
|
} else {
|
|
warning(pBegin,__tr2qs("Unexpected (and senseless) read-only data evaluation"));
|
|
warning(pBegin,__tr2qs("Unexpected character '%q' (unicode %x)"),KVSP_curCharPointer,KVSP_curCharUnicode);
|
|
error(KVSP_curCharPointer,__tr2qs("Syntax error: confused by earlier errors: bailing out"));
|
|
}
|
|
delete r;
|
|
return 0;
|
|
}
|
|
|
|
// ok.. parse the operation
|
|
KviKvsTreeNodeOperation * op = parseOperation();
|
|
if(!op)
|
|
{
|
|
delete r;
|
|
return 0;
|
|
}
|
|
|
|
op->setTargetVariableReference(r);
|
|
return op;
|
|
}
|