1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795 |
- /*++
- Copyright (c) 2013 Minoca Corp. All Rights Reserved
- Module Name:
- arith.c
- Abstract:
- This module implements arithmetic expansion for the sh shell.
- Author:
- Evan Green 7-Jun-2013
- Environment:
- POSIX
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "sh.h"
- #include "shparse.h"
- #include <assert.h>
- #include <ctype.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <string.h>
- #include "../swlib.h"
- //
- // --------------------------------------------------------------------- Macros
- //
- //
- // This macro takes in a token type and returns non-zero if it is an assignment
- // operator.
- //
- #define SHELL_ARITHMETIC_ASSIGN_OPERATOR(_TokenType) \
- (((_TokenType) == SHELL_ARITHMETIC_MULTIPLY_ASSIGN) || \
- ((_TokenType) == SHELL_ARITHMETIC_DIVIDE_ASSIGN) || \
- ((_TokenType) == SHELL_ARITHMETIC_MODULO_ASSIGN) || \
- ((_TokenType) == SHELL_ARITHMETIC_ADD_ASSIGN) || \
- ((_TokenType) == SHELL_ARITHMETIC_SUBTRACT_ASSIGN) || \
- ((_TokenType) == SHELL_ARITHMETIC_LEFT_SHIFT_ASSIGN) || \
- ((_TokenType) == SHELL_ARITHMETIC_RIGHT_SHIFT_ASSIGN) || \
- ((_TokenType) == SHELL_ARITHMETIC_AND_ASSIGN) || \
- ((_TokenType) == SHELL_ARITHMETIC_OR_ASSIGN) || \
- ((_TokenType) == SHELL_ARITHMETIC_XOR_ASSIGN) || \
- ((_TokenType) == '='))
- //
- // This macro takes a token type and evaluates to non-zero if it could be a
- // unary operator.
- //
- #define SHELL_ARITHMETIC_UNARY_OPERATOR(_TokenType) \
- (((_TokenType) == '-') || ((_TokenType) == '+') || \
- ((_TokenType) == '~') || ((_TokenType) == '!')) \
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the size of the string buffer needed to convert an integer to a
- // string.
- //
- #define SHELL_ARITHMETIC_INTEGER_STRING_BUFFER_SIZE 12
- //
- // Define the initial size of the arithmetic lexer's token buffer.
- //
- #define SHELL_ARITHMETIC_INITIAL_TOKEN_BUFFER_SIZE 256
- //
- // Define arithmetic lexer tokens.
- //
- #define SHELL_ARITHMETIC_END_OF_FILE 0
- #define SHELL_ARITHMETIC_WORD 600
- #define SHELL_ARITHMETIC_NUMBER 601
- #define SHELL_ARITHMETIC_SHIFT_LEFT 602
- #define SHELL_ARITHMETIC_SHIFT_RIGHT 603
- #define SHELL_ARITHMETIC_LESS_THAN_OR_EQUAL 604
- #define SHELL_ARITHMETIC_GREATER_THAN_OR_EQUAL 605
- #define SHELL_ARITHMETIC_EQUALITY 606
- #define SHELL_ARITHMETIC_NOT_EQUAL 607
- #define SHELL_ARITHMETIC_LOGICAL_AND 608
- #define SHELL_ARITHMETIC_LOGICAL_OR 609
- #define SHELL_ARITHMETIC_MULTIPLY_ASSIGN 610
- #define SHELL_ARITHMETIC_DIVIDE_ASSIGN 611
- #define SHELL_ARITHMETIC_MODULO_ASSIGN 612
- #define SHELL_ARITHMETIC_ADD_ASSIGN 613
- #define SHELL_ARITHMETIC_SUBTRACT_ASSIGN 614
- #define SHELL_ARITHMETIC_LEFT_SHIFT_ASSIGN 615
- #define SHELL_ARITHMETIC_RIGHT_SHIFT_ASSIGN 616
- #define SHELL_ARITHMETIC_AND_ASSIGN 617
- #define SHELL_ARITHMETIC_OR_ASSIGN 618
- #define SHELL_ARITHMETIC_XOR_ASSIGN 619
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure defines the state for the lexer of arithmetic expressions.
- Members:
- Input - Supplies a pointer to the input string.
- InputSize - Supplies the size of the input string in bytes.
- InputOffset - Supplies the offset of the next character to fetch.
- TokenType - Stores the type of token this current token represents. See
- SHELL_ARITHMETIC_* definitions.
- TokenBuffer - Stores a pointer to the buffer containing the current token.
- TokenBufferCapacity - Stores the total size fo the token buffer.
- TokenBufferSize - Stores the number of valid bytes in the token buffer.
- LexerPrimed - Stores a boolean indicating whether the lexer token is valid
- (TRUE) or uninitialized (FALSE).
- TokensRead - Stores the number of tokens that have been read, including
- this one.
- AssignmentName - Stores the name of the destination assignment variable.
- AssignmentNameSize - Stores the size of the assignment name in bytes.
- --*/
- typedef struct _SHELL_ARITHMETIC_LEXER {
- PSTR Input;
- UINTN InputSize;
- UINTN InputOffset;
- ULONG TokenType;
- PSTR TokenBuffer;
- UINTN TokenBufferCapacity;
- UINTN TokenBufferSize;
- BOOL LexerPrimed;
- UINTN TokensRead;
- PSTR AssignmentName;
- UINTN AssignmentNameSize;
- } SHELL_ARITHMETIC_LEXER, *PSHELL_ARITHMETIC_LEXER;
- /*++
- Structure Description:
- This structure defines an entry in the parse stack for arithmetic
- expressions.
- Members:
- ListEntry - Stores the next and previous elements in the parse stack.
- Elements get pushed onto the front of the list, so following the
- next pointer goes to older elements.
- TokenType - Stores the type of this token.
- Value - Stores the value for numeric tokens.
- --*/
- typedef struct SHELL_ARITHMETIC_PARSE_ELEMENT {
- LIST_ENTRY ListEntry;
- ULONG TokenType;
- LONG Value;
- } SHELL_ARITHMETIC_PARSE_ELEMENT, *PSHELL_ARITHMETIC_PARSE_ELEMENT;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- BOOL
- ShParseArithmeticExpression (
- PSHELL Shell,
- PSHELL_ARITHMETIC_LEXER Lexer,
- BOOL Nested,
- PLONG ExpressionResult
- );
- BOOL
- ShGetNextArithmeticParseElement (
- PSHELL Shell,
- PSHELL_ARITHMETIC_LEXER Lexer,
- PLIST_ENTRY Stack,
- BOOL Nested,
- PSHELL_ARITHMETIC_PARSE_ELEMENT Element
- );
- BOOL
- ShArithmeticShiftOrReduce (
- PSHELL Shell,
- PSHELL_ARITHMETIC_LEXER Lexer,
- PLIST_ENTRY Stack,
- PSHELL_ARITHMETIC_PARSE_ELEMENT Next,
- PBOOL Shift
- );
- BOOL
- ShEvaluateArithmeticOperator (
- PSHELL Shell,
- PSHELL_ARITHMETIC_PARSE_ELEMENT LeftValue,
- PSHELL_ARITHMETIC_PARSE_ELEMENT Operator,
- PSHELL_ARITHMETIC_PARSE_ELEMENT RightValue,
- PLONG Result
- );
- ULONG
- ShGetOperatorPrecedence (
- ULONG TokenType
- );
- BOOL
- ShAssignArithmeticResult (
- PSHELL Shell,
- PSHELL_ARITHMETIC_LEXER Lexer,
- LONG Value
- );
- BOOL
- ShGetArithmeticToken (
- PSHELL Shell,
- PSHELL_ARITHMETIC_LEXER Lexer
- );
- BOOL
- ShAddCharacterToArithmeticToken (
- PSHELL_ARITHMETIC_LEXER Lexer,
- CHAR Character
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- BOOL ShDebugArithmeticLexer = FALSE;
- BOOL ShDebugArithmeticParser = FALSE;
- PSTR ShArithmeticTokenStrings[] = {
- "ARITHMETIC_WORD",
- "ARITHMETIC_NUMBER",
- "ARITHMETIC_SHIFT_LEFT",
- "ARITHMETIC_SHIFT_RIGHT",
- "ARITHMETIC_LESS_THAN_OR_EQUAL",
- "ARITHMETIC_GREATER_THAN_OR_EQUAL",
- "ARITHMETIC_EQUALITY",
- "ARITHMETIC_NOT_EQUAL",
- "ARITHMETIC_LOGICAL_AND",
- "ARITHMETIC_LOGICAL_OR",
- "ARITHMETIC_MULTIPLY_ASSIGN",
- "ARITHMETIC_DIVIDE_ASSIGN",
- "ARITHMETIC_MODULO_ASSIGN",
- "ARITHMETIC_ADD_ASSIGN",
- "ARITHMETIC_SUBTRACT_ASSIGN",
- "ARITHMETIC_LEFT_SHIFT_ASSIGN",
- "ARITHMETIC_RIGHT_SHIFT_ASSIGN",
- "ARITHMETIC_AND_ASSIGN",
- "ARITHMETIC_OR_ASSIGN",
- "ARITHMETIC_XOR_ASSIGN"
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- BOOL
- ShEvaluateArithmeticExpression (
- PSHELL Shell,
- PSTR String,
- UINTN Length,
- PSTR *Answer,
- PUINTN AnswerSize
- )
- /*++
- Routine Description:
- This routine evaluates an arithmetic expression. It assumes that all
- expansions have already taken place except for variable names without a
- dollar sign.
- Arguments:
- Shell - Supplies a pointer to the shell.
- String - Supplies a pointer to the input string.
- Length - Supplies the length of the input string in bytes.
- Answer - Supplies a pointer where the evaluation will be returned on
- success. The caller is responsible for freeing this memory.
- AnswerSize - Supplies a pointer where the size of the answer buffer will
- be returned including the null terminating byte on success.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- PSTR AnswerBuffer;
- SHELL_ARITHMETIC_LEXER Lexer;
- LONG NumericAnswer;
- BOOL Result;
- AnswerBuffer = NULL;
- memset(&Lexer, 0, sizeof(SHELL_ARITHMETIC_LEXER));
- Lexer.TokenBufferCapacity = SHELL_ARITHMETIC_INITIAL_TOKEN_BUFFER_SIZE;
- Lexer.TokenBuffer = malloc(SHELL_ARITHMETIC_INITIAL_TOKEN_BUFFER_SIZE);
- if (Shell->Lexer.TokenBuffer == NULL) {
- Result = FALSE;
- goto EvaluateArithmeticExpressionEnd;
- }
- Lexer.Input = String;
- Lexer.InputSize = Length;
- Result = ShParseArithmeticExpression(Shell, &Lexer, FALSE, &NumericAnswer);
- if (Result == FALSE) {
- goto EvaluateArithmeticExpressionEnd;
- }
- //
- // Convert the answer to a string for the caller. So nice.
- //
- AnswerBuffer = malloc(SHELL_ARITHMETIC_INTEGER_STRING_BUFFER_SIZE);
- if (AnswerBuffer == NULL) {
- Result = FALSE;
- goto EvaluateArithmeticExpressionEnd;
- }
- *AnswerSize = snprintf(AnswerBuffer,
- SHELL_ARITHMETIC_INTEGER_STRING_BUFFER_SIZE,
- "%d",
- NumericAnswer) + 1;
- Result = TRUE;
- EvaluateArithmeticExpressionEnd:
- if (Lexer.TokenBuffer != NULL) {
- free(Lexer.TokenBuffer);
- }
- if (Lexer.AssignmentName != NULL) {
- free(Lexer.AssignmentName);
- }
- if (Result == FALSE) {
- if (AnswerBuffer != NULL) {
- free(AnswerBuffer);
- AnswerBuffer = NULL;
- }
- }
- *Answer = AnswerBuffer;
- return Result;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- BOOL
- ShParseArithmeticExpression (
- PSHELL Shell,
- PSHELL_ARITHMETIC_LEXER Lexer,
- BOOL Nested,
- PLONG ExpressionResult
- )
- /*++
- Routine Description:
- This routine parses and evaluates an arithmetic expression.
- Arguments:
- Shell - Supplies a pointer to the shell to operate on.
- Lexer - Supplies a pointer to the initialized and primed lexer.
- Nested - Supplies a boolean indicating whether this is the primary
- expression (FALSE) or whether this is nested as part of evaluating
- an expression inside parentheses or after a ? or :.
- ExpressionResult - Supplies a pointer where the evaluation will be returned
- on success.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- PSHELL_ARITHMETIC_PARSE_ELEMENT Element;
- SHELL_ARITHMETIC_PARSE_ELEMENT NextElement;
- BOOL Result;
- BOOL Shift;
- LIST_ENTRY Stack;
- INITIALIZE_LIST_HEAD(&Stack);
- while (TRUE) {
- Result = ShGetNextArithmeticParseElement(Shell,
- Lexer,
- &Stack,
- Nested,
- &NextElement);
- if (Result == FALSE) {
- break;
- }
- //
- // Reduce as much as possible.
- //
- do {
- Result = ShArithmeticShiftOrReduce(Shell,
- Lexer,
- &Stack,
- &NextElement,
- &Shift);
- if (Result == FALSE) {
- goto ParseArithmeticExpressionEnd;
- }
- } while (Shift == FALSE);
- //
- // If this was the EOF token, then the parser should be done.
- //
- if (NextElement.TokenType == SHELL_ARITHMETIC_END_OF_FILE) {
- //
- // If there's not exactly one element on the list, it's a failure.
- //
- if ((LIST_EMPTY(&Stack) != FALSE) || (Stack.Next->Next != &Stack)) {
- Result = FALSE;
- *ExpressionResult = 0;
- break;
- } else {
- Element = LIST_VALUE(Stack.Next,
- SHELL_ARITHMETIC_PARSE_ELEMENT,
- ListEntry);
- if (Element->TokenType != SHELL_ARITHMETIC_NUMBER) {
- Result = FALSE;
- *ExpressionResult = 0;
- } else {
- *ExpressionResult = Element->Value;
- if (Lexer->AssignmentName != NULL) {
- Result = ShAssignArithmeticResult(Shell,
- Lexer,
- Element->Value);
- if (Result == FALSE) {
- goto ParseArithmeticExpressionEnd;
- }
- }
- Result = TRUE;
- break;
- }
- }
- } else {
- Element = malloc(sizeof(SHELL_ARITHMETIC_PARSE_ELEMENT));
- if (Element == NULL) {
- Result = FALSE;
- goto ParseArithmeticExpressionEnd;
- }
- memcpy(Element,
- &NextElement,
- sizeof(SHELL_ARITHMETIC_PARSE_ELEMENT));
- INSERT_AFTER(&(Element->ListEntry), &Stack);
- }
- }
- ParseArithmeticExpressionEnd:
- while (LIST_EMPTY(&Stack) == FALSE) {
- Element = LIST_VALUE(Stack.Next,
- SHELL_ARITHMETIC_PARSE_ELEMENT,
- ListEntry);
- LIST_REMOVE(&(Element->ListEntry));
- free(Element);
- }
- if (ShDebugArithmeticParser != FALSE) {
- if (Result != FALSE) {
- ShPrintTrace(Shell, "Arithmetic Result: %ld\n", *ExpressionResult);
- } else {
- ShPrintTrace(Shell,
- "Error: Failed to parse arithmetic expression.\n");
- }
- }
- return Result;
- }
- BOOL
- ShGetNextArithmeticParseElement (
- PSHELL Shell,
- PSHELL_ARITHMETIC_LEXER Lexer,
- PLIST_ENTRY Stack,
- BOOL Nested,
- PSHELL_ARITHMETIC_PARSE_ELEMENT Element
- )
- /*++
- Routine Description:
- This routine retrieves the next parse element for an arithmetic expression.
- Arguments:
- Shell - Supplies a pointer to the shell to operate on.
- Lexer - Supplies a pointer to the initialized lexer.
- Stack - Supplies a pointer to the parsing stack.
- Nested - Supplies a boolean indicating whether this is the primary
- expression (FALSE) or whether this is nested as part of evaluating
- an expression inside parentheses or after a ? or :.
- Element - Supplies a pointer where the filled out element will be returned.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- PSTR AfterScan;
- LONG FalseValue;
- BOOL IsName;
- BOOL Result;
- PSHELL_ARITHMETIC_PARSE_ELEMENT Top;
- LONG TrueValue;
- LONG Value;
- PSTR ValueString;
- UINTN ValueStringSize;
- Result = ShGetArithmeticToken(Shell, Lexer);
- if (Result == FALSE) {
- return FALSE;
- }
- if ((Lexer->TokenType == SHELL_ARITHMETIC_NUMBER) ||
- (Lexer->TokenType == SHELL_ARITHMETIC_WORD)) {
- if (Lexer->TokenType == SHELL_ARITHMETIC_WORD) {
- Result = ShGetVariable(Shell,
- Lexer->TokenBuffer,
- Lexer->TokenBufferSize,
- &ValueString,
- &ValueStringSize);
- if (Result == FALSE) {
- ValueString = NULL;
- }
- //
- // Variables need to be valid names.
- //
- IsName = ShIsName(Lexer->TokenBuffer, Lexer->TokenBufferSize);
- if (IsName == FALSE) {
- return FALSE;
- }
- //
- // If this is the first token and it's a variable name, save it
- // in case it's an assignment.
- //
- if (Lexer->TokensRead == 1) {
- assert(Lexer->AssignmentName == NULL);
- Lexer->AssignmentName = SwStringDuplicate(
- Lexer->TokenBuffer,
- Lexer->TokenBufferSize);
- if (Lexer->AssignmentName == NULL) {
- return FALSE;
- }
- Lexer->AssignmentNameSize = Lexer->TokenBufferSize;
- }
- } else {
- ValueString = Lexer->TokenBuffer;
- ValueStringSize = Lexer->TokenBufferSize;
- }
- //
- // If there's a buffer, attempt to convert it to a number.
- //
- Value = 0;
- if (ValueString != NULL) {
- Value = strtol(ValueString, &AfterScan, 0);
- if ((UINTN)AfterScan != (UINTN)ValueString + ValueStringSize - 1) {
- Result = FALSE;
- return FALSE;
- }
- }
- Element->TokenType = SHELL_ARITHMETIC_NUMBER;
- Element->Value = Value;
- return TRUE;
- } else if (Lexer->TokenType == '(') {
- Result = ShParseArithmeticExpression(Shell, Lexer, TRUE, &Value);
- if (Result == FALSE) {
- return FALSE;
- }
- if (Lexer->TokenType != ')') {
- return FALSE;
- }
- Element->TokenType = SHELL_ARITHMETIC_NUMBER;
- Element->Value = Value;
- return TRUE;
- //
- // The question mark ternary operator is also recursive, as it requires two
- // full expressions. This cheats and does a bit of reducing which isn't
- // ideal architecturally but seeing as it's the only thing that does this
- // and I'm a little tipsy we'll let it slide.
- //
- } else if (Lexer->TokenType == '?') {
- Result = ShParseArithmeticExpression(Shell, Lexer, TRUE, &TrueValue);
- if (Result == FALSE) {
- return FALSE;
- }
- if (Lexer->TokenType != ':') {
- return FALSE;
- }
- Result = ShParseArithmeticExpression(Shell, Lexer, TRUE, &FalseValue);
- if (Result == FALSE) {
- return FALSE;
- }
- Top = LIST_VALUE(Stack->Next,
- SHELL_ARITHMETIC_PARSE_ELEMENT,
- ListEntry);
- if ((LIST_EMPTY(Stack) != FALSE) ||
- (Top->TokenType != SHELL_ARITHMETIC_NUMBER)) {
- return FALSE;
- }
- if (Top->Value != 0) {
- Value = TrueValue;
- } else {
- Value = FalseValue;
- }
- if (ShDebugArithmeticParser != FALSE) {
- ShPrintTrace(Shell,
- "arith: %ld <== %ld ? %ld : %ld\n",
- Value,
- Top->Value,
- TrueValue,
- FalseValue);
- }
- Top->Value = Value;
- Element->TokenType = SHELL_ARITHMETIC_END_OF_FILE;
- Element->Value = 0;
- return TRUE;
- //
- // If this is a closing parentheses or colon and it's nested, that's the
- // end of the line for the inner nested one. If it's not nested, then this
- // is a bad random close parentheses.
- //
- } else if ((Lexer->TokenType == ')') || (Lexer->TokenType == ':')) {
- if (Nested != FALSE) {
- Element->TokenType = SHELL_ARITHMETIC_END_OF_FILE;
- Element->Value = 0;
- return TRUE;
- } else {
- return FALSE;
- }
- }
- Element->TokenType = Lexer->TokenType;
- Element->Value = 0;
- return TRUE;
- }
- BOOL
- ShArithmeticShiftOrReduce (
- PSHELL Shell,
- PSHELL_ARITHMETIC_LEXER Lexer,
- PLIST_ENTRY Stack,
- PSHELL_ARITHMETIC_PARSE_ELEMENT Next,
- PBOOL Shift
- )
- /*++
- Routine Description:
- This routine attempts to reduce the given parse stack if possible, or
- directs the caller to shift.
- Arguments:
- Shell - Supplies a pointer to the shell to operate on.
- Lexer - Supplies a pointer to the initialized lexer.
- Stack - Supplies a pointer to the head of the parse stack.
- Next - Supplies a pointer to the next element.
- Shift - Supplies a boolean where TRUE will be returned if more values
- should be shifted onto the stack. Or FALSE if the stack was reduced.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- LONG Answer;
- ULONG NextPrecedence;
- ULONG NextToken;
- PSHELL_ARITHMETIC_PARSE_ELEMENT Operator;
- BOOL Result;
- ULONG StackPrecedence;
- PSHELL_ARITHMETIC_PARSE_ELEMENT Top;
- PSHELL_ARITHMETIC_PARSE_ELEMENT TwoBack;
- *Shift = FALSE;
- if (LIST_EMPTY(Stack) != FALSE) {
- *Shift = TRUE;
- return TRUE;
- }
- Top = LIST_VALUE(Stack->Next, SHELL_ARITHMETIC_PARSE_ELEMENT, ListEntry);
- //
- // Assignment operators are only allowed as the second value in an
- // expression (with the first being an assignment word).
- //
- NextToken = Next->TokenType;
- assert(NextToken != SHELL_ARITHMETIC_WORD);
- if (SHELL_ARITHMETIC_ASSIGN_OPERATOR(NextToken)) {
- if ((Lexer->TokensRead != 2) || (Lexer->AssignmentName == NULL)) {
- return FALSE;
- }
- //
- // If it's token 2 and not an assignment operator, free up the assignment
- // word.
- //
- } else if (Lexer->TokensRead == 2) {
- if (Lexer->AssignmentName != NULL) {
- free(Lexer->AssignmentName);
- Lexer->AssignmentName = NULL;
- }
- }
- if (Top->TokenType == SHELL_ARITHMETIC_NUMBER) {
- //
- // If that's all that's on the list, definitely shift, unless this
- // next token is another number which is invalid.
- //
- if (Top->ListEntry.Next == Stack) {
- if (Next->TokenType == SHELL_ARITHMETIC_NUMBER) {
- return FALSE;
- }
- *Shift = TRUE;
- return TRUE;
- }
- //
- // Get the operator down there and let's find out what it is.
- //
- Operator = LIST_VALUE(Top->ListEntry.Next,
- SHELL_ARITHMETIC_PARSE_ELEMENT,
- ListEntry);
- TwoBack = LIST_VALUE(Operator->ListEntry.Next,
- SHELL_ARITHMETIC_PARSE_ELEMENT,
- ListEntry);
- if (Operator->ListEntry.Next == Stack) {
- TwoBack = NULL;
- }
- //
- // If it's a plus or a minus, this could be a unary plus or minus, in
- // which case it should be reduced. It's known to be a unary operator
- // if there's not a number behind it. It could also be a binary plus
- // or minus, in which case it's left alone.
- //
- if ((Operator->TokenType == '+') || (Operator->TokenType == '-')) {
- if ((TwoBack == NULL) ||
- (TwoBack->TokenType != SHELL_ARITHMETIC_NUMBER)) {
- //
- // Reduce the unary + or minus and return.
- //
- LIST_REMOVE(&(Top->ListEntry));
- if (Operator->TokenType == '-') {
- Operator->Value = -Top->Value;
- } else {
- Operator->Value = Top->Value;
- }
- Operator->TokenType = Top->TokenType;
- free(Top);
- return TRUE;
- }
- } else if (SHELL_ARITHMETIC_UNARY_OPERATOR(Operator->TokenType)) {
- TwoBack = NULL;
- }
- StackPrecedence = ShGetOperatorPrecedence(Operator->TokenType);
- assert(StackPrecedence != -1);
- NextPrecedence = ShGetOperatorPrecedence(Next->TokenType);
- //
- // If the next thing is not an operator, then fail now.
- //
- if (NextPrecedence == -1) {
- return FALSE;
- }
- //
- // If the operator on the stack has equal or higher precedence than the
- // next operator, then reduce, otherwise shift.
- //
- if (StackPrecedence >= NextPrecedence) {
- assert((TwoBack == NULL) ||
- (TwoBack->TokenType == SHELL_ARITHMETIC_NUMBER));
- Result = ShEvaluateArithmeticOperator(Shell,
- TwoBack,
- Operator,
- Top,
- &Answer);
- if (Result == FALSE) {
- return FALSE;
- }
- LIST_REMOVE(&(Top->ListEntry));
- free(Top);
- if (TwoBack != NULL) {
- LIST_REMOVE(&(Operator->ListEntry));
- free(Operator);
- Operator = TwoBack;
- }
- Operator->TokenType = SHELL_ARITHMETIC_NUMBER;
- Operator->Value = Answer;
- } else {
- *Shift = TRUE;
- }
- return TRUE;
- }
- //
- // If what's coming next is a number, then let it on for sure.
- //
- if (NextToken == SHELL_ARITHMETIC_NUMBER) {
- *Shift = TRUE;
- return TRUE;
- }
- //
- // What's next is an operator. Only allow it if it is a unary operator.
- //
- if (!SHELL_ARITHMETIC_UNARY_OPERATOR(NextToken)) {
- return FALSE;
- }
- *Shift = TRUE;
- return TRUE;
- }
- BOOL
- ShEvaluateArithmeticOperator (
- PSHELL Shell,
- PSHELL_ARITHMETIC_PARSE_ELEMENT LeftValue,
- PSHELL_ARITHMETIC_PARSE_ELEMENT Operator,
- PSHELL_ARITHMETIC_PARSE_ELEMENT RightValue,
- PLONG Result
- )
- /*++
- Routine Description:
- This routine performs an arithmetic operation on two values.
- Arguments:
- Shell - Supplies a pointer to the shell.
- LeftValue - Supplies a pointer to the left operand.
- Operator - Supplies a pointer to the operator.
- RightValue - Supplies a pointer to the right operand.
- Result - Supplies a pointer where the resulting value will be returned on
- success.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- LONG Answer;
- CHAR DebugOperator[2];
- LONG Left;
- LONG Right;
- assert(((LeftValue == NULL) ||
- (LeftValue->TokenType == SHELL_ARITHMETIC_NUMBER)) &&
- (RightValue->TokenType == SHELL_ARITHMETIC_NUMBER));
- Left = 0;
- if (LeftValue != 0) {
- Left = LeftValue->Value;
- }
- Right = RightValue->Value;
- DebugOperator[0] = (CHAR)Operator->TokenType;
- if (Operator->TokenType < 0x100) {
- DebugOperator[1] = ' ';
- } else {
- DebugOperator[1] = '=';
- }
- switch (Operator->TokenType) {
- case SHELL_ARITHMETIC_LEFT_SHIFT_ASSIGN:
- case SHELL_ARITHMETIC_SHIFT_LEFT:
- DebugOperator[0] = '<';
- DebugOperator[1] = '<';
- Answer = Left << Right;
- break;
- case SHELL_ARITHMETIC_RIGHT_SHIFT_ASSIGN:
- case SHELL_ARITHMETIC_SHIFT_RIGHT:
- DebugOperator[0] = '>';
- DebugOperator[1] = '>';
- Answer = Left >> Right;
- break;
- case SHELL_ARITHMETIC_LESS_THAN_OR_EQUAL:
- DebugOperator[0] = '<';
- Answer = Left <= Right;
- break;
- case SHELL_ARITHMETIC_GREATER_THAN_OR_EQUAL:
- DebugOperator[0] = '>';
- Answer = Left >= Right;
- break;
- case SHELL_ARITHMETIC_EQUALITY:
- DebugOperator[0] = '=';
- Answer = Left == Right;
- break;
- case SHELL_ARITHMETIC_NOT_EQUAL:
- DebugOperator[0] = '!';
- Answer = Left != Right;
- break;
- case SHELL_ARITHMETIC_LOGICAL_AND:
- DebugOperator[0] = '&';
- DebugOperator[1] = '&';
- Answer = Left && Right;
- break;
- case SHELL_ARITHMETIC_LOGICAL_OR:
- DebugOperator[0] = '|';
- DebugOperator[1] = '|';
- Answer = Left || Right;
- break;
- case '~':
- Answer = ~Right;
- break;
- case '!':
- Answer = !Right;
- break;
- case SHELL_ARITHMETIC_MULTIPLY_ASSIGN:
- case '*':
- DebugOperator[0] = '*';
- Answer = Left * Right;
- break;
- case SHELL_ARITHMETIC_DIVIDE_ASSIGN:
- case '/':
- DebugOperator[0] = '/';
- Answer = Left / Right;
- break;
- case SHELL_ARITHMETIC_MODULO_ASSIGN:
- case '%':
- DebugOperator[0] = '%';
- Answer = Left % Right;
- break;
- case SHELL_ARITHMETIC_ADD_ASSIGN:
- case '+':
- DebugOperator[0] = '+';
- Answer = Left + Right;
- break;
- case SHELL_ARITHMETIC_SUBTRACT_ASSIGN:
- case '-':
- DebugOperator[0] = '-';
- Answer = Left - Right;
- break;
- case '<':
- Answer = Left < Right;
- break;
- case '>':
- Answer = Left > Right;
- break;
- case '=':
- Answer = Right;
- break;
- case SHELL_ARITHMETIC_AND_ASSIGN:
- case '&':
- DebugOperator[0] = '&';
- Answer = Left & Right;
- break;
- case SHELL_ARITHMETIC_OR_ASSIGN:
- case '|':
- DebugOperator[0] = '|';
- Answer = Left | Right;
- break;
- case SHELL_ARITHMETIC_XOR_ASSIGN:
- case '^':
- DebugOperator[0] = '^';
- Answer = Left ^ Right;
- break;
- default:
- assert(FALSE);
- return FALSE;
- }
- if (ShDebugArithmeticParser != FALSE) {
- ShPrintTrace(Shell,
- "Arith: %ld <== %ld %c%c %ld\n",
- Answer,
- Left,
- DebugOperator[0],
- DebugOperator[1],
- Right);
- }
- *Result = Answer;
- return TRUE;
- }
- ULONG
- ShGetOperatorPrecedence (
- ULONG TokenType
- )
- /*++
- Routine Description:
- This routine gives a ranking for the given operator. Higher numbers mean
- greater precence.
- Arguments:
- TokenType - Supplies the operator to rank.
- Return Value:
- Returns a value representing the operator's ranking. Higher number bind
- tighter to their arguments.
- -1 if the token is not an operator.
- --*/
- {
- switch (TokenType) {
- case SHELL_ARITHMETIC_END_OF_FILE:
- return 0;
- case SHELL_ARITHMETIC_MULTIPLY_ASSIGN:
- case SHELL_ARITHMETIC_DIVIDE_ASSIGN:
- case SHELL_ARITHMETIC_MODULO_ASSIGN:
- case SHELL_ARITHMETIC_ADD_ASSIGN:
- case SHELL_ARITHMETIC_SUBTRACT_ASSIGN:
- case SHELL_ARITHMETIC_LEFT_SHIFT_ASSIGN:
- case SHELL_ARITHMETIC_RIGHT_SHIFT_ASSIGN:
- case SHELL_ARITHMETIC_AND_ASSIGN:
- case SHELL_ARITHMETIC_OR_ASSIGN:
- case SHELL_ARITHMETIC_XOR_ASSIGN:
- case '=':
- return 1;
- case '?':
- return 2;
- case ':':
- return 3;
- case SHELL_ARITHMETIC_LOGICAL_OR:
- return 4;
- case SHELL_ARITHMETIC_LOGICAL_AND:
- return 5;
- case '|':
- return 6;
- case '^':
- return 7;
- case '&':
- return 8;
- case SHELL_ARITHMETIC_NOT_EQUAL:
- case SHELL_ARITHMETIC_EQUALITY:
- return 9;
- case SHELL_ARITHMETIC_LESS_THAN_OR_EQUAL:
- case SHELL_ARITHMETIC_GREATER_THAN_OR_EQUAL:
- case '<':
- case '>':
- return 10;
- case SHELL_ARITHMETIC_SHIFT_LEFT:
- case SHELL_ARITHMETIC_SHIFT_RIGHT:
- return 11;
- case '+':
- case '-':
- return 12;
- case '*':
- case '/':
- case '%':
- return 13;
- case '~':
- case '!':
- return 14;
- default:
- break;
- }
- assert(FALSE);
- return 0;
- }
- BOOL
- ShAssignArithmeticResult (
- PSHELL Shell,
- PSHELL_ARITHMETIC_LEXER Lexer,
- LONG Value
- )
- /*++
- Routine Description:
- This routine performs an assignment of an arithmetic result to a shell
- environment variable.
- Arguments:
- Shell - Supplies a pointer to the shell to operate on.
- Lexer - Supplies a pointer to the initialized lexer.
- Value - Supplies the numeric value to assign.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- BOOL Result;
- CHAR StringBuffer[SHELL_ARITHMETIC_INTEGER_STRING_BUFFER_SIZE];
- UINTN StringSize;
- StringSize = snprintf(StringBuffer,
- SHELL_ARITHMETIC_INTEGER_STRING_BUFFER_SIZE,
- "%d",
- Value) + 1;
- assert((Lexer->AssignmentName != NULL) && (Lexer->AssignmentNameSize != 0));
- Result = ShSetVariable(Shell,
- Lexer->AssignmentName,
- Lexer->AssignmentNameSize,
- StringBuffer,
- StringSize);
- return Result;
- }
- BOOL
- ShGetArithmeticToken (
- PSHELL Shell,
- PSHELL_ARITHMETIC_LEXER Lexer
- )
- /*++
- Routine Description:
- This routine gets a token for the arithmetic lexer.
- Arguments:
- Shell - Supplies a pointer to the shell.
- Lexer - Supplies a pointer to the lexer to operate on.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- CHAR AddCharacter;
- CHAR Character;
- BOOL Delimit;
- CHAR LastCharacter;
- CHAR LastLastCharacter;
- BOOL Result;
- UINTN TokenStringIndex;
- BOOL Unput;
- Character = 0;
- LastCharacter = 0;
- LastLastCharacter = 0;
- Lexer->TokenType = -1;
- Lexer->TokenBufferSize = 0;
- Lexer->TokensRead += 1;
- Delimit = FALSE;
- while (TRUE) {
- AddCharacter = TRUE;
- Unput = FALSE;
- //
- // If the end of the buffer came around, delimit the current token, or
- // return the EOF token.
- //
- if ((Lexer->InputOffset == Lexer->InputSize) ||
- (Lexer->Input[Lexer->InputOffset] == '\0')) {
- AddCharacter = FALSE;
- Delimit = TRUE;
- if (Lexer->TokenBufferSize == 0) {
- Lexer->TokenType = SHELL_ARITHMETIC_END_OF_FILE;
- }
- } else {
- Character = Lexer->Input[Lexer->InputOffset];
- Lexer->InputOffset += 1;
- switch (Character) {
- //
- // These characters are operators all by themselves, and only ever
- // by themselves.
- //
- case '~':
- case '?':
- case ':':
- case '(':
- case ')':
- Delimit = TRUE;
- if (Lexer->TokenBufferSize != 0) {
- AddCharacter = FALSE;
- Unput = TRUE;
- }
- break;
- //
- // This next batch of symbols either stands by itself or can only
- // have an equals after it (and is only ever the first character
- // in a double symbol).
- //
- case '!':
- case '*':
- case '/':
- case '%':
- case '+':
- case '-':
- case '^':
- if (Lexer->TokenBufferSize != 0) {
- Delimit = TRUE;
- AddCharacter = FALSE;
- Unput = TRUE;
- }
- break;
- //
- // The & and | symbols could either be on their own, with an
- // equals (&= |=) or with themselves (&& ||).
- //
- case '&':
- case '|':
- if (LastCharacter == Character) {
- Delimit = TRUE;
- if (Character == '&') {
- Lexer->TokenType = SHELL_ARITHMETIC_LOGICAL_AND;
- } else {
- assert(Character == '|');
- Lexer->TokenType = SHELL_ARITHMETIC_LOGICAL_OR;
- }
- //
- // Besides && and ||, these symbols are always the first in an
- // operator, so if there's something in the buffer flush it
- // out.
- //
- } else if (Lexer->TokenBufferSize != 0) {
- Delimit = TRUE;
- AddCharacter = FALSE;
- Unput = TRUE;
- }
- break;
- //
- // The > and < symbols could either be by themselves, doubled
- // (<< >>), with an equals after them (>= <=), or double and with
- // and equals after them (>>= <<=). The only way they can be
- // delimited for sure now is if the last character wasn't the same
- // as this one.
- //
- case '<':
- case '>':
- if ((Lexer->TokenBufferSize != 0) &&
- (LastCharacter != Character)) {
- Delimit = TRUE;
- AddCharacter = FALSE;
- Unput = TRUE;
- }
- break;
- //
- // The all important equal sign. It can be by itself, or with 1 or
- // 2 characters in front of it.
- //
- case '=':
- //
- // If it's not the first character in the buffer, it's always
- // the last.
- //
- if (Lexer->TokenBufferSize != 0) {
- Delimit = TRUE;
- }
- switch (LastCharacter) {
- case '!':
- Lexer->TokenType = SHELL_ARITHMETIC_NOT_EQUAL;
- break;
- case '=':
- Lexer->TokenType = SHELL_ARITHMETIC_EQUALITY;
- break;
- case '&':
- Lexer->TokenType = SHELL_ARITHMETIC_AND_ASSIGN;
- break;
- case '|':
- Lexer->TokenType = SHELL_ARITHMETIC_OR_ASSIGN;
- break;
- case '+':
- Lexer->TokenType = SHELL_ARITHMETIC_ADD_ASSIGN;
- break;
- case '-':
- Lexer->TokenType = SHELL_ARITHMETIC_SUBTRACT_ASSIGN;
- break;
- case '*':
- Lexer->TokenType = SHELL_ARITHMETIC_MULTIPLY_ASSIGN;
- break;
- case '/':
- Lexer->TokenType = SHELL_ARITHMETIC_DIVIDE_ASSIGN;
- break;
- case '%':
- Lexer->TokenType = SHELL_ARITHMETIC_MODULO_ASSIGN;
- break;
- case '^':
- Lexer->TokenType = SHELL_ARITHMETIC_XOR_ASSIGN;
- break;
- case '>':
- Lexer->TokenType = SHELL_ARITHMETIC_GREATER_THAN_OR_EQUAL;
- if (LastLastCharacter == '>') {
- Lexer->TokenType = SHELL_ARITHMETIC_RIGHT_SHIFT_ASSIGN;
- }
- break;
- case '<':
- Lexer->TokenType = SHELL_ARITHMETIC_LESS_THAN_OR_EQUAL;
- if (LastLastCharacter == '<') {
- Lexer->TokenType = SHELL_ARITHMETIC_LEFT_SHIFT_ASSIGN;
- }
- break;
- //
- // If the last character was nothing, an operator that can't
- // have an equals sign glued onto it, or an average joe
- // character then either delimit the previous token or don't
- // delimit and see if another equals comes in.
- //
- default:
- if (Lexer->TokenBufferSize != 0) {
- AddCharacter = FALSE;
- Unput = TRUE;
- }
- break;
- }
- break;
- //
- // This is an average joe character, either a digit, letter, or
- // space of some kind. Look to see if an operator that might have
- // been two or three characters but wasn't just ended.
- //
- default:
- AddCharacter = FALSE;
- switch (LastCharacter) {
- case '<':
- case '>':
- Delimit = TRUE;
- AddCharacter = FALSE;
- Unput = TRUE;
- if (LastCharacter == LastLastCharacter) {
- if (LastCharacter == '<') {
- Lexer->TokenType = SHELL_ARITHMETIC_SHIFT_LEFT;
- } else {
- assert(LastCharacter == '>');
- Lexer->TokenType = SHELL_ARITHMETIC_SHIFT_RIGHT;
- }
- }
- break;
- //
- // Check out characters that could stand as operators on their
- // own but were deferred to see if perhaps something else was
- // glued onto it.
- //
- case '!':
- case '*':
- case '/':
- case '%':
- case '+':
- case '-':
- case '^':
- case '&':
- case '|':
- case '=':
- Delimit = TRUE;
- AddCharacter = FALSE;
- Unput = TRUE;
- break;
- default:
- AddCharacter = TRUE;
- break;
- }
- //
- // If this character is still no longer on the table because
- // an operator is being delimited, stop now, this will come
- // back around next time.
- //
- if (AddCharacter == FALSE) {
- break;
- }
- //
- // If this is a whitespace character, delimit if there's
- // anything in the buffer and throw the whitespace away.
- //
- if (isspace(Character)) {
- AddCharacter = FALSE;
- if (Lexer->TokenBufferSize != 0) {
- Delimit = TRUE;
- }
- } else if (Lexer->TokenBufferSize == 0) {
- if ((Character >= '0') && (Character <= '9')) {
- Lexer->TokenType = SHELL_ARITHMETIC_NUMBER;
- } else {
- Lexer->TokenType = SHELL_ARITHMETIC_WORD;
- }
- }
- break;
- }
- }
- //
- // It's not expected that the someone wants to both add and unput the
- // character, as that would duplicate it.
- //
- assert((AddCharacter == FALSE) || (Unput == FALSE));
- //
- // Add, unput, or delimit the character as requested.
- //
- if (AddCharacter != FALSE) {
- assert(Character != 0);
- Result = ShAddCharacterToArithmeticToken(Lexer, Character);
- if (Result == FALSE) {
- return FALSE;
- }
- LastLastCharacter = LastCharacter;
- LastCharacter = Character;
- }
- if (Unput != FALSE) {
- assert(Lexer->InputOffset != 0);
- Lexer->InputOffset -= 1;
- }
- if (Delimit != FALSE) {
- if ((Lexer->TokenType == -1) && (Lexer->TokenBufferSize == 1)) {
- Lexer->TokenType = Lexer->TokenBuffer[0];
- }
- Result = ShAddCharacterToArithmeticToken(Lexer, '\0');
- if (Result == FALSE) {
- return FALSE;
- }
- break;
- }
- }
- assert(Lexer->TokenType != -1);
- if (ShDebugArithmeticLexer != FALSE) {
- if (Lexer->TokenType == SHELL_ARITHMETIC_END_OF_FILE) {
- ShPrintTrace(Shell, "Reached end of arithmetic expression.\n");
- } else if (Lexer->TokenType < 0xFF) {
- if (Lexer->TokenType < 0x20) {
- if (Lexer->TokenType == '\n') {
- ShPrintTrace(Shell, "%25s: \n", "<newline>");
- } else {
- ShPrintTrace(Shell, "%25d: \n", Lexer->TokenType);
- }
- } else {
- ShPrintTrace(Shell,
- "%25c: %s\n",
- Lexer->TokenType,
- Lexer->TokenBuffer);
- }
- } else {
- assert(Lexer->TokenType >= SHELL_ARITHMETIC_WORD);
- TokenStringIndex = Lexer->TokenType - SHELL_ARITHMETIC_WORD;
- ShPrintTrace(Shell,
- "%25s: %s\n",
- ShArithmeticTokenStrings[TokenStringIndex],
- Lexer->TokenBuffer);
- }
- }
- return TRUE;
- }
- BOOL
- ShAddCharacterToArithmeticToken (
- PSHELL_ARITHMETIC_LEXER Lexer,
- CHAR Character
- )
- /*++
- Routine Description:
- This routine adds the given character to the token buffer, expanding it if
- necessary.
- Arguments:
- Lexer - Supplies a pointer to the lexer to operate on.
- Character - Supplies the character to add.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- UINTN NewCapacity;
- if (Lexer->TokenBufferSize < Lexer->TokenBufferCapacity) {
- Lexer->TokenBuffer[Lexer->TokenBufferSize] = Character;
- Lexer->TokenBufferSize += 1;
- return TRUE;
- }
- //
- // Bummer, the buffer needs to be reallocated.
- //
- NewCapacity = Lexer->TokenBufferCapacity * 2;
- Lexer->TokenBuffer = realloc(Lexer->TokenBuffer, NewCapacity);
- if (Lexer->TokenBuffer == NULL) {
- printf("Error: Failed to allocate %d bytes for expanded token "
- "buffer.\n");
- return FALSE;
- }
- //
- // Now add the byte.
- //
- Lexer->TokenBufferCapacity = NewCapacity;
- Lexer->TokenBuffer[Lexer->TokenBufferSize] = Character;
- Lexer->TokenBufferSize += 1;
- return TRUE;
- }
|