0 input: 0 tSyntaxError = -1 0 tAmpersand "&' 0 tAnd "&&' 0 tAngleLeft "<' 0 tAngleRight ">' 0 tAppendLeft "<<' 0 tAppendRight ">>' 0 tAt "@' 0 tBackQuote 0 tBackQuoteLeft 0 tBackSlash 0 tBraceLeft "{' 0 tBraceRight "}' 0 tCaret "^' 0 tComma ",' 0 tColon ":' 0 tDash "-' 0 tDigit 0 tDollar "$' 0 tDoubleQuote 0 tEndOfFile 0 tEqual "=' 0 tExclamation "!' 0 tLabelEnd ";;' 0 tLetter 0 tNewLine 0 tOr "||' 0 tParenLeft "(' 0 tParenRight ")' 0 tPercent "%' 0 tPeriod ".' 0 tPlus "+' 0 tPipe "|' 0 tSemicolon ";' 0 tSharp "#' 0 tSingleQuote 0 tSlash "/' 0 tSquareLeft "[' 0 tSquareRight "]' 0 tStar "*' 0 tTilde "~' 0 tQuestionMark "?' 0 tUnderscore "_' 0 tWhiteSpace 0 ; 0 0 % TOV == top of variable stack 0 0 output: 0 sBufferSet % set the buffer contents to following string 0 sBufferAppend % append following string to buffer contents 0 sBufferExpand % dollar-expand the contents of the buffer 0 sBufferQuote % quote the next string and future expansions 0 sBufferSetFromArgV % set the buffer contents from "$@", for loop 0 sArgVpush % push buffer onto ArgV stack, then null buffer 0 sArgList % turn ArgV stack into real argument list 0 sVariablePush % push buffer contents onto variable stack 0 sVariablePop % pop variable stack 0 sVariableCdr % set TOV to (cdr TOV) 0 sVariableBuffer % set the buffer contents to TOV 0 sVariableAppend % expand operand and append to TOV 0 sVariableLoopAttach % loop variable in inner scope points at car TOV 0 sCommandPush % push command info structure onto command stack 0 sCommandPop % pop ditto (execute command, return from func) 0 sCommandCarryBuffer % don't null buffer/bufferp at next runcommand() 0 sIOopen % open file named in buffer 0 sIOopenString % open string operand for reading 0 sIOopenPortal % open named pipe named in buffer 0 sIOopenPipe % open pipe between processes on input/output 0 sIOintoBuffer % write stdout into buffer (for `...`) 0 sIOclose % close fd operand 0 sIOdup % dup fd operands (dup2(op2,op1)) 0 sIOsetIn % open operations are for input 0 sIOsetInOut % open operations are for input/output 0 sIOsetOut % open operations are for output 0 sIOsetAppend % open operations are for output appending 0 sIOsetDesc % open operations are for given file descriptor 0 sIObufIn % read from string buffer 0 sIObufOut % write to string buffer 0 sIObufFree % free string buffer 0 sIObufString % copy string buffer to command buffer 0 sAssign % assign argv[top] to sh var. argv[top-1], pop 0 sAssignTemporary % like sAssign but only for next command 0 sFunction % define function operand starting here 0 sParameter % LocalVariable op SetBuffer op Push Swap Assign 0 sJump % unconditional jump to operand 0 sBranchOrigin % placeholder for backpatching 0 sJumpFork % fork 0 sJumpIfFailure % if last exit status is != 0 jump 0 sJumpIfSuccess % if last exit status is == 0 jump 0 sJumpIfNilVariable % if variable on TOV is nil, jump 0 sJumpIfMatch % if !(map #'(lambda (a) (match TOV-1 a)) TOV) 0 sJumpIfFindVarNil % if findvar(buffer) == NULL, jump 0 sJumpIfOrValueNil % if findvar(buffer) and value is ""/0, jump 0 sJumpLoopBreak % where to go on a break for this loop 0 sJumpLoopContinue % where to go on a continue for this loop 0 sLoopEnter % push the JumpLoops on 0 sLoopExit % pop the JumpLoops off 0 sLocalVariable % make operand refer to local variable in scope 0 sScopePush % push scope 0 sScopePop % pop scope 0 sDollarExpand % expand most recently emitted buffer 0 sNoOp % null operation, used by optimizer 0 sPrintAndExit % print contents of buffer, then exit 0 sBackground % command must be backgrounded 0 %ifdef MAILER 0 % String RegExprs 0 sSiftPush % do whatever is needed before sift expression 0 sSiftBody % ditto after sift expression before body 0 sSiftCompileRegexp % compile the regular expression in buffer 0 sSiftReevaluate % if expression variables changed, reevaluate it 0 sSiftPop % all done, pheew 0 sSiftBufferAppend % the buffer is [0-9] 0 sJumpIfRegmatch % if current regexp matches token buffer, jump 0 0 % Token RegExprs 0 sTSiftPush % do whatever is needed before sift expression 0 sTSiftBody % ditto after sift expression before body 0 sTSiftCompileRegexp % compile the regular expression in buffer 0 sTSiftReevaluate % if expression variables changed, reevaluate it 0 sTSiftPop % all done, pheew 0 % sTSiftBufferAppend % --- REUSE sSiftBufferAppend !! 0 sTJumpIfRegmatch % if current regexp matches token buffer, jump 0 %endif /* MAILER */ 0 ; 0 0 error: 0 eFirstUserError = 10 0 eIllegalArgumentSeparator = 10 0 eMissingDo 0 eMissingDoOrIn 0 eMissingDone 0 eMissingEndOfPattern 0 eMissingEsac 0 eMissingFi 0 eMissingIOopTarget 0 eMissingKeywordIn 0 eMissingThen 0 eMissingRightBrace 0 eUnknownDollarOperand 0 eUnmatchedEndOfGroup 0 eIllegalLeftParen 0 eIllegalConnector 0 eIllegalTokenUnbalancedList 0 eObsoleteSift 0 eObsoleteTfis 0 eTfissMisparity 0 eTfistMisparity 0 eSslStackOverflow = 40 0 ; 0 0 type StringTerminator: 0 sDoubleQuote 0 sSingleQuote 0 sBackQuote 0 ; 0 0 type WordKind: 0 sName 0 sWord 0 ; 0 0 type Keyword: 0 kCase 0 kDo 0 kDone 0 kElif 0 kElse 0 kEsac 0 kFi 0 kFor 0 kIf 0 kIn 0 kLocalVariable 0 kNull 0 %ifdef MAILER 0 kTSift 0 kTfisT 0 kSSift 0 kTfisS 0 kSift 0 kTfis 0 %endif /* MAILER */ 0 kThen 0 kUntil 0 kWhile 0 ; 0 0 type Flag: 0 off 0 on 0 ; 0 0 type FlagBit: 0 bitHereData 0 bitQuotingHereData 0 bitStripTabs 0 bitTwoJumps 0 bitInQuotes 0 bitEmittedBuffer 0 ; 0 0 type Counter: 0 countDoubleQuoteNestingLevel = 0 0 countBackQuoteNestingLevel = 1 0 countDollarInSiftLabel = 2 0 % countDollarInTSiftLabel = 3 0 ; 0 0 type HereCompare: 0 same 0 different 0 ; 0 0 type BufferState: 0 empty 0 used 0 ; 0 0 type IOop: 0 noIO 0 yesIO 0 ; 0 0 mechanism Identify: 0 oIdentWord >> WordKind 0 oIdentifyKeyword >> Keyword 0 ; 0 0 mechanism Backup: 0 oUngetKeyword 0 ; 0 0 mechanism Buffer: 0 oBufferClear 0 oBufferAppend 0 oBufferAppendCaret % appends ^ to buffer 0 oBufferAppendDollar % appends $ to buffer 0 oBufferTerminate 0 oBufferEmit % emit string from buffer 0 oBufferEmitPattern % this emits ^buffer$ 0 oBufferUsed >> BufferState % empty or used ? 0 ; 0 0 mechanism BranchStack: 0 oBranchPushNullOrigin % push 0 onto stack 0 oBranchPushOrigin % push current output position onto stack 0 oBranchPatch % stack[top] = current position (patch target) 0 oBranchPatchBack % stack[top] = stack[top-1] (patch target) 0 oBranchPopOrigin % pop stack 0 oBranchSwapTop % swap top two stack entries 0 ; 0 0 mechanism Emit: 0 oEmitBranchOrigin % emit value on top of BranchStack 0 ; 0 0 mechanism HereDocuments: 0 oHereSaveStop % save stuff in buffer into HereSave buffer 0 oHereCompareStop >> HereCompare % have we reached the stop line? 0 oHereCutBuffer % remove last partial line in buffer 0 ; 0 0 mechanism Flags: 0 oFlagsPush % push flag scope 0 oFlagsPop % pop flag scope 0 oFlagsSet(FlagBit) % set the specified flag 0 oFlagsTest(FlagBit) >> Flag % test the specified flag 0 ; 0 0 mechanism Counters: 0 oCounterIncrement(Counter) % increment the specified counter 0 oCounterDecrement(Counter) % decrement the specified counter 0 oCounterClear(Counter) % reset the specified counter to 0 0 oCounterTest(Counter) >> Flag % is the specified counter positive? 0 %oCounterSave(Counter) % remember this counter value 0 %oCounterCopy(Counter) % copy the remembered value to counter 0 ; 0 0 rules 0 0 Script: 0 oCounterClear(countDoubleQuoteNestingLevel) 3 oCounterClear(countBackQuoteNestingLevel) 6 @WhiteSpace 6 {[* 8 | tEndOfFile: 11 > 11 | tNewLine,tWhiteSpace,";;': 15 ? 15 | "#': 18 ? 18 {[ 19 | tNewLine: 21 > 21 | *: 25 ? 28 ]} 29 | "}',")': 33 #eUnmatchedEndOfGroup 33 ? 35 | *: 38 @CommandList 53 ]} 55 ; 57 57 Command: 58 [* 58 | tEndOfFile: 61 >> 61 | *: 64 ] 67 [* 67 | "{': 70 ? 70 .sScopePush 71 .sCommandPush 73 oFlagsPush 75 @SimpleCommandIOprep 76 @CommandList 78 "}' 80 @SimpleCommandIO 82 .sCommandPop 84 .sScopePop 86 [ oFlagsTest(bitHereData) 91 | off: 93 oFlagsPop 93 | *: 96 ] 99 | "(': 101 ? 101 .sJumpFork 102 oBranchPushOrigin 104 .sBranchOrigin 105 .sCommandPush 107 oFlagsPush 109 @SimpleCommandIOprep 110 @CommandList 112 ")' 114 @SimpleCommandIO 116 .sCommandPop 118 oBranchPatch 120 oBranchPopOrigin 121 [ oFlagsTest(bitHereData) 125 | off: 127 oFlagsPop 127 | *: 130 ] 133 %| '=',':','+','-','?','[',']','^','~','/': 133 % @SimpleCommand 133 | *: 135 @NamePrelim 140 [ oIdentifyKeyword 142 %ifdef MAILER 142 | kSSift: 145 @WhiteSpace 145 @SimpleCommandIOprep 147 @SSiftStatement 149 @SimpleCommandIO 151 | kTSift: 155 @WhiteSpace 155 @SimpleCommandIOprep 157 @TSiftStatement 159 @SimpleCommandIO 161 | kSift: 165 #eObsoleteSift 165 %endif /* MAILER */ 165 | kCase: 169 @WhiteSpace 169 @SimpleCommandIOprep 171 @CaseStatement 173 @SimpleCommandIO 175 | kIf: 179 @WhiteSpace 179 @SimpleCommandIOprep 181 @IfStatement 183 @SimpleCommandIO 185 | kFor: 189 @WhiteSpace 189 @SimpleCommandIOprep 191 @ForStatement 193 @SimpleCommandIO 195 | kWhile: 199 @WhiteSpace 199 @SimpleCommandIOprep 201 @WhileStatement 203 @SimpleCommandIO 205 | kUntil: 209 @WhiteSpace 209 @SimpleCommandIOprep 211 @UntilStatement 213 @SimpleCommandIO 215 | kLocalVariable: 219 @WhiteSpace 219 @LocalDeclaration 221 | *: 225 oUngetKeyword 244 @SimpleCommand 245 ] 247 ] 247 @WhiteSpace 247 ; 249 249 LocalDeclaration: 250 {[* 250 | tLetter: 253 @NamePrelim 253 .sLocalVariable 255 oBufferEmit 257 @WhiteSpace 258 | *: 262 > 265 ]} 267 ; 269 269 %ifdef MAILER 269 SingleQuotePattern: 270 {[* 270 | tNewLine: 273 > % Always breaks 273 | tSingleQuote: 277 ? % Eat it away! 277 > 278 | *: 282 ? % Accept it 287 oBufferAppend 288 ]} 289 ; 291 DoubleQuotePattern: 292 {[* 292 | tNewLine: 295 > % Always breaks 295 | tDoubleQuote: 299 ? % Eat it away! 299 > 300 | *: 304 ? % Accept it 309 oBufferAppend 310 ]} 311 ; 313 313 SSiftStatement: 314 .sSiftPush 314 @Word 316 .sSiftBody 318 @IgnoreComments 320 @NamePrelim 322 [ oIdentifyKeyword 324 | kIn: 327 | *: 329 #eMissingKeywordIn 332 ] 334 @IgnoreComments 334 .sLoopEnter 336 .sJumpLoopBreak 338 oBranchPushOrigin 340 .sBranchOrigin 341 { 343 % get the pattern 343 oCounterClear(countDollarInSiftLabel) 346 oBufferClear 346 {[* 347 | tSingleQuote: 350 ? 350 @SingleQuotePattern 351 | tDoubleQuote: 355 ? 355 @DoubleQuotePattern 356 | tWhiteSpace,tNewLine: 360 > 360 | tDollar: 364 oCounterIncrement(countDollarInSiftLabel) 367 ? 367 oBufferAppend 368 | *: 371 ? 382 oBufferAppend 383 ]} 384 oBufferTerminate 386 [ oIdentifyKeyword 387 | kDone, kElif, kElse, kEsac, kFi, kIn: 390 % to get error position right 390 oUngetKeyword 390 #eSyntaxError 391 | kTfisT: 395 #eTfistMisparity 395 | kTfisS: 399 > 399 | *: 403 .sJumpLoopContinue 420 oBranchPushOrigin 422 .sBranchOrigin 423 oBranchPatch 425 oBranchPopOrigin 426 .sSiftReevaluate 427 [ oCounterTest(countDollarInSiftLabel) 432 | on: 434 oUngetKeyword 434 oBufferClear 435 oBufferTerminate 436 .sBufferSet 437 oBufferEmit 439 oBufferClear 440 oBufferAppendCaret 441 {[* 442 | tWhiteSpace,tNewLine: 445 > 445 | tDollar: 449 @FlushBuffer 449 ? @Dollar 452 | *: 456 ? 463 oBufferAppend 464 ]} 465 oBufferAppendDollar 467 oBufferTerminate 468 @FlushBuffer 469 | off: 473 .sBufferSet 473 % emit the pattern 473 oBufferEmitPattern 475 ] 484 .sSiftCompileRegexp 484 oBranchPushNullOrigin 486 oEmitBranchOrigin 487 oBranchPopOrigin 488 .sJumpIfRegmatch 489 oBranchPushOrigin 491 .sBranchOrigin 492 @CommandList 494 ";;' 496 oBranchPatch 498 oBranchPopOrigin 499 @IgnoreComments 500 ] 502 } 502 oBranchPatch 504 oBranchPopOrigin 505 .sLoopExit 506 .sSiftPop 508 ; 510 510 TSiftStatement: 511 .sTSiftPush 511 @Word 513 .sTSiftBody 515 @IgnoreComments 517 @NamePrelim 519 [ oIdentifyKeyword 521 | kIn: 524 | *: 526 #eMissingKeywordIn 529 ] 531 @IgnoreComments 531 .sLoopEnter 533 .sJumpLoopBreak 535 oBranchPushOrigin 537 .sBranchOrigin 538 { 540 % get the pattern 540 oCounterClear(countDollarInSiftLabel) 543 oBufferClear 543 {[* 544 | tSingleQuote: 547 ? 547 @SingleQuotePattern 548 | tDoubleQuote: 552 ? 552 @DoubleQuotePattern 553 | tWhiteSpace,tNewLine: 557 > 557 | tDollar: 561 oCounterIncrement(countDollarInSiftLabel) 564 ? 564 oBufferAppend 565 | *: 568 ? 579 oBufferAppend 580 ]} 581 oBufferTerminate 583 [ oIdentifyKeyword 584 | kDone, kElif, kElse, kEsac, kFi, kIn: 587 % to get error position right 587 oUngetKeyword 587 #eSyntaxError 588 | kTfis: 592 % to get error position right 592 oUngetKeyword 592 #eObsoleteTfis 593 | kTfisS: 597 #eTfissMisparity 597 | kTfisT: 601 > 601 | *: 605 .sJumpLoopContinue 624 oBranchPushOrigin 626 .sBranchOrigin 627 oBranchPatch 629 oBranchPopOrigin 630 .sTSiftReevaluate 631 [ oCounterTest(countDollarInSiftLabel) 636 | on: 638 oUngetKeyword 638 oBufferClear 639 oBufferTerminate 640 .sBufferSet 641 oBufferEmit 643 oBufferClear 644 oBufferAppendCaret 645 {[* 646 | tWhiteSpace,tNewLine: 649 > 649 | tDollar: 653 @FlushBuffer 653 ? @Dollar 656 | *: 660 ? 667 oBufferAppend 668 ]} 669 oBufferAppendDollar 671 oBufferTerminate 672 @FlushBuffer 673 | off: 677 .sBufferSet 677 % emit the pattern 677 oBufferEmitPattern 679 ] 688 .sTSiftCompileRegexp 688 oBranchPushNullOrigin 690 oEmitBranchOrigin 691 oBranchPopOrigin 692 .sTJumpIfRegmatch 693 oBranchPushOrigin 695 .sBranchOrigin 696 @CommandList 698 ";;' 700 oBranchPatch 702 oBranchPopOrigin 703 @IgnoreComments 704 ] 706 } 706 oBranchPatch 708 oBranchPopOrigin 709 .sLoopExit 710 .sTSiftPop 712 ; 714 %endif /* MAILER */ 714 714 CaseStatement: 715 @Word 715 .sVariablePush 717 @IgnoreComments 719 @NamePrelim 721 [ oIdentifyKeyword 723 | kIn: 726 | *: 728 #eMissingKeywordIn 731 ] 733 @IgnoreComments 733 @CaseStatementAux 735 .sVariablePop 737 ; 739 739 CaseStatementAux: 740 @Word 740 [ oIdentifyKeyword 742 | kDone, kElif, kElse, kFi, kIn, kTfisS, kTfisT: 745 % to get error position right 745 oUngetKeyword 745 #eSyntaxError 746 | kEsac: 750 | *: 752 @WhiteSpace 769 @CasePart % will leave an oBranchPushOrigin 771 @IgnoreComments 773 @CaseStatementAux % tail recusion on purpose! 775 oBranchPatch % patch jump from taken label body (3) 777 oBranchPopOrigin 778 ] 779 ; 779 779 CasePart: 780 oBranchPushOrigin % jumped to by (4) 780 .sJumpIfMatch % to the case body (1) 781 oBranchPushOrigin 783 .sBranchOrigin 784 oBranchSwapTop 786 {[ 787 | "|': 789 @WhiteSpace 789 @Word 791 @WhiteSpace 793 .sJumpIfMatch % to case body (4) 795 oEmitBranchOrigin % jump back up 797 | ")': 800 oBranchPopOrigin 800 > 801 % ------ Should recognize there, but.. Doing so would need call 801 % ------ for oIdentifyKeyword 801 % | kCase, kDo, kDone, kElif, kElse, kEsac, kFi, kFor, kIf, 801 % kIn, kLocalVariable, kTSift, kTfisT, kSSift, kTfisS, 801 % kSift, kTfis, kThen, kUntil, kWhile: 801 % #eSyntaxError 801 | *: 805 #eMissingEndOfPattern 810 ? 812 ]} 813 .sJump % around case-part body (2) 815 oBranchPushOrigin 817 .sBranchOrigin 818 oBranchSwapTop 820 oBranchPatch 821 oBranchPopOrigin % to here (1) 822 @CommandList 823 @IgnoreComments 825 .sJump % to end of case statement (3) 827 oBranchPushOrigin 829 .sBranchOrigin 830 oBranchSwapTop 832 oBranchPatch 833 oBranchPopOrigin % to here (2) 834 [* 835 | ";;': 838 ? 838 | tLetter: % this is the 'e' in esac... 841 @NamePrelim 841 [ oIdentifyKeyword 843 | kEsac: 846 | *: 848 #eMissingEsac 851 ] 853 oUngetKeyword 853 ] 865 ; 865 865 IfStatement: 866 @CommandList 866 @NamePrelim 868 [ oIdentifyKeyword 870 | kThen: 873 | *: 875 #eMissingThen 878 ] 880 .sJumpIfFailure 880 oBranchPushOrigin 882 .sBranchOrigin 883 @CommandList 885 @ElsePart 887 @NamePrelim 889 [ oIdentifyKeyword 891 | kFi: 894 | *: 896 #eMissingFi 899 ] 901 ; 901 901 ElsePart: 902 @IgnoreComments 902 @NamePrelim 904 [ oIdentifyKeyword 906 | kElif: 909 .sJump 909 oBranchPushOrigin 911 .sBranchOrigin 912 oBranchSwapTop 914 oBranchPatch 915 oBranchPopOrigin 916 @CommandList 917 @NamePrelim 919 [ oIdentifyKeyword 921 | kThen: 924 ] 930 .sJumpIfFailure 930 oBranchPushOrigin 932 .sBranchOrigin 933 @CommandList 935 @ElsePart 937 oBranchPatch 939 oBranchPopOrigin 940 | kElse: 943 .sJump 943 oBranchPushOrigin 945 .sBranchOrigin 946 oBranchSwapTop 948 oBranchPatch 949 oBranchPopOrigin 950 @CommandList 951 oBranchPatch 953 oBranchPopOrigin 954 | *: 957 oBranchPatch 962 oBranchPopOrigin 963 oUngetKeyword 964 ] 965 ; 965 965 ForStatement: 966 @Name 966 .sScopePush 968 .sLocalVariable 970 oBufferEmit 972 @IgnoreComments 973 @NamePrelim 975 [ oIdentifyKeyword 977 | kDo: % argument list is $@ 980 .sBufferSetFromArgV 980 .sVariablePush 982 .sVariableLoopAttach 984 .sLoopEnter 986 | kIn: 990 @WhiteSpace 990 @Word 992 .sVariablePush 994 .sVariableLoopAttach 996 .sLoopEnter 998 @WhiteSpace 1000 {[* 1002 | ";': 1005 ? 1005 > 1006 | tNewLine, "#': 1010 > 1010 | *: 1014 @Word 1021 .sVariableAppend 1023 @WhiteSpace 1025 ]} 1027 @IgnoreComments 1029 @NamePrelim 1031 [ oIdentifyKeyword 1033 | kDo: 1036 | *: 1038 % to get error position right 1038 oUngetKeyword 1041 #eMissingDoOrIn 1042 ] 1044 @IgnoreComments 1044 | *: 1048 oUngetKeyword % to get error position right 1053 #eMissingDoOrIn 1054 ] 1056 oBranchPushOrigin % loop top 1056 .sJumpIfNilVariable % loop exit 1057 oBranchPushOrigin 1059 oBranchSwapTop 1060 .sBranchOrigin 1061 .sJumpLoopBreak 1063 oBranchPushOrigin 1065 .sBranchOrigin 1066 oBranchSwapTop 1068 .sJumpLoopContinue 1069 oBranchPushOrigin 1071 .sBranchOrigin 1072 @CommandList 1074 oBranchPatch % loop continue 1076 oBranchPopOrigin 1077 .sVariableCdr 1078 .sJump % back to top of loop 1080 oEmitBranchOrigin 1082 oBranchPopOrigin 1083 oBranchPatch % backpatch exit from loop 1084 oBranchPopOrigin 1085 oBranchPatch % loop break 1086 oBranchPopOrigin 1087 .sLoopExit 1088 .sVariablePop 1090 @NamePrelim 1092 [ oIdentifyKeyword 1094 | kDone: 1097 | *: 1099 #eMissingDone 1102 ] 1104 .sScopePop 1104 ; 1106 1106 WhileStatement: 1107 @WhileUntilPrelude 1107 @CommandList 1109 .sJumpIfFailure % loop exit 1111 @WhileUntilCommon 1113 ; 1115 1115 UntilStatement: 1116 @WhileUntilPrelude 1116 @CommandList 1118 .sJumpIfSuccess % loop exit 1120 @WhileUntilCommon 1122 ; 1124 1124 WhileUntilPrelude: 1125 .sLoopEnter 1125 .sJumpLoopBreak 1127 oBranchPushOrigin 1129 .sBranchOrigin 1130 .sJumpLoopContinue 1132 oBranchPushOrigin % loop top 1134 .sBranchOrigin 1135 oBranchPushOrigin % loop top 1137 oBranchSwapTop 1138 oBranchPatch 1139 oBranchPopOrigin 1140 ; 1141 1141 WhileUntilCommon: 1142 oBranchPushOrigin 1142 .sBranchOrigin 1143 oBranchSwapTop 1145 @NamePrelim 1146 [ oIdentifyKeyword 1148 | kDo: 1151 | *: 1153 #eMissingDo 1156 ] 1158 @CommandList 1158 @NamePrelim 1160 [ oIdentifyKeyword 1162 | kDone: 1165 | *: 1167 #eMissingDone 1170 ] 1172 .sJump % back to top of loop 1172 oEmitBranchOrigin 1174 oBranchPopOrigin 1175 oBranchPatch % backpatch loop exit 1176 oBranchPopOrigin 1177 oBranchPatch % loop break 1178 oBranchPopOrigin 1179 .sLoopExit 1180 ; 1182 1182 CommandList: 1183 @IgnoreComments 1183 [* 1185 | tEndOfFile: 1188 >> 1188 | *: 1191 ] 1194 @AndOr 1194 { 1196 [ 1196 | tNewLine: 1198 [ oFlagsTest(bitHereData) 1201 | on: 1203 @HereData 1203 | *: 1207 ] 1210 % do the stuff below 1210 | ";': 1212 % do the stuff below 1212 | *: 1214 > 1219 ] 1221 @IgnoreComments 1221 [* 1223 | tEndOfFile, ";;', "}', ")', tBackQuote,tBackQuoteLeft: 1226 > 1226 | tLetter: 1230 @NamePrelim 1230 [ oIdentifyKeyword 1232 | kThen,kFi,kElse,kElif,kDo,kDone,kEsac: 1235 oUngetKeyword 1235 > 1236 | *: 1240 oUngetKeyword 1255 @SkipComment 1256 @AndOr 1258 ] 1260 | *: 1262 @SkipComment 1277 @AndOr 1279 ] 1281 } 1281 ; 1283 1283 AndOr: 1284 @PipeLine 1284 [ 1286 | "&&': 1288 .sJumpIfFailure % of previous command 1288 oBranchPushOrigin 1290 .sBranchOrigin 1291 @IgnoreComments 1293 @AndOr % tail recursion on purpose! 1295 oBranchPatch 1297 oBranchPopOrigin 1298 | "||': 1301 .sJumpIfSuccess 1301 oBranchPushOrigin 1303 .sBranchOrigin 1304 @IgnoreComments 1306 @AndOr 1308 oBranchPatch 1310 oBranchPopOrigin 1311 | *: 1314 ] 1319 ; 1319 1319 PipeLine: 1320 .sCommandPush 1320 oFlagsPush 1322 .sJump % jump to background indication (a) 1323 oBranchPushOrigin 1325 .sBranchOrigin 1326 oBranchPushOrigin % jump back here after backgrounding known (b) 1328 oBranchSwapTop 1329 .sJump % jump to pipe setup (1) 1330 oBranchPushOrigin 1332 .sBranchOrigin 1333 oBranchPushOrigin % jump back to here after pipe setup (2) 1335 oBranchSwapTop 1336 @Command 1337 {[ 1339 | "|': 1341 @IgnoreComments 1341 .sJump % jump over the pipe setup (3) 1343 oBranchPushOrigin 1345 .sBranchOrigin 1346 oBranchSwapTop 1348 oBranchPatch % jump to here from (1) 1349 oBranchPopOrigin 1350 oBranchSwapTop 1351 .sIOsetOut 1352 .sIOopenPipe 1354 .sJump 1356 oEmitBranchOrigin % jump from here to (2) 1358 oBranchPopOrigin 1359 oBranchPatch % jump to here from (3) 1360 oBranchPopOrigin 1361 .sCommandPop 1362 [ oFlagsTest(bitHereData) 1367 | off: 1369 oFlagsPop 1369 | *: 1372 ] 1375 .sCommandPush 1375 .sIOsetIn 1377 .sIOopenPipe 1379 oFlagsPush 1381 .sJump % jump to pipe setup (1) 1382 oBranchPushOrigin 1384 .sBranchOrigin 1385 oBranchPushOrigin % jump back here afterwards (2) 1387 oBranchSwapTop 1388 @Command 1389 | *: 1393 > 1396 ]} 1398 oBranchPatchBack % patch previous jump (1) to continue at (2) 1400 oBranchPopOrigin 1401 oBranchPopOrigin 1402 [ 1403 | "&': 1405 .sCommandPop 1405 .sJump % jump over the setup (c) 1407 oBranchPushOrigin 1409 .sBranchOrigin 1410 oBranchSwapTop 1412 oBranchPatch % jump to here from (a) 1413 oBranchPopOrigin 1414 oBranchSwapTop 1415 .sBackground 1416 .sCommandPush 1418 .sJump % jump back to (b) 1420 oEmitBranchOrigin 1422 oBranchPopOrigin 1423 oBranchPatch % jump to here from (c) 1424 oBranchPopOrigin 1425 @WhiteSpace 1426 [ 1428 | "&&',"||': 1430 #eIllegalConnector 1430 | *: 1434 ] 1439 | *: 1441 oBranchPatchBack % patch (a) to go to (b) 1444 oBranchPopOrigin 1445 oBranchPopOrigin 1446 ] 1447 .sCommandPop 1447 [ oFlagsTest(bitHereData) 1452 | off: 1454 oFlagsPop 1454 | *: 1457 ] 1460 ; 1460 1460 SimpleCommand: 1461 @SkipComment 1461 [* 1463 | tLetter,tBackQuoteLeft: % efficiency hack 1466 | tNewLine,";',";;',"&',"|',"&&',"||',tParenRight,tBraceRight: 1468 >> 1468 | tBackQuote: 1471 [ oCounterTest(countBackQuoteNestingLevel) 1474 | on: 1476 % if we are waiting for end of backquote 1476 % then we abort back to @BackQuote 1476 >> 1476 | *: 1479 % otherwise the first word in our 1479 % command is a backquote... 1479 ] 1482 | *: 1484 ] 1509 [ @IOoperation 1511 | noIO: 1513 @SimpleItem 1513 | *: 1517 ] 1520 { 1520 { 1520 @WhiteSpace 1520 @SkipComment 1522 [* 1524 | tBackSlash: 1527 oBufferClear 1527 oBufferTerminate 1528 ? 1529 oBufferAppend 1530 [* 1531 | tNewLine: 1534 ? 1534 oBufferClear 1535 % repeat the loop 1535 | *: 1538 oBufferTerminate 1541 oUngetKeyword 1542 > 1543 ] 1545 | *: 1547 > 1550 ] 1552 } 1552 [* 1554 | tLetter,tBackQuoteLeft: % efficiency hack 1557 | tNewLine,";',";;',"&',"|',"&&',"||',tParenRight,tBraceRight: 1559 > 1559 | tBackQuote: 1563 [ oCounterTest(countBackQuoteNestingLevel) 1566 | on: 1568 % this is the end of the command 1568 > 1568 | *: 1572 % the next word is a backquote 1572 ] 1575 %| tParenLeft: 1575 % #eIllegalLeftParen 1575 % > 1575 | *: 1577 ] 1602 [ @IOoperation 1604 | noIO: 1606 % whatever we see here, it isn't a separator 1606 @Word 1606 .sArgVpush 1608 | *: 1612 ] 1615 } 1615 ; 1617 1617 SimpleCommandIOprep: 1618 .sJump % jump to I/O setup 1618 oBranchPushOrigin 1620 .sBranchOrigin 1621 oBranchPushOrigin 1623 oBranchSwapTop 1624 % followed by @some-command 1624 % then @SimpleCommandIO 1624 ; 1625 1625 SimpleCommandIO: 1626 .sJump % after command code, jump to after I/O setup 1626 oBranchPushOrigin 1628 .sBranchOrigin 1629 oBranchSwapTop 1631 oBranchPatch % I/O setup 1632 oBranchPopOrigin 1633 oBranchSwapTop 1634 { 1635 @WhiteSpace 1635 [ @IOoperation 1639 | noIO: 1641 > 1641 | *: 1645 ] 1648 } 1648 .sJump % jump back to the command code 1650 oEmitBranchOrigin 1652 oBranchPopOrigin 1653 oBranchPatch % resume here after command code 1654 oBranchPopOrigin 1655 ; 1656 1656 SimpleItem: 1657 [* 1657 | "=',":',"+',"-',"?': 1660 @Word 1660 .sArgVpush 1662 >> 1664 | *: 1667 ] 1678 @FirstWord 1678 [ oIdentWord 1680 | sName: 1683 @WhiteSpace 1683 [ 1685 | "=': % no whitespace allowed here 1687 [* 1687 | tWhiteSpace,tNewLine: 1690 % assign null 1690 .sArgVpush 1690 oBufferClear 1692 oBufferTerminate 1693 .sBufferSet 1694 oBufferEmit 1696 | *: 1699 .sArgVpush 1704 @Word 1706 ] 1708 %.sArgVpush 1708 @WhiteSpace 1708 @SkipComment 1710 [* 1712 | tNewLine,";',";;',"&',"|',"&&',"||',tParenRight,tBraceRight: 1715 % permanent assign 1715 .sAssign 1715 | *: % heavy recursion! 1719 .sAssignTemporary 1738 @Command 1740 ] 1742 | "(': 1744 .sFunction 1744 oBranchPushOrigin 1746 .sBranchOrigin 1747 % most functions have local variables... 1747 .sScopePush 1749 @Function 1751 .sScopePop 1753 oBranchPatch 1755 oBranchPopOrigin 1756 | *: 1759 .sArgVpush 1764 ] 1766 | sWord: 1768 .sArgVpush 1768 ] 1778 ; 1778 1778 IOoperation >> IOop: 1779 oBufferClear 1779 {[* 1780 | tDigit: 1783 ? 1783 oBufferAppend 1784 | "<',">',"<<',">>': 1787 oBufferTerminate 1787 > 1788 | *: 1792 oBufferTerminate 1803 [ oBufferUsed 1804 | used: 1807 oUngetKeyword 1807 | *: 1810 ] 1813 >> noIO 1813 ]} 1816 [ 1818 | ">': 1820 .sIOsetOut 1820 @File 1822 | "<': 1826 [ 1826 | ">': 1828 .sIOsetInOut 1828 | *: 1832 .sIOsetIn 1835 ] 1837 @File 1837 | ">>': 1841 .sIOsetAppend 1841 @File 1843 | "<<': 1847 [ 1847 | "-': 1849 oFlagsSet(bitStripTabs) 1852 | *: 1854 ] 1857 @WhiteSpace 1857 @HereDocument 1859 | *: 1863 >> noIO 1872 ] 1875 >> yesIO 1875 ; 1878 1878 File: 1879 [ oBufferUsed 1879 | used: 1882 .sIOsetDesc 1882 oBufferEmit 1884 | *: 1887 ] 1890 [ 1890 | "&': 1892 [ 1892 | "-': 1894 .sIOclose 1894 | tDigit: 1898 % interestingly, this code is 1898 % identical for n<&m and n>&m 1898 .sIOdup % dup2(op2, op1) 1898 oBufferClear 1900 oBufferAppend 1901 {[ 1902 | tDigit: 1904 oBufferAppend 1904 | *: 1907 > 1910 ]} 1912 oBufferTerminate 1914 oBufferEmit 1915 | *: 1918 #eMissingIOopTarget 1923 ] 1925 | *: 1927 @Whitespace 1930 [ 1932 | "@': 1934 @Word 1934 .sIOopenPortal 1936 | *: 1940 @Word 1943 .sIOopen 1945 ] 1947 ] 1947 ; 1947 1947 Function: 1948 @ParameterList 1948 @WhiteSpace 1950 %@Command 1950 @PipeLine 1952 ; 1954 1954 ParameterList: 1955 @WhiteSpace 1955 [ 1957 | ")': 1959 .sArgList 1959 >> 1961 | *: 1964 ] 1967 @NamePrelim 1967 .sParameter 1969 oBufferEmit 1971 @IgnoreComments 1972 {[ 1974 | ",': 1976 @IgnoreComments 1976 @NamePrelim 1978 .sParameter 1980 oBufferEmit 1982 @IgnoreComments 1983 | ")': 1987 > 1987 | *: 1991 #eIllegalArgumentSeparator 1996 ? 1998 ]} 1999 .sArgList 2001 ; 2003 2003 NamePrelim: 2004 oBufferClear 2004 [ 2005 | tLetter: 2007 oBufferAppend 2007 {[ 2008 | tLetter, tDigit, "_': 2010 oBufferAppend 2010 | *: 2013 > 2020 ]} 2022 | *: 2026 % must be a word... 2026 ] 2029 oBufferTerminate 2029 ; 2030 2030 Name: 2031 @NamePrelim 2031 .sBufferSet 2033 oBufferEmit 2035 ; 2036 2036 FlushQBuffer: 2037 [ oFlagsTest(bitInQuotes) 2040 | on: 2042 [ oFlagsTest(bitEmittedBuffer) 2045 | on: 2047 @FlushBuffer 2047 >> 2049 | *: 2052 .sBufferQuote 2055 oFlagsSet(bitEmittedBuffer) 2060 ] 2060 | *: 2062 ] 2065 oBufferTerminate 2065 .sBufferAppend 2066 oBufferEmit 2068 oBufferClear 2069 ; 2070 2070 FlushBuffer: 2071 [ oBufferUsed 2071 | used: 2074 oBufferTerminate 2074 [ oFlagsTest(bitInQuotes) 2078 | on: 2080 .sBufferQuote 2080 oFlagsSet(bitEmittedBuffer) 2085 | *: 2087 ] 2090 .sBufferAppend 2090 oBufferEmit 2092 oBufferClear 2093 | *: 2096 ] 2099 ; 2099 2099 Word: % not deep recursive, alas... our buffer should really be stack of do.. 2100 oBufferClear 2100 oBufferTerminate 2101 .sBufferSet 2102 oBufferEmit 2104 {[* 2105 | tLetter: 2108 {[ 2108 | tLetter: 2110 oBufferAppend 2110 | *: 2113 > 2116 ]} 2118 | tWhiteSpace,tNewLine,"|',"&',";',"&&',"||',"<',">': 2122 > 2122 | ";;',")',"}': 2126 > 2126 | "(': 2130 [ oBufferUsed 2130 | empty: 2133 @List 2133 oBufferClear 2135 | *: 2138 ] 2141 > 2141 | tDoubleQuote: 2145 @FlushBuffer 2145 ? @DoubleQuote 2148 | tSingleQuote: 2152 @FlushBuffer 2152 ? @SingleQuote 2155 | tBackQuoteLeft: 2159 @FlushBuffer 2159 ? @BackQuote 2162 % we don't want another sBufferAppend 2162 oBufferClear 2164 | tBackQuote: 2167 [ oCounterTest(countBackQuoteNestingLevel) 2170 | on: 2172 > 2172 | off: 2176 @FlushBuffer 2176 ? @BackQuote 2179 % we don't want another sBufferAppend 2179 oBufferClear 2181 ] 2190 | tBackSlash: % this is the magic regsubst character 2192 ? 2192 %ifdef MAILER 2192 [* 2193 | tDigit: 2196 @FlushBuffer 2196 ? 2198 oBufferAppend 2199 oBufferTerminate 2200 .sSiftBufferAppend 2201 oBufferEmit 2203 oBufferClear 2204 | *: 2207 @BackSlash 2210 ] 2212 %else /* !MAILER */ 2212 % @BackSlash 2212 %endif /* MAILER */ 2212 | tDollar: 2214 @FlushBuffer 2214 ? @Dollar 2217 | *: 2221 ? 2262 oBufferAppend 2263 ]} 2264 % not quite a FlushBuffer, so the buffer can be re-emitted later 2264 [ oBufferUsed 2266 | used: 2269 oBufferTerminate 2269 .sBufferAppend 2270 oBufferEmit 2272 | *: 2275 ] 2278 ; 2278 2278 FirstWord: % like word, except =, :, +, -, and ? are delimiters 2279 oBufferClear 2279 oBufferTerminate 2280 [ oFlagsTest(bitInQuotes) 2284 | on: 2286 .sBufferQuote 2286 oFlagsSet(bitEmittedBuffer) 2291 | *: 2293 ] 2296 .sBufferSet 2296 oBufferEmit 2298 {[* 2299 | tLetter: 2302 {[ 2302 | tLetter: 2304 oBufferAppend 2304 | *: 2307 > 2310 ]} 2312 | tWhiteSpace,tNewLine,"|',"&',";',"&&',"||',"<',">',"(': 2316 > 2316 | ";;',")',"}',"=',":',"+',"-',"?': 2320 > 2320 | tDoubleQuote: 2324 @FlushBuffer 2324 ? @DoubleQuote 2327 | tSingleQuote: 2331 @FlushBuffer 2331 ? @SingleQuote 2334 | tBackQuoteLeft: 2338 @FlushBuffer 2338 ? @BackQuote 2341 % we don't want another sBufferAppend 2341 oBufferClear 2343 | tBackQuote: 2346 [ oCounterTest(countBackQuoteNestingLevel) 2349 | on: 2351 > 2351 | off: 2355 @FlushBuffer 2355 ? @BackQuote 2358 % we don't want another sBufferAppend 2358 oBufferClear 2360 ] 2369 | tBackSlash: 2371 ? 2371 @BackSlash 2372 | tDollar: 2376 @FlushBuffer 2376 ? @Dollar 2379 | *: 2383 ? 2434 oBufferAppend 2435 ]} 2436 % not quite a FlushBuffer, so the buffer can be re-emitted later 2436 [ oBufferUsed 2438 | used: 2441 oBufferTerminate 2441 [ oFlagsTest(bitInQuotes) 2445 | on: 2447 .sBufferQuote 2447 oFlagsSet(bitEmittedBuffer) 2452 | *: 2454 ] 2457 .sBufferAppend 2457 oBufferEmit 2459 | *: 2462 ] 2465 ; 2465 2465 List: 2466 "(' % we know we're getting this 2466 oBufferClear 2468 oBufferTerminate 2469 .sBufferSet 2470 oBufferEmit 2472 .sVariablePush 2473 .sVariableCdr 2475 { 2477 @WhiteSpace 2477 [* 2479 | "(': 2482 @List 2482 .sVariableAppend 2484 | ")': 2488 > 2488 | tNewLine: 2492 ? 2492 | "|',"&',";',"&&',"||',"<',">',";;',"}': 2495 #eIllegalTokenUnbalancedList 2495 ? 2497 | *: 2500 @Word 2525 .sVariableAppend 2527 ] 2529 } 2529 ")' 2531 .sVariableBuffer 2533 .sVariablePop 2535 ; 2537 2537 WhiteSpace: 2538 [* 2538 | tEndOfFile: % required by EOF-detection algorithm 2541 >> 2541 | *: 2544 ] 2547 {[ 2547 | tWhiteSpace: 2549 | *: 2551 > 2554 ]} 2556 ; 2558 2558 SkipComment: 2559 [ 2559 | "#': 2561 {[* 2561 | tNewLine: 2564 > 2564 | *: 2568 ? 2571 ]} 2572 | *: 2576 ] 2579 ; 2579 2579 IgnoreComments: 2580 {[* 2580 | tEndOfFile: 2583 > 2583 | "#': 2587 ? 2587 {[* 2588 | tNewLine: 2591 > 2591 | *: 2595 ? 2598 ]} 2599 | tNewLine: 2603 ? 2603 [ oFlagsTest(bitHereData) 2607 | on: 2609 @HereData 2609 | *: 2613 ] 2616 | tWhiteSpace: 2618 ? 2618 | *: 2621 > 2630 ]} 2632 ; 2634 2634 DoubleQuote: % we have seen a double-quote, accept till its matching symbol 2635 % buffer is cleared when we enter here 2635 oCounterIncrement(countDoubleQuoteNestingLevel) 2638 oFlagsPush 2638 oFlagsSet(bitInQuotes) 2642 {[ 2642 | tLetter,tWhiteSpace: % efficiency hack 2644 oBufferAppend 2644 | tDollar: 2647 @FlushBuffer 2647 @Dollar 2649 | tBackQuote,tBackQuoteLeft: 2653 @FlushBuffer 2653 @BackQuote 2655 oBufferClear 2657 | tBackSlash: % this is the magic regsubst character 2660 %ifdef MAILER 2660 [* 2660 | tDigit: 2663 @FlushBuffer 2663 ? 2665 oBufferAppend 2666 oBufferTerminate 2667 .sSiftBufferAppend 2668 oBufferEmit 2670 oBufferClear 2671 | *: 2674 @BackSlash 2677 ] 2679 %else /* !MAILER */ 2679 % @BackSlash 2679 %endif /* MAILER */ 2679 | tDoubleQuote: 2681 > 2681 | *: 2685 ? 2700 oBufferAppend 2701 ]} 2702 @FlushQBuffer % needed before the FlagsPop below 2704 oCounterDecrement(countDoubleQuoteNestingLevel) 2709 oFlagsPop 2709 ; 2710 2710 SingleQuote: % we have seen a single-quote, accept till its matching symbol 2711 oFlagsPush 2711 oFlagsSet(bitInQuotes) 2715 {[ 2715 | tSingleQuote: 2717 > 2717 | *: 2721 ? 2724 oBufferAppend 2725 ]} 2726 @FlushQBuffer % needed before the FlagsPop below 2728 oFlagsPop 2730 ; 2731 2731 BackQuotePre: 2732 oCounterIncrement(countBackQuoteNestingLevel) 2735 .sCommandPush 2735 [ oFlagsTest(bitInQuotes) 2740 | on: 2742 .sBufferQuote 2742 | *: 2746 ] 2749 oFlagsPush 2749 .sIOsetOut 2750 .sIOintoBuffer 2752 @CommandList 2754 ; 2756 2756 BackQuotePost: 2757 .sCommandPop 2757 oCounterDecrement(countBackQuoteNestingLevel) 2762 [ oFlagsTest(bitHereData) 2765 | off: 2767 oFlagsPop 2767 | *: 2770 ] 2773 % still no need to do .sBufferAppend since parent will do so 2773 ; 2773 2773 BackQuote: % we have seen a back-quote, accept till its matching symbol 2774 @BackQuotePre 2774 tBackQuote 2776 @BackQuotePost 2778 ; 2780 2780 KshBackQuote: % we have seen a $(, accept till its matching symbol 2781 @BackQuotePre 2781 tParenRight 2783 @BackQuotePost 2785 ; 2787 2787 Dollar: % we have seen a $, deal with it... 2788 % buffer is clear at this point 2788 [ 2788 | tDigit: 2790 oBufferAppend 2790 | tLetter: 2793 oBufferAppend 2793 {[ 2794 | tLetter, tDigit, tUnderScore: 2796 oBufferAppend 2796 | *: 2799 > 2806 ]} 2808 | tParenLeft: 2812 @FlushBuffer 2812 @KshBackQuote 2814 oBufferClear 2816 >> 2817 | tBraceLeft: 2820 @VariableInBrace 2820 >> 2822 | tSharp: 2825 oBufferAppend 2825 [ 2826 | tLetter: 2828 oBufferAppend 2828 {[ 2829 | tLetter, tDigit, tUnderScore: 2831 oBufferAppend 2831 | *: 2834 > 2841 ]} 2843 | *: 2847 ] 2850 | tStar,tAt,tDollar,tDash,tQuestionMark: 2852 oBufferAppend 2852 | *: % just emit the dollar sign 2855 oBufferAppend 2876 @FlushBuffer 2877 >> 2879 %#eUnknownDollarOperand 2879 ] 2880 oBufferTerminate 2880 .sDollarExpand 2881 [ oFlagsTest(bitInQuotes) 2886 | on: 2888 .sBufferQuote 2888 oFlagsSet(bitEmittedBuffer) 2893 | *: 2895 ] 2898 .sBufferAppend 2898 oBufferEmit 2900 oBufferClear 2901 ; 2902 2902 VariableJumpLtwoLabelLone: 2903 .sJump 2903 oBranchPushOrigin 2905 .sBranchOrigin 2906 oBranchSwapTop 2908 [ oFlagsTest(bitTwoJumps) 2912 | on: 2914 oBranchPatch 2914 oBranchPopOrigin 2915 oBranchSwapTop 2916 | off: 2919 ] 2927 oBranchPatch 2927 oBranchPopOrigin 2928 ; 2929 2929 VariableInBrace: 2930 % we need to save the current list of buffers so we don't stomp on it 2930 .sCommandPush % happens to do exactly what we want, here 2930 @FirstWord 2932 [ 2934 | tBraceRight: 2936 .sBufferExpand 2936 | *: 2940 oFlagsPush 2943 % branch to L1 2943 .sJumpIfFindVarNil 2944 oBranchPushOrigin 2946 .sBranchOrigin 2947 [ 2949 | tColon: 2951 oFlagsSet(bitTwoJumps) 2954 % branch to L1 2954 .sJumpIfOrValueNil 2954 oBranchPushOrigin 2956 .sBranchOrigin 2957 | *: 2961 ] 2964 [ 2964 | "-': 2966 .sBufferExpand 2966 @VariableJumpLtwoLabelLone 2968 @Word 2970 | "=': 2974 % want to return null string 2974 oBufferClear 2974 .sBufferExpand 2975 @VariableJumpLtwoLabelLone 2977 .sArgVpush 2979 @Word 2981 %.sArgVpush 2981 .sAssign 2983 % there is code in the interpreter to 2983 % automatically stuff this value into 2983 % the buffer list. No easy other way 2983 % to do it w/o another command or two. 2983 | "?': 2987 .sBufferExpand 2987 @VariableJumpLtwoLabelLone 2989 @Word 2991 .sPrintAndExit 2993 | "+': 2997 @Word 2997 @VariableJumpLtwoLabelLone 2999 oBufferClear 3001 oBufferTerminate 3002 [ oFlagsTest(bitInQuotes) 3006 | on: 3008 .sBufferQuote 3008 oFlagsSet(bitEmittedBuffer) 3013 | *: 3015 ] 3018 .sBufferSet 3018 oBufferEmit 3020 ] 3036 oFlagsPop 3036 % Label 2 3036 oBranchPatch 3037 oBranchPopOrigin 3038 [ 3039 | tBraceRight: 3041 | *: 3043 #eMissingRightBrace 3046 ] 3048 ] 3048 % here we restore the old list of buffers and append ourselves. 3048 .sCommandCarryBuffer % so buffers won't be stomped by runcommand() 3048 .sCommandPop 3050 oBufferClear 3052 ; 3053 3053 BackSlash: 3054 [* 3054 | tBackSlash, tBackQuote, tDollar: 3057 % quote this character (below) 3057 | tDoubleQuote: 3059 % if we are inside doublequote *and* backquote, 3059 % do nothing. otherwise we do as above. 3059 [ oCounterTest(countDoubleQuoteNestingLevel) 3062 | on: 3064 [ oCounterTest(countBackQuoteNestingLevel) 3067 | on: % ignore backslash. 3069 % don't read quote so it 3069 % interpreted normally 3069 >> 3069 | off: 3072 ] 3080 | off: 3082 ] 3090 | tNewLine: 3092 ? % ignore this combo completely 3092 >> 3093 | *: 3096 [ oCounterTest(countDoubleQuoteNestingLevel) 3110 | on: 3112 oBufferAppend % include the backslash 3112 | off: 3115 ] 3123 ] 3123 ? 3123 oBufferAppend 3124 ; 3125 3125 HereDocument: % called after reading a '<<', sets things up for later HereData 3126 [* 3126 | tSingleQuote: 3129 oFlagsSet(bitQuotingHereData) 3132 | tBackSlash: 3134 ? 3134 % sh semantics says if *any* character is quoted. sigh. 3134 oFlagsSet(bitQuotingHereData) 3138 | *: 3140 ] 3145 @Word 3145 oHereSaveStop 3147 oFlagsSet(bitHereData) 3151 .sJump 3151 oBranchPushOrigin 3153 .sBranchOrigin 3154 oBranchPushOrigin 3156 oBranchSwapTop 3157 ; 3158 3158 HereData: % called due to previous HereDocument spec in this command 3159 .sJump % jump to after the heredocument stuff 3159 oBranchPushOrigin 3161 .sBranchOrigin 3162 oBranchSwapTop 3164 % jump to here from the main body of the command 3164 oBranchPatch 3165 oBranchPopOrigin 3166 oBufferClear 3167 oBufferTerminate 3168 .sBufferSet 3169 oBufferEmit 3171 [ oFlagsTest(bitStripTabs) 3175 | on: 3177 @WhiteSpace 3177 | *: 3181 ] 3184 {[* 3184 | tLetter,tWhiteSpace: % efficiency hack 3187 ? 3187 oBufferAppend 3188 | tNewLine: 3191 [ oHereCompareStop 3191 | same: 3194 oHereCutBuffer 3194 > 3195 | different: 3199 ? 3199 oBufferAppend 3200 [ oFlagsTest(bitStripTabs) 3204 | on: 3206 @WhiteSpace 3206 | *: 3210 ] 3213 ] 3221 | tBackSlash: 3223 ? 3223 [ oFlagsTest(bitQuotingHereData) 3227 | on: 3229 oBufferAppend 3229 | off: 3232 @BackSlash 3232 ] 3242 | tBackQuote: 3244 ? 3244 [ oFlagsTest(bitQuotingHereData) 3248 | on: 3250 oBufferAppend 3250 | off: 3253 oBufferTerminate 3253 .sBufferAppend 3254 oBufferEmit 3256 oBufferClear 3257 @BackQuote 3258 oBufferClear 3260 ] 3269 | tDollar: 3271 ? 3271 [ oFlagsTest(bitQuotingHereData) 3275 | on: 3277 oBufferAppend 3277 | off: 3280 oBufferTerminate 3280 .sBufferAppend 3281 oBufferEmit 3283 oBufferClear 3284 @Dollar 3285 ] 3295 | *: 3297 ? 3310 oBufferAppend 3311 ]} 3312 oBufferTerminate 3314 [ oBufferUsed 3315 | used: 3318 .sBufferAppend 3318 oBufferEmit 3320 | *: 3323 ] 3326 .sIOsetIn 3326 .sIOopenString 3328 oFlagsPop 3330 oBranchSwapTop 3331 .sJump 3332 oEmitBranchOrigin % back to continue with the command 3334 oBranchPopOrigin 3335 oBranchPatch % jump to here from before heredocument stuff 3336 oBranchPopOrigin 3337 ; 3338 3338 end 3339