Blame | Last modification | View Log | RSS feed
/** MS-DOS SHELL - Maths Evaluation Functions** MS-DOS SHELL - Copyright (c) 1990,4 Data Logic Limited and Paul Falstad** This code is based on (in part) the shell program written by Paul Falstad* and is subject to the following copyright restrictions:** 1. Redistribution and use in source and binary forms are permitted* provided that the above copyright notice is duplicated in the* source form and the copyright notice in file sh6.c is displayed* on entry to the program.** 2. The sources (or parts thereof) or objects generated from the sources* (or parts of sources) cannot be sold under any circumstances.** This source is based on the math.c (mathematical expression evaluation) from* the Z shell. Z Shell is free software, under the GNU license. This* code is included in this program under the provisions of paragraph 8 of* GNU GENERAL PUBLIC LICENSE, Version 1, February 1989. I contacted Paul* via E-Mail, and he is happy to allow the source to be included in this* program.** $Header: /cvsroot/device/DEVL/UTILS/SH/SH11.C,v 1.1 2002/08/02 06:49:32 adamy Exp $** $Log: SH11.C,v $* Revision 1.1 2002/08/02 06:49:32 adamy* imported (reference only)** Revision 1.1 2001/07/20 05:55:42 ayoung* WIN32 support** Revision 1.1.1.1 1999/12/02 01:11:12 gordonh* UTIL** Revision 2.10 1994/08/25 20:49:11 istewart* MS Shell 2.3 Release** Revision 2.9 1994/02/01 10:25:20 istewart* Release 2.3 Beta 2, including first NT port** Revision 2.8 1993/11/09 10:39:49 istewart* Beta 226 checking** Revision 2.7 1993/07/02 10:21:35 istewart* 224 Beta fixes** Revision 2.7 1993/07/02 10:21:35 istewart* 224 Beta fixes** Revision 2.6 1993/06/14 11:01:44 istewart* More changes for 223 beta** Revision 2.5 1993/06/02 09:52:35 istewart* Beta 223 Updates - see Notes file** Revision 2.4 1993/02/16 16:03:15 istewart* Beta 2.22 Release** Revision 2.3 1993/01/26 18:35:09 istewart* Release 2.2 beta 0** Revision 2.2 1992/11/06 10:03:44 istewart* 214 Beta test updates** Revision 2.1 1992/07/10 10:52:48 istewart* 211 Beta updates** Revision 2.0 1992/04/13 17:39:09 Ian_Stewartson* MS-Shell 2.0 Baseline release**/#include <sys/types.h>#include <sys/stat.h>#include <stdio.h>#include <signal.h>#include <setjmp.h>#include <ctype.h>#include <string.h>#include <unistd.h>#include <stdlib.h>#include <limits.h>#include "sh.h"#define STACK_SIZE 100 /* Stack size */#define MAX_PRECEDENCE 15#define MAX_VARIABLES 32 /* Number of user variables *//** Some macros*/#define POP_2_VALUES() b = stack[StackPointer--].val; \a = stack[StackPointer--].val;#define PUSH_VALUE_ON_STACK(X) PushOnToStack ((long)(X), -1);#define SET_VALUE_ON_STACK(X) PushOnToStack (SetVariableValue \(lv, (long)(X)), lv);/* the value stack */static int LastToken; /* Last token */static int StackPointer = -1; /* Stack pointer */static struct MathsStack {int lval;long val;} stack[STACK_SIZE];static int NumberOfVariables = 0; /* Number of variables */static char *ListOfVariableNames[MAX_VARIABLES];static char *CStringp; /* Current position */static long YYLongValue;static int YYIntValue;static int JustParsing = 0; /* Nonzero means we are *//* not evaluating, just *//* parsing */static bool RecogniseUnaryOperator = TRUE; /* TRUE means recognize *//* unary plus, minus, *//* etc. *//** LEFT_RIGHT_A = left-to-right associativity* RIGHT_LEFT_A = right-to-left associativity* BOOL_A = short-circuiting boolean*/#define LEFT_RIGHT_A 0#define RIGHT_LEFT_A 1#define BOOL_A 2#define OP_OPEN_PAR 0#define OP_CLOSE_PAR 1#define OP_NOT 2#define OP_COMPLEMENT 3#define OP_POST_PLUS 4#define OP_POST_MINUS 5#define OP_UNARY_PLUS 6#define OP_UNARY_MINUS 7#define OP_BINARY_AND_EQUALS 8#define OP_BINARY_XOR_EQUALS 9#define OP_BINARY_OR_EQUALS 10#define OP_MULTIPLY 11#define OP_DIVIDE 12#define OP_MODULUS 13#define OP_PLUS 14#define OP_MINUS 15#define OP_SHIFT_LEFT 16#define OP_SHIFT_RIGHT 17#define OP_LESS 18#define OP_LESS_EQUALS 19#define OP_GREATER 20#define OP_GREATER_EQUALS 21#define OP_EQUALS 22#define OP_NOT_EQUALS 23#define OP_LOGICAL_AND_EQUALS 24#define OP_LOGICAL_OR_EQUALS 25#define OP_LOGICAL_XOR_EQUALS 26#define OP_QUESTION_MARK 27#define OP_COLON 28#define OP_SET 29#define OP_PLUS_EQUAL 30#define OP_MINUS_EQUAL 31#define OP_MULTIPLY_EQUAL 32#define OP_DIVIDE_EQUAL 33#define OP_MODULUS_EQUAL 34#define OP_BINARY_AND_SET 35#define OP_BINARY_XOR_SET 36#define OP_BINARY_OR_SET 37#define OP_SHIFT_LEFT_EQUAL 38#define OP_SHIFT_RIGHT_EQUAL 39#define OP_LOGICAL_AND_SET 40#define OP_LOGICAL_OR_SET 41#define OP_LOGICAL_XOR_SET 42#define OP_COMMA 43#define OP_END_OF_INPUT 44#define OP_PRE_PLUS 45#define OP_PRE_MINUS 46#define OP_NUMERIC_VALUE 47#define OP_VARIABLE 48#define MAX_OPERATORS 49/* precedences */static struct Operators {int Precedences; /* Operator Precedences */int Type; /* Operator Association */} Operators [MAX_OPERATORS] = {{ 1, LEFT_RIGHT_A }, /* 0 - ( */{ 137, LEFT_RIGHT_A }, /* 1 - ) */{ 2, RIGHT_LEFT_A }, /* 2 - ! */{ 2, RIGHT_LEFT_A }, /* 3 - ~ */{ 2, RIGHT_LEFT_A }, /* 4 - x++ */{ 2, RIGHT_LEFT_A }, /* 5 - x-- */{ 2, RIGHT_LEFT_A }, /* 6 - + */{ 2, RIGHT_LEFT_A }, /* 7 - - */{ 4, LEFT_RIGHT_A }, /* 8 - & */{ 5, LEFT_RIGHT_A }, /* 9 - ^ */{ 6, LEFT_RIGHT_A }, /* 10 - | */{ 7, LEFT_RIGHT_A }, /* 11 - * */{ 7, LEFT_RIGHT_A }, /* 12 - / */{ 7, LEFT_RIGHT_A }, /* 13 - % */{ 8, LEFT_RIGHT_A }, /* 14 - + */{ 8, LEFT_RIGHT_A }, /* 15 - - */{ 3, LEFT_RIGHT_A }, /* 16 - < */{ 3, LEFT_RIGHT_A }, /* 17 - > */{ 9, LEFT_RIGHT_A }, /* 18 - < (less than) */{ 9, LEFT_RIGHT_A }, /* 19 - <= (less than equal) */{ 9, LEFT_RIGHT_A }, /* 20 - > (greater than) */{ 9, LEFT_RIGHT_A }, /* 21 - >= (greater than equal) */{ 10, LEFT_RIGHT_A }, /* 22 - == */{ 10, LEFT_RIGHT_A }, /* 23 - != */{ 11, BOOL_A }, /* 24 - && */{ 12, BOOL_A }, /* 25 - || */{ 12, LEFT_RIGHT_A }, /* 26 - ^^ */{ 13, RIGHT_LEFT_A }, /* 27 - ? */{ 13, RIGHT_LEFT_A }, /* 28 - : */{ 14, RIGHT_LEFT_A }, /* 29 - = */{ 14, RIGHT_LEFT_A }, /* 30 - += */{ 14, RIGHT_LEFT_A }, /* 31 - -= */{ 14, RIGHT_LEFT_A }, /* 32 - *= */{ 14, RIGHT_LEFT_A }, /* 33 - /= */{ 14, RIGHT_LEFT_A }, /* 34 - %= */{ 14, RIGHT_LEFT_A }, /* 35 - &= */{ 14, RIGHT_LEFT_A }, /* 36 - ^= */{ 14, RIGHT_LEFT_A }, /* 37 - |= */{ 14, RIGHT_LEFT_A }, /* 38 - <= */{ 14, RIGHT_LEFT_A }, /* 39 - >= */{ 14, BOOL_A }, /* 40 - &&= */{ 14, BOOL_A }, /* 41 - ||= */{ 14, RIGHT_LEFT_A }, /* 42 - ^^= */{ 15, RIGHT_LEFT_A }, /* 43 - , */{ 200, RIGHT_LEFT_A }, /* 44 - End of input */{ 2, RIGHT_LEFT_A }, /* 45 - ++x */{ 2, RIGHT_LEFT_A }, /* 46 - --x */{ 0, LEFT_RIGHT_A }, /* 47 - Numeric value */{ 0, LEFT_RIGHT_A } /* 48 - Variable */};/** Functions*/static void F_LOCAL PushOnToStack (long, int);static long F_LOCAL SetVariableValue (int, long);static bool F_LOCAL CheckNotZero (long);static void F_LOCAL ProcessOperator (int);static void F_LOCAL ProcessBinaryOperator (int);static void F_LOCAL ParseMathsExpression (int);static int F_LOCAL MathsLexicalAnalyser (void);static int F_LOCAL DecideSingleOperator (int, int);static int F_LOCAL DecideDoubleOperator (char, int, int, int, int);static int F_LOCAL DecideSignOperator (char, int, int, int, int, int);static char * F_LOCAL ExtractNameAndIndex (int, int *);/** Analyse the string*/static int F_LOCAL MathsLexicalAnalyser (void){while (TRUE){switch (*(CStringp++)){case '+':return DecideSignOperator ('+', OP_PRE_PLUS,OP_POST_PLUS,OP_PLUS_EQUAL,OP_UNARY_PLUS,OP_PLUS);case '-':return DecideSignOperator ('+', OP_PRE_MINUS,OP_POST_MINUS,OP_MINUS_EQUAL,OP_UNARY_MINUS,OP_MINUS);case CHAR_OPEN_PARATHENSIS:RecogniseUnaryOperator = TRUE;return OP_OPEN_PAR;case CHAR_CLOSE_PARATHENSIS:return OP_CLOSE_PAR;case '!':if (*CStringp == '='){RecogniseUnaryOperator = TRUE;CStringp++;return OP_NOT_EQUALS;}return OP_NOT;case CHAR_TILDE:return OP_COMPLEMENT;case '&':return DecideDoubleOperator ('&', OP_LOGICAL_AND_SET,OP_BINARY_AND_SET,OP_LOGICAL_AND_EQUALS,OP_BINARY_AND_EQUALS);case '|':return DecideDoubleOperator ('|', OP_LOGICAL_OR_SET,OP_BINARY_OR_SET,OP_LOGICAL_OR_EQUALS,OP_BINARY_OR_EQUALS);case CHAR_XOR:return DecideDoubleOperator (CHAR_XOR, OP_LOGICAL_XOR_SET,OP_BINARY_XOR_SET,OP_LOGICAL_XOR_EQUALS,OP_BINARY_XOR_EQUALS);case '*':return DecideSingleOperator (OP_MULTIPLY_EQUAL, OP_MULTIPLY);case '/':return DecideSingleOperator (OP_DIVIDE_EQUAL, OP_DIVIDE);case '%':return DecideSingleOperator (OP_MODULUS_EQUAL, OP_MODULUS);case '<':return DecideDoubleOperator ('<', OP_SHIFT_LEFT_EQUAL,OP_LESS_EQUALS,OP_SHIFT_LEFT,OP_LESS);case '>':return DecideDoubleOperator ('>', OP_SHIFT_RIGHT_EQUAL,OP_GREATER_EQUALS,OP_SHIFT_RIGHT,OP_GREATER);case CHAR_ASSIGN:return DecideSingleOperator (OP_EQUALS, OP_SET);case '?':RecogniseUnaryOperator = TRUE;return OP_QUESTION_MARK;case ':':RecogniseUnaryOperator = TRUE;return OP_COLON;case ',':RecogniseUnaryOperator = TRUE;return OP_COMMA;case 0:RecogniseUnaryOperator = TRUE;CStringp--;return OP_END_OF_INPUT;default:if (isspace (*(CStringp - 1)))break;/* Check for a numeric value */if (isdigit (*--CStringp)){char *End;int base = 10;RecogniseUnaryOperator = FALSE;/* Which format are we in? base#number or number. Base is a decimal number* so we can check for a decimal base and look at the end character to see* if it was a # sign. If it was, this is a base#number. Otherwise, its* just a number*/strtol (CStringp, &End, 10);if (*End == '#'){LastNumberBase = (int)strtol (CStringp, &CStringp, 10);base = LastNumberBase;CStringp++;}YYLongValue = strtol (CStringp, &CStringp, base);return OP_NUMERIC_VALUE;}/* Check for a variable */if (IS_VariableFC ((int)*CStringp)){char *p, q;char *eb;p = CStringp;if (NumberOfVariables == MAX_VARIABLES){ShellErrorMessage ("too many identifiers");ExpansionErrorDetected = TRUE;return OP_END_OF_INPUT;}RecogniseUnaryOperator = FALSE;while (IS_VariableSC ((int)(*++CStringp)))continue;/* Save the variable name. Check for array index and skip over. */if ((*CStringp == CHAR_OPEN_BRACKETS) &&((eb = strchr (CStringp,CHAR_CLOSE_BRACKETS)) != (char *)NULL))CStringp = eb + 1;/* Save the string */q = *CStringp;*CStringp = 0;ListOfVariableNames[YYIntValue = NumberOfVariables++] =StringCopy (p);*CStringp = q;return OP_VARIABLE;}return OP_END_OF_INPUT;}}}/** Stick variable on the stack*/static void F_LOCAL PushOnToStack (long val, int lval){if (StackPointer == STACK_SIZE - 1){ShellErrorMessage ("stack overflow");ExpansionErrorDetected = TRUE;}elseStackPointer++;stack[StackPointer].val = val;stack[StackPointer].lval = lval;}/** Get a variable value*/static long F_LOCAL SetVariableValue (int s, long v){char *vn;int index;if (s == -1 || s >= NumberOfVariables){ExpansionErrorDetected = TRUE;ShellErrorMessage ("lvalue required");return 0;}if (JustParsing)return v;vn = ExtractNameAndIndex (s, &index);SetVariableArrayFromNumeric (vn, index, v);return v;}/** Check for Division by zero*/static bool F_LOCAL CheckNotZero (long a){if (a)return TRUE;ShellErrorMessage ("division by zero");ExpansionErrorDetected = TRUE;return FALSE;}/** Process operator*/static void F_LOCAL ProcessOperator (int what){long a, b, c;int lv;if (StackPointer < 0){ShellErrorMessage ("bad math expression - stack empty");ExpansionErrorDetected = TRUE;return;}switch (what){case OP_NOT:stack[StackPointer].val = !stack[StackPointer].val;stack[StackPointer].lval= -1;break;case OP_COMPLEMENT:stack[StackPointer].val = ~stack[StackPointer].val;stack[StackPointer].lval= -1;break;case OP_POST_PLUS:SetVariableValue (stack[StackPointer].lval,stack[StackPointer].val + 1);break;case OP_POST_MINUS:SetVariableValue (stack[StackPointer].lval,stack[StackPointer].val - 1);break;case OP_UNARY_PLUS:stack[StackPointer].lval= -1;break;case OP_UNARY_MINUS:stack[StackPointer].val = -stack[StackPointer].val;stack[StackPointer].lval= -1;break;case OP_BINARY_AND_EQUALS:POP_2_VALUES ();PUSH_VALUE_ON_STACK (a & b);break;case OP_BINARY_XOR_EQUALS:POP_2_VALUES ();PUSH_VALUE_ON_STACK (a ^ b);break;case OP_BINARY_OR_EQUALS:POP_2_VALUES ();PUSH_VALUE_ON_STACK (a | b);break;case OP_MULTIPLY:POP_2_VALUES ();PUSH_VALUE_ON_STACK (a * b);break;case OP_DIVIDE:POP_2_VALUES ();if (CheckNotZero (b))PUSH_VALUE_ON_STACK (a / b);break;case OP_MODULUS:POP_2_VALUES ();if (CheckNotZero (b))PUSH_VALUE_ON_STACK (a % b);break;case OP_PLUS:POP_2_VALUES ();PUSH_VALUE_ON_STACK (a + b);break;case OP_MINUS:POP_2_VALUES ();PUSH_VALUE_ON_STACK (a - b);break;case OP_SHIFT_LEFT:POP_2_VALUES ();PUSH_VALUE_ON_STACK (a << b);break;case OP_SHIFT_RIGHT:POP_2_VALUES ();PUSH_VALUE_ON_STACK (a >> b);break;case OP_LESS:POP_2_VALUES ();PUSH_VALUE_ON_STACK (a < b);break;case OP_LESS_EQUALS:POP_2_VALUES ();PUSH_VALUE_ON_STACK (a <= b);break;case OP_GREATER:POP_2_VALUES ();PUSH_VALUE_ON_STACK (a > b);break;case OP_GREATER_EQUALS:POP_2_VALUES ();PUSH_VALUE_ON_STACK (a >= b);break;case OP_EQUALS:POP_2_VALUES ();PUSH_VALUE_ON_STACK (a == b);break;case OP_NOT_EQUALS:POP_2_VALUES ();PUSH_VALUE_ON_STACK (a != b);break;case OP_LOGICAL_AND_EQUALS:POP_2_VALUES ();PUSH_VALUE_ON_STACK (a && b);break;case OP_LOGICAL_OR_EQUALS:POP_2_VALUES ();PUSH_VALUE_ON_STACK (a || b);break;case OP_LOGICAL_XOR_EQUALS:POP_2_VALUES ();PUSH_VALUE_ON_STACK ((a && !b) || (!a && b));break;case OP_QUESTION_MARK:c = stack[StackPointer--].val;POP_2_VALUES ();PUSH_VALUE_ON_STACK ((a) ? b : c);break;case OP_COLON:break;case OP_SET:POP_2_VALUES ();lv = stack[StackPointer + 1].lval;SET_VALUE_ON_STACK (b);break;case OP_PLUS_EQUAL:POP_2_VALUES ();lv = stack[StackPointer + 1].lval;SET_VALUE_ON_STACK (a + b);break;case OP_MINUS_EQUAL:POP_2_VALUES ();lv = stack[StackPointer + 1].lval;SET_VALUE_ON_STACK (a - b);break;case OP_MULTIPLY_EQUAL:POP_2_VALUES ();lv = stack[StackPointer + 1].lval;SET_VALUE_ON_STACK (a * b);break;case OP_DIVIDE_EQUAL:POP_2_VALUES ();lv = stack[StackPointer + 1].lval;if (CheckNotZero (b))SET_VALUE_ON_STACK (a / b);break;case OP_MODULUS_EQUAL:POP_2_VALUES ();lv = stack[StackPointer + 1].lval;if (CheckNotZero (b))SET_VALUE_ON_STACK (a % b);break;case OP_BINARY_AND_SET:POP_2_VALUES ();lv = stack[StackPointer + 1].lval;SET_VALUE_ON_STACK (a & b);break;case OP_BINARY_XOR_SET:POP_2_VALUES ();lv = stack[StackPointer + 1].lval;SET_VALUE_ON_STACK (a ^ b);break;case OP_BINARY_OR_SET:POP_2_VALUES ();lv = stack[StackPointer + 1].lval;SET_VALUE_ON_STACK (a | b);break;case OP_SHIFT_LEFT_EQUAL:POP_2_VALUES ();lv = stack[StackPointer + 1].lval;SET_VALUE_ON_STACK (a << b);break;case OP_SHIFT_RIGHT_EQUAL:POP_2_VALUES ();lv = stack[StackPointer + 1].lval;SET_VALUE_ON_STACK (a >> b);break;case OP_LOGICAL_AND_SET:POP_2_VALUES ();lv = stack[StackPointer + 1].lval;SET_VALUE_ON_STACK (a && b);break;case OP_LOGICAL_OR_SET:POP_2_VALUES ();lv = stack[StackPointer + 1].lval;SET_VALUE_ON_STACK (a || b);break;case OP_LOGICAL_XOR_SET:POP_2_VALUES ();lv = stack[StackPointer + 1].lval;SET_VALUE_ON_STACK ((a && !b) || (!a && b));break;case OP_COMMA:POP_2_VALUES ();PUSH_VALUE_ON_STACK (b);break;case OP_PRE_PLUS:stack[StackPointer].val =SetVariableValue (stack[StackPointer].lval,stack[StackPointer].val + 1);break;case OP_PRE_MINUS:stack[StackPointer].val =SetVariableValue (stack[StackPointer].lval,stack[StackPointer].val - 1);break;default:ShellErrorMessage ("out of integers");ExpansionErrorDetected = TRUE;return;}}/** Handle binary operators*/static void F_LOCAL ProcessBinaryOperator (int tk){switch (tk){case OP_LOGICAL_AND_EQUALS:case OP_LOGICAL_AND_SET:if (!stack[StackPointer].val)JustParsing++;break;case OP_LOGICAL_OR_EQUALS:case OP_LOGICAL_OR_SET:if (stack[StackPointer].val)JustParsing++;break;}}/** Common processing*/long EvaluateMathsExpression (char *s){int i;for (i = 0; i != MAX_VARIABLES; i++)ListOfVariableNames[i] = (char *)NULL;LastNumberBase = -1; /* Reset base */NumberOfVariables = 0;CStringp = s;StackPointer = -1;RecogniseUnaryOperator = TRUE;ParseMathsExpression (MAX_PRECEDENCE);if (StackPointer){ShellErrorMessage ("bad math expression - unbalanced stack");ExpansionErrorDetected = TRUE;}if (*CStringp){ShellErrorMessage ("bad math expression - illegal character: %c",*CStringp);ExpansionErrorDetected = TRUE;}for (i = 0; i != NumberOfVariables; i++)ReleaseMemoryCell ((void *)ListOfVariableNames[i]);return stack[0].val;}/** operator-precedence parse the string and execute*/static void F_LOCAL ParseMathsExpression (int pc){char *vn;int index;LastToken = MathsLexicalAnalyser ();while (Operators[LastToken].Precedences <= pc){if (LastToken == OP_NUMERIC_VALUE)PushOnToStack (YYLongValue, -1);else if (LastToken == OP_VARIABLE){vn = ExtractNameAndIndex (YYIntValue, &index);PushOnToStack (GetVariableArrayAsNumeric (vn, index), YYIntValue);}else if (LastToken == OP_OPEN_PAR){ParseMathsExpression (MAX_PRECEDENCE);if (LastToken != OP_CLOSE_PAR){ShellErrorMessage ("unmatched ()'s");return;}}else if (LastToken == OP_QUESTION_MARK){long q = stack[StackPointer].val;if (!q)JustParsing++;ParseMathsExpression (Operators[OP_QUESTION_MARK].Precedences - 1);if (!q)JustParsing--;elseJustParsing++;ParseMathsExpression (Operators[OP_QUESTION_MARK].Precedences);if (q)JustParsing--;ProcessOperator (OP_QUESTION_MARK);continue;}else{int otok = LastToken;int onoeval = JustParsing;if (Operators[otok].Type == BOOL_A)ProcessBinaryOperator (otok);ParseMathsExpression (Operators[otok].Precedences -(Operators[otok].Type != RIGHT_LEFT_A));JustParsing = onoeval;ProcessOperator (otok);continue;}LastToken = MathsLexicalAnalyser ();}}/** Decide on 'op=', 'opop' or 'op'*/static int F_LOCAL DecideDoubleOperator (char op,int dequal,int equal,int twice,int single){RecogniseUnaryOperator = TRUE;if (*CStringp == op){if (*(++CStringp) == CHAR_ASSIGN){CStringp++;return dequal;}return twice;}else if (*CStringp == CHAR_ASSIGN){CStringp++;return equal;}return single;}/** Decide on single operator 'op' or 'op='*/static int F_LOCAL DecideSingleOperator (int equal, int single){RecogniseUnaryOperator = TRUE;if (*CStringp != CHAR_ASSIGN)return single;CStringp++;return equal;}/** Handle +=, ++, + or -=, --, -*/static int F_LOCAL DecideSignOperator (char sign, int pre_op, int post_op,int equals, int unary_op, int op){if ((*CStringp == sign) && (RecogniseUnaryOperator || !isalnum (*CStringp))){CStringp++;return RecogniseUnaryOperator ? pre_op : post_op;}if (*CStringp == CHAR_ASSIGN){RecogniseUnaryOperator = TRUE;CStringp++;return equals;}return RecogniseUnaryOperator ? unary_op : op;}/** Validate maths expression without the error message generated a* command. This forces the processing to drop down the stack rather than* doing a deep-exit on error.*/bool ValidMathsExpression (char *string, long *value){ErrorPoint Save_ERP = e.ErrorReturnPoint;bool Save_EED = ExpansionErrorDetected;bool Result;/* save the environment */e.ErrorReturnPoint = (ErrorPoint)NULL;ExpansionErrorDetected = FALSE;/* Validate the number */*value = EvaluateMathsExpression (string);Result = ExpansionErrorDetected;/* Restore environment */e.ErrorReturnPoint = Save_ERP;ExpansionErrorDetected = Save_EED;return Result;}/** Extract a variable name and possible index*/static char * F_LOCAL ExtractNameAndIndex (int s, int *index){long IndValue;char *Vp;char *sp = StringCopy (ListOfVariableNames[s]);if (!GetVariableName (sp, &IndValue, &Vp, (bool *)NULL) || (*Vp))PrintErrorMessage (BasicErrorMessage, ListOfVariableNames[s],LIT_BadID);if (IndValue == -1)PrintErrorMessage (LIT_BadArray, ListOfVariableNames[s]);*index = (int)IndValue;return sp;}