arith.c 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. arith.c
  5. Abstract:
  6. This module implements arithmetic expansion for the sh shell.
  7. Author:
  8. Evan Green 7-Jun-2013
  9. Environment:
  10. POSIX
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include "sh.h"
  16. #include "shparse.h"
  17. #include <assert.h>
  18. #include <ctype.h>
  19. #include <errno.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include "../swlib.h"
  23. //
  24. // --------------------------------------------------------------------- Macros
  25. //
  26. //
  27. // This macro takes in a token type and returns non-zero if it is an assignment
  28. // operator.
  29. //
  30. #define SHELL_ARITHMETIC_ASSIGN_OPERATOR(_TokenType) \
  31. (((_TokenType) == SHELL_ARITHMETIC_MULTIPLY_ASSIGN) || \
  32. ((_TokenType) == SHELL_ARITHMETIC_DIVIDE_ASSIGN) || \
  33. ((_TokenType) == SHELL_ARITHMETIC_MODULO_ASSIGN) || \
  34. ((_TokenType) == SHELL_ARITHMETIC_ADD_ASSIGN) || \
  35. ((_TokenType) == SHELL_ARITHMETIC_SUBTRACT_ASSIGN) || \
  36. ((_TokenType) == SHELL_ARITHMETIC_LEFT_SHIFT_ASSIGN) || \
  37. ((_TokenType) == SHELL_ARITHMETIC_RIGHT_SHIFT_ASSIGN) || \
  38. ((_TokenType) == SHELL_ARITHMETIC_AND_ASSIGN) || \
  39. ((_TokenType) == SHELL_ARITHMETIC_OR_ASSIGN) || \
  40. ((_TokenType) == SHELL_ARITHMETIC_XOR_ASSIGN) || \
  41. ((_TokenType) == '='))
  42. //
  43. // This macro takes a token type and evaluates to non-zero if it could be a
  44. // unary operator.
  45. //
  46. #define SHELL_ARITHMETIC_UNARY_OPERATOR(_TokenType) \
  47. (((_TokenType) == '-') || ((_TokenType) == '+') || \
  48. ((_TokenType) == '~') || ((_TokenType) == '!')) \
  49. //
  50. // ---------------------------------------------------------------- Definitions
  51. //
  52. //
  53. // Define the size of the string buffer needed to convert an integer to a
  54. // string.
  55. //
  56. #define SHELL_ARITHMETIC_INTEGER_STRING_BUFFER_SIZE 12
  57. //
  58. // Define the initial size of the arithmetic lexer's token buffer.
  59. //
  60. #define SHELL_ARITHMETIC_INITIAL_TOKEN_BUFFER_SIZE 256
  61. //
  62. // Define arithmetic lexer tokens.
  63. //
  64. #define SHELL_ARITHMETIC_END_OF_FILE 0
  65. #define SHELL_ARITHMETIC_WORD 600
  66. #define SHELL_ARITHMETIC_NUMBER 601
  67. #define SHELL_ARITHMETIC_SHIFT_LEFT 602
  68. #define SHELL_ARITHMETIC_SHIFT_RIGHT 603
  69. #define SHELL_ARITHMETIC_LESS_THAN_OR_EQUAL 604
  70. #define SHELL_ARITHMETIC_GREATER_THAN_OR_EQUAL 605
  71. #define SHELL_ARITHMETIC_EQUALITY 606
  72. #define SHELL_ARITHMETIC_NOT_EQUAL 607
  73. #define SHELL_ARITHMETIC_LOGICAL_AND 608
  74. #define SHELL_ARITHMETIC_LOGICAL_OR 609
  75. #define SHELL_ARITHMETIC_MULTIPLY_ASSIGN 610
  76. #define SHELL_ARITHMETIC_DIVIDE_ASSIGN 611
  77. #define SHELL_ARITHMETIC_MODULO_ASSIGN 612
  78. #define SHELL_ARITHMETIC_ADD_ASSIGN 613
  79. #define SHELL_ARITHMETIC_SUBTRACT_ASSIGN 614
  80. #define SHELL_ARITHMETIC_LEFT_SHIFT_ASSIGN 615
  81. #define SHELL_ARITHMETIC_RIGHT_SHIFT_ASSIGN 616
  82. #define SHELL_ARITHMETIC_AND_ASSIGN 617
  83. #define SHELL_ARITHMETIC_OR_ASSIGN 618
  84. #define SHELL_ARITHMETIC_XOR_ASSIGN 619
  85. //
  86. // ------------------------------------------------------ Data Type Definitions
  87. //
  88. /*++
  89. Structure Description:
  90. This structure defines the state for the lexer of arithmetic expressions.
  91. Members:
  92. Input - Supplies a pointer to the input string.
  93. InputSize - Supplies the size of the input string in bytes.
  94. InputOffset - Supplies the offset of the next character to fetch.
  95. TokenType - Stores the type of token this current token represents. See
  96. SHELL_ARITHMETIC_* definitions.
  97. TokenBuffer - Stores a pointer to the buffer containing the current token.
  98. TokenBufferCapacity - Stores the total size fo the token buffer.
  99. TokenBufferSize - Stores the number of valid bytes in the token buffer.
  100. LexerPrimed - Stores a boolean indicating whether the lexer token is valid
  101. (TRUE) or uninitialized (FALSE).
  102. TokensRead - Stores the number of tokens that have been read, including
  103. this one.
  104. AssignmentName - Stores the name of the destination assignment variable.
  105. AssignmentNameSize - Stores the size of the assignment name in bytes.
  106. --*/
  107. typedef struct _SHELL_ARITHMETIC_LEXER {
  108. PSTR Input;
  109. UINTN InputSize;
  110. UINTN InputOffset;
  111. ULONG TokenType;
  112. PSTR TokenBuffer;
  113. UINTN TokenBufferCapacity;
  114. UINTN TokenBufferSize;
  115. BOOL LexerPrimed;
  116. UINTN TokensRead;
  117. PSTR AssignmentName;
  118. UINTN AssignmentNameSize;
  119. } SHELL_ARITHMETIC_LEXER, *PSHELL_ARITHMETIC_LEXER;
  120. /*++
  121. Structure Description:
  122. This structure defines an entry in the parse stack for arithmetic
  123. expressions.
  124. Members:
  125. ListEntry - Stores the next and previous elements in the parse stack.
  126. Elements get pushed onto the front of the list, so following the
  127. next pointer goes to older elements.
  128. TokenType - Stores the type of this token.
  129. Value - Stores the value for numeric tokens.
  130. --*/
  131. typedef struct SHELL_ARITHMETIC_PARSE_ELEMENT {
  132. LIST_ENTRY ListEntry;
  133. ULONG TokenType;
  134. LONG Value;
  135. } SHELL_ARITHMETIC_PARSE_ELEMENT, *PSHELL_ARITHMETIC_PARSE_ELEMENT;
  136. //
  137. // ----------------------------------------------- Internal Function Prototypes
  138. //
  139. BOOL
  140. ShParseArithmeticExpression (
  141. PSHELL Shell,
  142. PSHELL_ARITHMETIC_LEXER Lexer,
  143. BOOL Nested,
  144. PLONG ExpressionResult
  145. );
  146. BOOL
  147. ShGetNextArithmeticParseElement (
  148. PSHELL Shell,
  149. PSHELL_ARITHMETIC_LEXER Lexer,
  150. PLIST_ENTRY Stack,
  151. BOOL Nested,
  152. PSHELL_ARITHMETIC_PARSE_ELEMENT Element
  153. );
  154. BOOL
  155. ShArithmeticShiftOrReduce (
  156. PSHELL Shell,
  157. PSHELL_ARITHMETIC_LEXER Lexer,
  158. PLIST_ENTRY Stack,
  159. PSHELL_ARITHMETIC_PARSE_ELEMENT Next,
  160. PBOOL Shift
  161. );
  162. BOOL
  163. ShEvaluateArithmeticOperator (
  164. PSHELL Shell,
  165. PSHELL_ARITHMETIC_PARSE_ELEMENT LeftValue,
  166. PSHELL_ARITHMETIC_PARSE_ELEMENT Operator,
  167. PSHELL_ARITHMETIC_PARSE_ELEMENT RightValue,
  168. PLONG Result
  169. );
  170. ULONG
  171. ShGetOperatorPrecedence (
  172. ULONG TokenType
  173. );
  174. BOOL
  175. ShAssignArithmeticResult (
  176. PSHELL Shell,
  177. PSHELL_ARITHMETIC_LEXER Lexer,
  178. LONG Value
  179. );
  180. BOOL
  181. ShGetArithmeticToken (
  182. PSHELL Shell,
  183. PSHELL_ARITHMETIC_LEXER Lexer
  184. );
  185. BOOL
  186. ShAddCharacterToArithmeticToken (
  187. PSHELL_ARITHMETIC_LEXER Lexer,
  188. CHAR Character
  189. );
  190. //
  191. // -------------------------------------------------------------------- Globals
  192. //
  193. BOOL ShDebugArithmeticLexer = FALSE;
  194. BOOL ShDebugArithmeticParser = FALSE;
  195. PSTR ShArithmeticTokenStrings[] = {
  196. "ARITHMETIC_WORD",
  197. "ARITHMETIC_NUMBER",
  198. "ARITHMETIC_SHIFT_LEFT",
  199. "ARITHMETIC_SHIFT_RIGHT",
  200. "ARITHMETIC_LESS_THAN_OR_EQUAL",
  201. "ARITHMETIC_GREATER_THAN_OR_EQUAL",
  202. "ARITHMETIC_EQUALITY",
  203. "ARITHMETIC_NOT_EQUAL",
  204. "ARITHMETIC_LOGICAL_AND",
  205. "ARITHMETIC_LOGICAL_OR",
  206. "ARITHMETIC_MULTIPLY_ASSIGN",
  207. "ARITHMETIC_DIVIDE_ASSIGN",
  208. "ARITHMETIC_MODULO_ASSIGN",
  209. "ARITHMETIC_ADD_ASSIGN",
  210. "ARITHMETIC_SUBTRACT_ASSIGN",
  211. "ARITHMETIC_LEFT_SHIFT_ASSIGN",
  212. "ARITHMETIC_RIGHT_SHIFT_ASSIGN",
  213. "ARITHMETIC_AND_ASSIGN",
  214. "ARITHMETIC_OR_ASSIGN",
  215. "ARITHMETIC_XOR_ASSIGN"
  216. };
  217. //
  218. // ------------------------------------------------------------------ Functions
  219. //
  220. BOOL
  221. ShEvaluateArithmeticExpression (
  222. PSHELL Shell,
  223. PSTR String,
  224. UINTN Length,
  225. PSTR *Answer,
  226. PUINTN AnswerSize
  227. )
  228. /*++
  229. Routine Description:
  230. This routine evaluates an arithmetic expression. It assumes that all
  231. expansions have already taken place except for variable names without a
  232. dollar sign.
  233. Arguments:
  234. Shell - Supplies a pointer to the shell.
  235. String - Supplies a pointer to the input string.
  236. Length - Supplies the length of the input string in bytes.
  237. Answer - Supplies a pointer where the evaluation will be returned on
  238. success. The caller is responsible for freeing this memory.
  239. AnswerSize - Supplies a pointer where the size of the answer buffer will
  240. be returned including the null terminating byte on success.
  241. Return Value:
  242. TRUE on success.
  243. FALSE on failure.
  244. --*/
  245. {
  246. PSTR AnswerBuffer;
  247. SHELL_ARITHMETIC_LEXER Lexer;
  248. LONG NumericAnswer;
  249. BOOL Result;
  250. AnswerBuffer = NULL;
  251. memset(&Lexer, 0, sizeof(SHELL_ARITHMETIC_LEXER));
  252. Lexer.TokenBufferCapacity = SHELL_ARITHMETIC_INITIAL_TOKEN_BUFFER_SIZE;
  253. Lexer.TokenBuffer = malloc(SHELL_ARITHMETIC_INITIAL_TOKEN_BUFFER_SIZE);
  254. if (Shell->Lexer.TokenBuffer == NULL) {
  255. Result = FALSE;
  256. goto EvaluateArithmeticExpressionEnd;
  257. }
  258. Lexer.Input = String;
  259. Lexer.InputSize = Length;
  260. Result = ShParseArithmeticExpression(Shell, &Lexer, FALSE, &NumericAnswer);
  261. if (Result == FALSE) {
  262. goto EvaluateArithmeticExpressionEnd;
  263. }
  264. //
  265. // Convert the answer to a string for the caller. So nice.
  266. //
  267. AnswerBuffer = malloc(SHELL_ARITHMETIC_INTEGER_STRING_BUFFER_SIZE);
  268. if (AnswerBuffer == NULL) {
  269. Result = FALSE;
  270. goto EvaluateArithmeticExpressionEnd;
  271. }
  272. *AnswerSize = snprintf(AnswerBuffer,
  273. SHELL_ARITHMETIC_INTEGER_STRING_BUFFER_SIZE,
  274. "%d",
  275. NumericAnswer) + 1;
  276. Result = TRUE;
  277. EvaluateArithmeticExpressionEnd:
  278. if (Lexer.TokenBuffer != NULL) {
  279. free(Lexer.TokenBuffer);
  280. }
  281. if (Lexer.AssignmentName != NULL) {
  282. free(Lexer.AssignmentName);
  283. }
  284. if (Result == FALSE) {
  285. if (AnswerBuffer != NULL) {
  286. free(AnswerBuffer);
  287. AnswerBuffer = NULL;
  288. }
  289. }
  290. *Answer = AnswerBuffer;
  291. return Result;
  292. }
  293. //
  294. // --------------------------------------------------------- Internal Functions
  295. //
  296. BOOL
  297. ShParseArithmeticExpression (
  298. PSHELL Shell,
  299. PSHELL_ARITHMETIC_LEXER Lexer,
  300. BOOL Nested,
  301. PLONG ExpressionResult
  302. )
  303. /*++
  304. Routine Description:
  305. This routine parses and evaluates an arithmetic expression.
  306. Arguments:
  307. Shell - Supplies a pointer to the shell to operate on.
  308. Lexer - Supplies a pointer to the initialized and primed lexer.
  309. Nested - Supplies a boolean indicating whether this is the primary
  310. expression (FALSE) or whether this is nested as part of evaluating
  311. an expression inside parentheses or after a ? or :.
  312. ExpressionResult - Supplies a pointer where the evaluation will be returned
  313. on success.
  314. Return Value:
  315. TRUE on success.
  316. FALSE on failure.
  317. --*/
  318. {
  319. PSHELL_ARITHMETIC_PARSE_ELEMENT Element;
  320. SHELL_ARITHMETIC_PARSE_ELEMENT NextElement;
  321. BOOL Result;
  322. BOOL Shift;
  323. LIST_ENTRY Stack;
  324. INITIALIZE_LIST_HEAD(&Stack);
  325. while (TRUE) {
  326. Result = ShGetNextArithmeticParseElement(Shell,
  327. Lexer,
  328. &Stack,
  329. Nested,
  330. &NextElement);
  331. if (Result == FALSE) {
  332. break;
  333. }
  334. //
  335. // Reduce as much as possible.
  336. //
  337. do {
  338. Result = ShArithmeticShiftOrReduce(Shell,
  339. Lexer,
  340. &Stack,
  341. &NextElement,
  342. &Shift);
  343. if (Result == FALSE) {
  344. goto ParseArithmeticExpressionEnd;
  345. }
  346. } while (Shift == FALSE);
  347. //
  348. // If this was the EOF token, then the parser should be done.
  349. //
  350. if (NextElement.TokenType == SHELL_ARITHMETIC_END_OF_FILE) {
  351. //
  352. // If there's not exactly one element on the list, it's a failure.
  353. //
  354. if ((LIST_EMPTY(&Stack) != FALSE) || (Stack.Next->Next != &Stack)) {
  355. Result = FALSE;
  356. *ExpressionResult = 0;
  357. break;
  358. } else {
  359. Element = LIST_VALUE(Stack.Next,
  360. SHELL_ARITHMETIC_PARSE_ELEMENT,
  361. ListEntry);
  362. if (Element->TokenType != SHELL_ARITHMETIC_NUMBER) {
  363. Result = FALSE;
  364. *ExpressionResult = 0;
  365. } else {
  366. *ExpressionResult = Element->Value;
  367. if (Lexer->AssignmentName != NULL) {
  368. Result = ShAssignArithmeticResult(Shell,
  369. Lexer,
  370. Element->Value);
  371. if (Result == FALSE) {
  372. goto ParseArithmeticExpressionEnd;
  373. }
  374. }
  375. Result = TRUE;
  376. break;
  377. }
  378. }
  379. } else {
  380. Element = malloc(sizeof(SHELL_ARITHMETIC_PARSE_ELEMENT));
  381. if (Element == NULL) {
  382. Result = FALSE;
  383. goto ParseArithmeticExpressionEnd;
  384. }
  385. memcpy(Element,
  386. &NextElement,
  387. sizeof(SHELL_ARITHMETIC_PARSE_ELEMENT));
  388. INSERT_AFTER(&(Element->ListEntry), &Stack);
  389. }
  390. }
  391. ParseArithmeticExpressionEnd:
  392. while (LIST_EMPTY(&Stack) == FALSE) {
  393. Element = LIST_VALUE(Stack.Next,
  394. SHELL_ARITHMETIC_PARSE_ELEMENT,
  395. ListEntry);
  396. LIST_REMOVE(&(Element->ListEntry));
  397. free(Element);
  398. }
  399. if (ShDebugArithmeticParser != FALSE) {
  400. if (Result != FALSE) {
  401. ShPrintTrace(Shell, "Arithmetic Result: %ld\n", *ExpressionResult);
  402. } else {
  403. ShPrintTrace(Shell,
  404. "Error: Failed to parse arithmetic expression.\n");
  405. }
  406. }
  407. return Result;
  408. }
  409. BOOL
  410. ShGetNextArithmeticParseElement (
  411. PSHELL Shell,
  412. PSHELL_ARITHMETIC_LEXER Lexer,
  413. PLIST_ENTRY Stack,
  414. BOOL Nested,
  415. PSHELL_ARITHMETIC_PARSE_ELEMENT Element
  416. )
  417. /*++
  418. Routine Description:
  419. This routine retrieves the next parse element for an arithmetic expression.
  420. Arguments:
  421. Shell - Supplies a pointer to the shell to operate on.
  422. Lexer - Supplies a pointer to the initialized lexer.
  423. Stack - Supplies a pointer to the parsing stack.
  424. Nested - Supplies a boolean indicating whether this is the primary
  425. expression (FALSE) or whether this is nested as part of evaluating
  426. an expression inside parentheses or after a ? or :.
  427. Element - Supplies a pointer where the filled out element will be returned.
  428. Return Value:
  429. TRUE on success.
  430. FALSE on failure.
  431. --*/
  432. {
  433. PSTR AfterScan;
  434. LONG FalseValue;
  435. BOOL IsName;
  436. BOOL Result;
  437. PSHELL_ARITHMETIC_PARSE_ELEMENT Top;
  438. LONG TrueValue;
  439. LONG Value;
  440. PSTR ValueString;
  441. UINTN ValueStringSize;
  442. Result = ShGetArithmeticToken(Shell, Lexer);
  443. if (Result == FALSE) {
  444. return FALSE;
  445. }
  446. if ((Lexer->TokenType == SHELL_ARITHMETIC_NUMBER) ||
  447. (Lexer->TokenType == SHELL_ARITHMETIC_WORD)) {
  448. if (Lexer->TokenType == SHELL_ARITHMETIC_WORD) {
  449. Result = ShGetVariable(Shell,
  450. Lexer->TokenBuffer,
  451. Lexer->TokenBufferSize,
  452. &ValueString,
  453. &ValueStringSize);
  454. if (Result == FALSE) {
  455. ValueString = NULL;
  456. }
  457. //
  458. // Variables need to be valid names.
  459. //
  460. IsName = ShIsName(Lexer->TokenBuffer, Lexer->TokenBufferSize);
  461. if (IsName == FALSE) {
  462. return FALSE;
  463. }
  464. //
  465. // If this is the first token and it's a variable name, save it
  466. // in case it's an assignment.
  467. //
  468. if (Lexer->TokensRead == 1) {
  469. assert(Lexer->AssignmentName == NULL);
  470. Lexer->AssignmentName = SwStringDuplicate(
  471. Lexer->TokenBuffer,
  472. Lexer->TokenBufferSize);
  473. if (Lexer->AssignmentName == NULL) {
  474. return FALSE;
  475. }
  476. Lexer->AssignmentNameSize = Lexer->TokenBufferSize;
  477. }
  478. } else {
  479. ValueString = Lexer->TokenBuffer;
  480. ValueStringSize = Lexer->TokenBufferSize;
  481. }
  482. //
  483. // If there's a buffer, attempt to convert it to a number.
  484. //
  485. Value = 0;
  486. if (ValueString != NULL) {
  487. Value = strtol(ValueString, &AfterScan, 0);
  488. if ((UINTN)AfterScan != (UINTN)ValueString + ValueStringSize - 1) {
  489. Result = FALSE;
  490. return FALSE;
  491. }
  492. }
  493. Element->TokenType = SHELL_ARITHMETIC_NUMBER;
  494. Element->Value = Value;
  495. return TRUE;
  496. } else if (Lexer->TokenType == '(') {
  497. Result = ShParseArithmeticExpression(Shell, Lexer, TRUE, &Value);
  498. if (Result == FALSE) {
  499. return FALSE;
  500. }
  501. if (Lexer->TokenType != ')') {
  502. return FALSE;
  503. }
  504. Element->TokenType = SHELL_ARITHMETIC_NUMBER;
  505. Element->Value = Value;
  506. return TRUE;
  507. //
  508. // The question mark ternary operator is also recursive, as it requires two
  509. // full expressions. This cheats and does a bit of reducing which isn't
  510. // ideal architecturally but seeing as it's the only thing that does this
  511. // and I'm a little tipsy we'll let it slide.
  512. //
  513. } else if (Lexer->TokenType == '?') {
  514. Result = ShParseArithmeticExpression(Shell, Lexer, TRUE, &TrueValue);
  515. if (Result == FALSE) {
  516. return FALSE;
  517. }
  518. if (Lexer->TokenType != ':') {
  519. return FALSE;
  520. }
  521. Result = ShParseArithmeticExpression(Shell, Lexer, TRUE, &FalseValue);
  522. if (Result == FALSE) {
  523. return FALSE;
  524. }
  525. Top = LIST_VALUE(Stack->Next,
  526. SHELL_ARITHMETIC_PARSE_ELEMENT,
  527. ListEntry);
  528. if ((LIST_EMPTY(Stack) != FALSE) ||
  529. (Top->TokenType != SHELL_ARITHMETIC_NUMBER)) {
  530. return FALSE;
  531. }
  532. if (Top->Value != 0) {
  533. Value = TrueValue;
  534. } else {
  535. Value = FalseValue;
  536. }
  537. if (ShDebugArithmeticParser != FALSE) {
  538. ShPrintTrace(Shell,
  539. "arith: %ld <== %ld ? %ld : %ld\n",
  540. Value,
  541. Top->Value,
  542. TrueValue,
  543. FalseValue);
  544. }
  545. Top->Value = Value;
  546. Element->TokenType = SHELL_ARITHMETIC_END_OF_FILE;
  547. Element->Value = 0;
  548. return TRUE;
  549. //
  550. // If this is a closing parentheses or colon and it's nested, that's the
  551. // end of the line for the inner nested one. If it's not nested, then this
  552. // is a bad random close parentheses.
  553. //
  554. } else if ((Lexer->TokenType == ')') || (Lexer->TokenType == ':')) {
  555. if (Nested != FALSE) {
  556. Element->TokenType = SHELL_ARITHMETIC_END_OF_FILE;
  557. Element->Value = 0;
  558. return TRUE;
  559. } else {
  560. return FALSE;
  561. }
  562. }
  563. Element->TokenType = Lexer->TokenType;
  564. Element->Value = 0;
  565. return TRUE;
  566. }
  567. BOOL
  568. ShArithmeticShiftOrReduce (
  569. PSHELL Shell,
  570. PSHELL_ARITHMETIC_LEXER Lexer,
  571. PLIST_ENTRY Stack,
  572. PSHELL_ARITHMETIC_PARSE_ELEMENT Next,
  573. PBOOL Shift
  574. )
  575. /*++
  576. Routine Description:
  577. This routine attempts to reduce the given parse stack if possible, or
  578. directs the caller to shift.
  579. Arguments:
  580. Shell - Supplies a pointer to the shell to operate on.
  581. Lexer - Supplies a pointer to the initialized lexer.
  582. Stack - Supplies a pointer to the head of the parse stack.
  583. Next - Supplies a pointer to the next element.
  584. Shift - Supplies a boolean where TRUE will be returned if more values
  585. should be shifted onto the stack. Or FALSE if the stack was reduced.
  586. Return Value:
  587. TRUE on success.
  588. FALSE on failure.
  589. --*/
  590. {
  591. LONG Answer;
  592. ULONG NextPrecedence;
  593. ULONG NextToken;
  594. PSHELL_ARITHMETIC_PARSE_ELEMENT Operator;
  595. BOOL Result;
  596. ULONG StackPrecedence;
  597. PSHELL_ARITHMETIC_PARSE_ELEMENT Top;
  598. PSHELL_ARITHMETIC_PARSE_ELEMENT TwoBack;
  599. *Shift = FALSE;
  600. if (LIST_EMPTY(Stack) != FALSE) {
  601. *Shift = TRUE;
  602. return TRUE;
  603. }
  604. Top = LIST_VALUE(Stack->Next, SHELL_ARITHMETIC_PARSE_ELEMENT, ListEntry);
  605. //
  606. // Assignment operators are only allowed as the second value in an
  607. // expression (with the first being an assignment word).
  608. //
  609. NextToken = Next->TokenType;
  610. assert(NextToken != SHELL_ARITHMETIC_WORD);
  611. if (SHELL_ARITHMETIC_ASSIGN_OPERATOR(NextToken)) {
  612. if ((Lexer->TokensRead != 2) || (Lexer->AssignmentName == NULL)) {
  613. return FALSE;
  614. }
  615. //
  616. // If it's token 2 and not an assignment operator, free up the assignment
  617. // word.
  618. //
  619. } else if (Lexer->TokensRead == 2) {
  620. if (Lexer->AssignmentName != NULL) {
  621. free(Lexer->AssignmentName);
  622. Lexer->AssignmentName = NULL;
  623. }
  624. }
  625. if (Top->TokenType == SHELL_ARITHMETIC_NUMBER) {
  626. //
  627. // If that's all that's on the list, definitely shift, unless this
  628. // next token is another number which is invalid.
  629. //
  630. if (Top->ListEntry.Next == Stack) {
  631. if (Next->TokenType == SHELL_ARITHMETIC_NUMBER) {
  632. return FALSE;
  633. }
  634. *Shift = TRUE;
  635. return TRUE;
  636. }
  637. //
  638. // Get the operator down there and let's find out what it is.
  639. //
  640. Operator = LIST_VALUE(Top->ListEntry.Next,
  641. SHELL_ARITHMETIC_PARSE_ELEMENT,
  642. ListEntry);
  643. TwoBack = LIST_VALUE(Operator->ListEntry.Next,
  644. SHELL_ARITHMETIC_PARSE_ELEMENT,
  645. ListEntry);
  646. if (Operator->ListEntry.Next == Stack) {
  647. TwoBack = NULL;
  648. }
  649. //
  650. // If it's a plus or a minus, this could be a unary plus or minus, in
  651. // which case it should be reduced. It's known to be a unary operator
  652. // if there's not a number behind it. It could also be a binary plus
  653. // or minus, in which case it's left alone.
  654. //
  655. if ((Operator->TokenType == '+') || (Operator->TokenType == '-')) {
  656. if ((TwoBack == NULL) ||
  657. (TwoBack->TokenType != SHELL_ARITHMETIC_NUMBER)) {
  658. //
  659. // Reduce the unary + or minus and return.
  660. //
  661. LIST_REMOVE(&(Top->ListEntry));
  662. if (Operator->TokenType == '-') {
  663. Operator->Value = -Top->Value;
  664. } else {
  665. Operator->Value = Top->Value;
  666. }
  667. Operator->TokenType = Top->TokenType;
  668. free(Top);
  669. return TRUE;
  670. }
  671. } else if (SHELL_ARITHMETIC_UNARY_OPERATOR(Operator->TokenType)) {
  672. TwoBack = NULL;
  673. }
  674. StackPrecedence = ShGetOperatorPrecedence(Operator->TokenType);
  675. assert(StackPrecedence != -1);
  676. NextPrecedence = ShGetOperatorPrecedence(Next->TokenType);
  677. //
  678. // If the next thing is not an operator, then fail now.
  679. //
  680. if (NextPrecedence == -1) {
  681. return FALSE;
  682. }
  683. //
  684. // If the operator on the stack has equal or higher precedence than the
  685. // next operator, then reduce, otherwise shift.
  686. //
  687. if (StackPrecedence >= NextPrecedence) {
  688. assert((TwoBack == NULL) ||
  689. (TwoBack->TokenType == SHELL_ARITHMETIC_NUMBER));
  690. Result = ShEvaluateArithmeticOperator(Shell,
  691. TwoBack,
  692. Operator,
  693. Top,
  694. &Answer);
  695. if (Result == FALSE) {
  696. return FALSE;
  697. }
  698. LIST_REMOVE(&(Top->ListEntry));
  699. free(Top);
  700. if (TwoBack != NULL) {
  701. LIST_REMOVE(&(Operator->ListEntry));
  702. free(Operator);
  703. Operator = TwoBack;
  704. }
  705. Operator->TokenType = SHELL_ARITHMETIC_NUMBER;
  706. Operator->Value = Answer;
  707. } else {
  708. *Shift = TRUE;
  709. }
  710. return TRUE;
  711. }
  712. //
  713. // If what's coming next is a number, then let it on for sure.
  714. //
  715. if (NextToken == SHELL_ARITHMETIC_NUMBER) {
  716. *Shift = TRUE;
  717. return TRUE;
  718. }
  719. //
  720. // What's next is an operator. Only allow it if it is a unary operator.
  721. //
  722. if (!SHELL_ARITHMETIC_UNARY_OPERATOR(NextToken)) {
  723. return FALSE;
  724. }
  725. *Shift = TRUE;
  726. return TRUE;
  727. }
  728. BOOL
  729. ShEvaluateArithmeticOperator (
  730. PSHELL Shell,
  731. PSHELL_ARITHMETIC_PARSE_ELEMENT LeftValue,
  732. PSHELL_ARITHMETIC_PARSE_ELEMENT Operator,
  733. PSHELL_ARITHMETIC_PARSE_ELEMENT RightValue,
  734. PLONG Result
  735. )
  736. /*++
  737. Routine Description:
  738. This routine performs an arithmetic operation on two values.
  739. Arguments:
  740. Shell - Supplies a pointer to the shell.
  741. LeftValue - Supplies a pointer to the left operand.
  742. Operator - Supplies a pointer to the operator.
  743. RightValue - Supplies a pointer to the right operand.
  744. Result - Supplies a pointer where the resulting value will be returned on
  745. success.
  746. Return Value:
  747. TRUE on success.
  748. FALSE on failure.
  749. --*/
  750. {
  751. LONG Answer;
  752. CHAR DebugOperator[2];
  753. LONG Left;
  754. LONG Right;
  755. assert(((LeftValue == NULL) ||
  756. (LeftValue->TokenType == SHELL_ARITHMETIC_NUMBER)) &&
  757. (RightValue->TokenType == SHELL_ARITHMETIC_NUMBER));
  758. Left = 0;
  759. if (LeftValue != 0) {
  760. Left = LeftValue->Value;
  761. }
  762. Right = RightValue->Value;
  763. DebugOperator[0] = (CHAR)Operator->TokenType;
  764. if (Operator->TokenType < 0x100) {
  765. DebugOperator[1] = ' ';
  766. } else {
  767. DebugOperator[1] = '=';
  768. }
  769. switch (Operator->TokenType) {
  770. case SHELL_ARITHMETIC_LEFT_SHIFT_ASSIGN:
  771. case SHELL_ARITHMETIC_SHIFT_LEFT:
  772. DebugOperator[0] = '<';
  773. DebugOperator[1] = '<';
  774. Answer = Left << Right;
  775. break;
  776. case SHELL_ARITHMETIC_RIGHT_SHIFT_ASSIGN:
  777. case SHELL_ARITHMETIC_SHIFT_RIGHT:
  778. DebugOperator[0] = '>';
  779. DebugOperator[1] = '>';
  780. Answer = Left >> Right;
  781. break;
  782. case SHELL_ARITHMETIC_LESS_THAN_OR_EQUAL:
  783. DebugOperator[0] = '<';
  784. Answer = Left <= Right;
  785. break;
  786. case SHELL_ARITHMETIC_GREATER_THAN_OR_EQUAL:
  787. DebugOperator[0] = '>';
  788. Answer = Left >= Right;
  789. break;
  790. case SHELL_ARITHMETIC_EQUALITY:
  791. DebugOperator[0] = '=';
  792. Answer = Left == Right;
  793. break;
  794. case SHELL_ARITHMETIC_NOT_EQUAL:
  795. DebugOperator[0] = '!';
  796. Answer = Left != Right;
  797. break;
  798. case SHELL_ARITHMETIC_LOGICAL_AND:
  799. DebugOperator[0] = '&';
  800. DebugOperator[1] = '&';
  801. Answer = Left && Right;
  802. break;
  803. case SHELL_ARITHMETIC_LOGICAL_OR:
  804. DebugOperator[0] = '|';
  805. DebugOperator[1] = '|';
  806. Answer = Left || Right;
  807. break;
  808. case '~':
  809. Answer = ~Right;
  810. break;
  811. case '!':
  812. Answer = !Right;
  813. break;
  814. case SHELL_ARITHMETIC_MULTIPLY_ASSIGN:
  815. case '*':
  816. DebugOperator[0] = '*';
  817. Answer = Left * Right;
  818. break;
  819. case SHELL_ARITHMETIC_DIVIDE_ASSIGN:
  820. case '/':
  821. DebugOperator[0] = '/';
  822. Answer = Left / Right;
  823. break;
  824. case SHELL_ARITHMETIC_MODULO_ASSIGN:
  825. case '%':
  826. DebugOperator[0] = '%';
  827. Answer = Left % Right;
  828. break;
  829. case SHELL_ARITHMETIC_ADD_ASSIGN:
  830. case '+':
  831. DebugOperator[0] = '+';
  832. Answer = Left + Right;
  833. break;
  834. case SHELL_ARITHMETIC_SUBTRACT_ASSIGN:
  835. case '-':
  836. DebugOperator[0] = '-';
  837. Answer = Left - Right;
  838. break;
  839. case '<':
  840. Answer = Left < Right;
  841. break;
  842. case '>':
  843. Answer = Left > Right;
  844. break;
  845. case '=':
  846. Answer = Right;
  847. break;
  848. case SHELL_ARITHMETIC_AND_ASSIGN:
  849. case '&':
  850. DebugOperator[0] = '&';
  851. Answer = Left & Right;
  852. break;
  853. case SHELL_ARITHMETIC_OR_ASSIGN:
  854. case '|':
  855. DebugOperator[0] = '|';
  856. Answer = Left | Right;
  857. break;
  858. case SHELL_ARITHMETIC_XOR_ASSIGN:
  859. case '^':
  860. DebugOperator[0] = '^';
  861. Answer = Left ^ Right;
  862. break;
  863. default:
  864. assert(FALSE);
  865. return FALSE;
  866. }
  867. if (ShDebugArithmeticParser != FALSE) {
  868. ShPrintTrace(Shell,
  869. "Arith: %ld <== %ld %c%c %ld\n",
  870. Answer,
  871. Left,
  872. DebugOperator[0],
  873. DebugOperator[1],
  874. Right);
  875. }
  876. *Result = Answer;
  877. return TRUE;
  878. }
  879. ULONG
  880. ShGetOperatorPrecedence (
  881. ULONG TokenType
  882. )
  883. /*++
  884. Routine Description:
  885. This routine gives a ranking for the given operator. Higher numbers mean
  886. greater precence.
  887. Arguments:
  888. TokenType - Supplies the operator to rank.
  889. Return Value:
  890. Returns a value representing the operator's ranking. Higher number bind
  891. tighter to their arguments.
  892. -1 if the token is not an operator.
  893. --*/
  894. {
  895. switch (TokenType) {
  896. case SHELL_ARITHMETIC_END_OF_FILE:
  897. return 0;
  898. case SHELL_ARITHMETIC_MULTIPLY_ASSIGN:
  899. case SHELL_ARITHMETIC_DIVIDE_ASSIGN:
  900. case SHELL_ARITHMETIC_MODULO_ASSIGN:
  901. case SHELL_ARITHMETIC_ADD_ASSIGN:
  902. case SHELL_ARITHMETIC_SUBTRACT_ASSIGN:
  903. case SHELL_ARITHMETIC_LEFT_SHIFT_ASSIGN:
  904. case SHELL_ARITHMETIC_RIGHT_SHIFT_ASSIGN:
  905. case SHELL_ARITHMETIC_AND_ASSIGN:
  906. case SHELL_ARITHMETIC_OR_ASSIGN:
  907. case SHELL_ARITHMETIC_XOR_ASSIGN:
  908. case '=':
  909. return 1;
  910. case '?':
  911. return 2;
  912. case ':':
  913. return 3;
  914. case SHELL_ARITHMETIC_LOGICAL_OR:
  915. return 4;
  916. case SHELL_ARITHMETIC_LOGICAL_AND:
  917. return 5;
  918. case '|':
  919. return 6;
  920. case '^':
  921. return 7;
  922. case '&':
  923. return 8;
  924. case SHELL_ARITHMETIC_NOT_EQUAL:
  925. case SHELL_ARITHMETIC_EQUALITY:
  926. return 9;
  927. case SHELL_ARITHMETIC_LESS_THAN_OR_EQUAL:
  928. case SHELL_ARITHMETIC_GREATER_THAN_OR_EQUAL:
  929. case '<':
  930. case '>':
  931. return 10;
  932. case SHELL_ARITHMETIC_SHIFT_LEFT:
  933. case SHELL_ARITHMETIC_SHIFT_RIGHT:
  934. return 11;
  935. case '+':
  936. case '-':
  937. return 12;
  938. case '*':
  939. case '/':
  940. case '%':
  941. return 13;
  942. case '~':
  943. case '!':
  944. return 14;
  945. default:
  946. break;
  947. }
  948. assert(FALSE);
  949. return 0;
  950. }
  951. BOOL
  952. ShAssignArithmeticResult (
  953. PSHELL Shell,
  954. PSHELL_ARITHMETIC_LEXER Lexer,
  955. LONG Value
  956. )
  957. /*++
  958. Routine Description:
  959. This routine performs an assignment of an arithmetic result to a shell
  960. environment variable.
  961. Arguments:
  962. Shell - Supplies a pointer to the shell to operate on.
  963. Lexer - Supplies a pointer to the initialized lexer.
  964. Value - Supplies the numeric value to assign.
  965. Return Value:
  966. TRUE on success.
  967. FALSE on failure.
  968. --*/
  969. {
  970. BOOL Result;
  971. CHAR StringBuffer[SHELL_ARITHMETIC_INTEGER_STRING_BUFFER_SIZE];
  972. UINTN StringSize;
  973. StringSize = snprintf(StringBuffer,
  974. SHELL_ARITHMETIC_INTEGER_STRING_BUFFER_SIZE,
  975. "%d",
  976. Value) + 1;
  977. assert((Lexer->AssignmentName != NULL) && (Lexer->AssignmentNameSize != 0));
  978. Result = ShSetVariable(Shell,
  979. Lexer->AssignmentName,
  980. Lexer->AssignmentNameSize,
  981. StringBuffer,
  982. StringSize);
  983. return Result;
  984. }
  985. BOOL
  986. ShGetArithmeticToken (
  987. PSHELL Shell,
  988. PSHELL_ARITHMETIC_LEXER Lexer
  989. )
  990. /*++
  991. Routine Description:
  992. This routine gets a token for the arithmetic lexer.
  993. Arguments:
  994. Shell - Supplies a pointer to the shell.
  995. Lexer - Supplies a pointer to the lexer to operate on.
  996. Return Value:
  997. TRUE on success.
  998. FALSE on failure.
  999. --*/
  1000. {
  1001. CHAR AddCharacter;
  1002. CHAR Character;
  1003. BOOL Delimit;
  1004. CHAR LastCharacter;
  1005. CHAR LastLastCharacter;
  1006. BOOL Result;
  1007. UINTN TokenStringIndex;
  1008. BOOL Unput;
  1009. Character = 0;
  1010. LastCharacter = 0;
  1011. LastLastCharacter = 0;
  1012. Lexer->TokenType = -1;
  1013. Lexer->TokenBufferSize = 0;
  1014. Lexer->TokensRead += 1;
  1015. Delimit = FALSE;
  1016. while (TRUE) {
  1017. AddCharacter = TRUE;
  1018. Unput = FALSE;
  1019. //
  1020. // If the end of the buffer came around, delimit the current token, or
  1021. // return the EOF token.
  1022. //
  1023. if ((Lexer->InputOffset == Lexer->InputSize) ||
  1024. (Lexer->Input[Lexer->InputOffset] == '\0')) {
  1025. AddCharacter = FALSE;
  1026. Delimit = TRUE;
  1027. if (Lexer->TokenBufferSize == 0) {
  1028. Lexer->TokenType = SHELL_ARITHMETIC_END_OF_FILE;
  1029. }
  1030. } else {
  1031. Character = Lexer->Input[Lexer->InputOffset];
  1032. Lexer->InputOffset += 1;
  1033. switch (Character) {
  1034. //
  1035. // These characters are operators all by themselves, and only ever
  1036. // by themselves.
  1037. //
  1038. case '~':
  1039. case '?':
  1040. case ':':
  1041. case '(':
  1042. case ')':
  1043. Delimit = TRUE;
  1044. if (Lexer->TokenBufferSize != 0) {
  1045. AddCharacter = FALSE;
  1046. Unput = TRUE;
  1047. }
  1048. break;
  1049. //
  1050. // This next batch of symbols either stands by itself or can only
  1051. // have an equals after it (and is only ever the first character
  1052. // in a double symbol).
  1053. //
  1054. case '!':
  1055. case '*':
  1056. case '/':
  1057. case '%':
  1058. case '+':
  1059. case '-':
  1060. case '^':
  1061. if (Lexer->TokenBufferSize != 0) {
  1062. Delimit = TRUE;
  1063. AddCharacter = FALSE;
  1064. Unput = TRUE;
  1065. }
  1066. break;
  1067. //
  1068. // The & and | symbols could either be on their own, with an
  1069. // equals (&= |=) or with themselves (&& ||).
  1070. //
  1071. case '&':
  1072. case '|':
  1073. if (LastCharacter == Character) {
  1074. Delimit = TRUE;
  1075. if (Character == '&') {
  1076. Lexer->TokenType = SHELL_ARITHMETIC_LOGICAL_AND;
  1077. } else {
  1078. assert(Character == '|');
  1079. Lexer->TokenType = SHELL_ARITHMETIC_LOGICAL_OR;
  1080. }
  1081. //
  1082. // Besides && and ||, these symbols are always the first in an
  1083. // operator, so if there's something in the buffer flush it
  1084. // out.
  1085. //
  1086. } else if (Lexer->TokenBufferSize != 0) {
  1087. Delimit = TRUE;
  1088. AddCharacter = FALSE;
  1089. Unput = TRUE;
  1090. }
  1091. break;
  1092. //
  1093. // The > and < symbols could either be by themselves, doubled
  1094. // (<< >>), with an equals after them (>= <=), or double and with
  1095. // and equals after them (>>= <<=). The only way they can be
  1096. // delimited for sure now is if the last character wasn't the same
  1097. // as this one.
  1098. //
  1099. case '<':
  1100. case '>':
  1101. if ((Lexer->TokenBufferSize != 0) &&
  1102. (LastCharacter != Character)) {
  1103. Delimit = TRUE;
  1104. AddCharacter = FALSE;
  1105. Unput = TRUE;
  1106. }
  1107. break;
  1108. //
  1109. // The all important equal sign. It can be by itself, or with 1 or
  1110. // 2 characters in front of it.
  1111. //
  1112. case '=':
  1113. //
  1114. // If it's not the first character in the buffer, it's always
  1115. // the last.
  1116. //
  1117. if (Lexer->TokenBufferSize != 0) {
  1118. Delimit = TRUE;
  1119. }
  1120. switch (LastCharacter) {
  1121. case '!':
  1122. Lexer->TokenType = SHELL_ARITHMETIC_NOT_EQUAL;
  1123. break;
  1124. case '=':
  1125. Lexer->TokenType = SHELL_ARITHMETIC_EQUALITY;
  1126. break;
  1127. case '&':
  1128. Lexer->TokenType = SHELL_ARITHMETIC_AND_ASSIGN;
  1129. break;
  1130. case '|':
  1131. Lexer->TokenType = SHELL_ARITHMETIC_OR_ASSIGN;
  1132. break;
  1133. case '+':
  1134. Lexer->TokenType = SHELL_ARITHMETIC_ADD_ASSIGN;
  1135. break;
  1136. case '-':
  1137. Lexer->TokenType = SHELL_ARITHMETIC_SUBTRACT_ASSIGN;
  1138. break;
  1139. case '*':
  1140. Lexer->TokenType = SHELL_ARITHMETIC_MULTIPLY_ASSIGN;
  1141. break;
  1142. case '/':
  1143. Lexer->TokenType = SHELL_ARITHMETIC_DIVIDE_ASSIGN;
  1144. break;
  1145. case '%':
  1146. Lexer->TokenType = SHELL_ARITHMETIC_MODULO_ASSIGN;
  1147. break;
  1148. case '^':
  1149. Lexer->TokenType = SHELL_ARITHMETIC_XOR_ASSIGN;
  1150. break;
  1151. case '>':
  1152. Lexer->TokenType = SHELL_ARITHMETIC_GREATER_THAN_OR_EQUAL;
  1153. if (LastLastCharacter == '>') {
  1154. Lexer->TokenType = SHELL_ARITHMETIC_RIGHT_SHIFT_ASSIGN;
  1155. }
  1156. break;
  1157. case '<':
  1158. Lexer->TokenType = SHELL_ARITHMETIC_LESS_THAN_OR_EQUAL;
  1159. if (LastLastCharacter == '<') {
  1160. Lexer->TokenType = SHELL_ARITHMETIC_LEFT_SHIFT_ASSIGN;
  1161. }
  1162. break;
  1163. //
  1164. // If the last character was nothing, an operator that can't
  1165. // have an equals sign glued onto it, or an average joe
  1166. // character then either delimit the previous token or don't
  1167. // delimit and see if another equals comes in.
  1168. //
  1169. default:
  1170. if (Lexer->TokenBufferSize != 0) {
  1171. AddCharacter = FALSE;
  1172. Unput = TRUE;
  1173. }
  1174. break;
  1175. }
  1176. break;
  1177. //
  1178. // This is an average joe character, either a digit, letter, or
  1179. // space of some kind. Look to see if an operator that might have
  1180. // been two or three characters but wasn't just ended.
  1181. //
  1182. default:
  1183. AddCharacter = FALSE;
  1184. switch (LastCharacter) {
  1185. case '<':
  1186. case '>':
  1187. Delimit = TRUE;
  1188. AddCharacter = FALSE;
  1189. Unput = TRUE;
  1190. if (LastCharacter == LastLastCharacter) {
  1191. if (LastCharacter == '<') {
  1192. Lexer->TokenType = SHELL_ARITHMETIC_SHIFT_LEFT;
  1193. } else {
  1194. assert(LastCharacter == '>');
  1195. Lexer->TokenType = SHELL_ARITHMETIC_SHIFT_RIGHT;
  1196. }
  1197. }
  1198. break;
  1199. //
  1200. // Check out characters that could stand as operators on their
  1201. // own but were deferred to see if perhaps something else was
  1202. // glued onto it.
  1203. //
  1204. case '!':
  1205. case '*':
  1206. case '/':
  1207. case '%':
  1208. case '+':
  1209. case '-':
  1210. case '^':
  1211. case '&':
  1212. case '|':
  1213. case '=':
  1214. Delimit = TRUE;
  1215. AddCharacter = FALSE;
  1216. Unput = TRUE;
  1217. break;
  1218. default:
  1219. AddCharacter = TRUE;
  1220. break;
  1221. }
  1222. //
  1223. // If this character is still no longer on the table because
  1224. // an operator is being delimited, stop now, this will come
  1225. // back around next time.
  1226. //
  1227. if (AddCharacter == FALSE) {
  1228. break;
  1229. }
  1230. //
  1231. // If this is a whitespace character, delimit if there's
  1232. // anything in the buffer and throw the whitespace away.
  1233. //
  1234. if (isspace(Character)) {
  1235. AddCharacter = FALSE;
  1236. if (Lexer->TokenBufferSize != 0) {
  1237. Delimit = TRUE;
  1238. }
  1239. } else if (Lexer->TokenBufferSize == 0) {
  1240. if ((Character >= '0') && (Character <= '9')) {
  1241. Lexer->TokenType = SHELL_ARITHMETIC_NUMBER;
  1242. } else {
  1243. Lexer->TokenType = SHELL_ARITHMETIC_WORD;
  1244. }
  1245. }
  1246. break;
  1247. }
  1248. }
  1249. //
  1250. // It's not expected that the someone wants to both add and unput the
  1251. // character, as that would duplicate it.
  1252. //
  1253. assert((AddCharacter == FALSE) || (Unput == FALSE));
  1254. //
  1255. // Add, unput, or delimit the character as requested.
  1256. //
  1257. if (AddCharacter != FALSE) {
  1258. assert(Character != 0);
  1259. Result = ShAddCharacterToArithmeticToken(Lexer, Character);
  1260. if (Result == FALSE) {
  1261. return FALSE;
  1262. }
  1263. LastLastCharacter = LastCharacter;
  1264. LastCharacter = Character;
  1265. }
  1266. if (Unput != FALSE) {
  1267. assert(Lexer->InputOffset != 0);
  1268. Lexer->InputOffset -= 1;
  1269. }
  1270. if (Delimit != FALSE) {
  1271. if ((Lexer->TokenType == -1) && (Lexer->TokenBufferSize == 1)) {
  1272. Lexer->TokenType = Lexer->TokenBuffer[0];
  1273. }
  1274. Result = ShAddCharacterToArithmeticToken(Lexer, '\0');
  1275. if (Result == FALSE) {
  1276. return FALSE;
  1277. }
  1278. break;
  1279. }
  1280. }
  1281. assert(Lexer->TokenType != -1);
  1282. if (ShDebugArithmeticLexer != FALSE) {
  1283. if (Lexer->TokenType == SHELL_ARITHMETIC_END_OF_FILE) {
  1284. ShPrintTrace(Shell, "Reached end of arithmetic expression.\n");
  1285. } else if (Lexer->TokenType < 0xFF) {
  1286. if (Lexer->TokenType < 0x20) {
  1287. if (Lexer->TokenType == '\n') {
  1288. ShPrintTrace(Shell, "%25s: \n", "<newline>");
  1289. } else {
  1290. ShPrintTrace(Shell, "%25d: \n", Lexer->TokenType);
  1291. }
  1292. } else {
  1293. ShPrintTrace(Shell,
  1294. "%25c: %s\n",
  1295. Lexer->TokenType,
  1296. Lexer->TokenBuffer);
  1297. }
  1298. } else {
  1299. assert(Lexer->TokenType >= SHELL_ARITHMETIC_WORD);
  1300. TokenStringIndex = Lexer->TokenType - SHELL_ARITHMETIC_WORD;
  1301. ShPrintTrace(Shell,
  1302. "%25s: %s\n",
  1303. ShArithmeticTokenStrings[TokenStringIndex],
  1304. Lexer->TokenBuffer);
  1305. }
  1306. }
  1307. return TRUE;
  1308. }
  1309. BOOL
  1310. ShAddCharacterToArithmeticToken (
  1311. PSHELL_ARITHMETIC_LEXER Lexer,
  1312. CHAR Character
  1313. )
  1314. /*++
  1315. Routine Description:
  1316. This routine adds the given character to the token buffer, expanding it if
  1317. necessary.
  1318. Arguments:
  1319. Lexer - Supplies a pointer to the lexer to operate on.
  1320. Character - Supplies the character to add.
  1321. Return Value:
  1322. TRUE on success.
  1323. FALSE on failure.
  1324. --*/
  1325. {
  1326. UINTN NewCapacity;
  1327. if (Lexer->TokenBufferSize < Lexer->TokenBufferCapacity) {
  1328. Lexer->TokenBuffer[Lexer->TokenBufferSize] = Character;
  1329. Lexer->TokenBufferSize += 1;
  1330. return TRUE;
  1331. }
  1332. //
  1333. // Bummer, the buffer needs to be reallocated.
  1334. //
  1335. NewCapacity = Lexer->TokenBufferCapacity * 2;
  1336. Lexer->TokenBuffer = realloc(Lexer->TokenBuffer, NewCapacity);
  1337. if (Lexer->TokenBuffer == NULL) {
  1338. printf("Error: Failed to allocate %d bytes for expanded token "
  1339. "buffer.\n");
  1340. return FALSE;
  1341. }
  1342. //
  1343. // Now add the byte.
  1344. //
  1345. Lexer->TokenBufferCapacity = NewCapacity;
  1346. Lexer->TokenBuffer[Lexer->TokenBufferSize] = Character;
  1347. Lexer->TokenBufferSize += 1;
  1348. return TRUE;
  1349. }