prsexp.asm
上传用户:xiaoan1112
上传日期:2013-04-11
资源大小:19621k
文件大小:25k
源码类别:

操作系统开发

开发平台:

Visual C++

  1. TITLE prsexp.asm - Parser Expression Recognizer
  2. ;==========================================================================
  3. ; Module:  prsexp.asm - Parser Expression Recognizer
  4. ; Subsystem:  Parser
  5. ; System:  Quick BASIC Interpreter
  6. ;
  7. ;  NOTE:
  8. ; See prsnt.asm for general comments
  9. ;
  10. ;===========================================================================
  11. include version.inc
  12. PRSEXP_ASM = ON 
  13. includeOnce opaftqb4
  14. includeOnce prstab
  15. includeOnce opintrsc
  16. includeOnce qbimsgs
  17. includeOnce parser
  18. includeOnce pcode
  19. includeOnce psint
  20. includeOnce variable
  21. assumes DS,DATA
  22. assumes SS,DATA
  23. assumes ES,NOTHING
  24. sBegin DATA
  25. PREC_lPar EQU 1 ;operator precedence for '('
  26. PREC_rPar EQU 1 ;operator precedence for ')'
  27. PREC_mark EQU 0 ;minimum operator precedence
  28. FOP_unary EQU 1 ;flag indicating resword can be a unary operator
  29. ;NOTE: order of this table assumes values of IOP_mark through IOP_LParen
  30. ; as defined in psint.inc
  31. ;
  32. .errnz IOP_mark - 0
  33. .errnz IOP_RParen - 1
  34. .errnz IOP_Imp - 2
  35. .errnz IOP_Eqv - 3
  36. .errnz IOP_Xor - 4
  37. .errnz IOP_Or - 5
  38. .errnz IOP_And - 6
  39. .errnz IOP_Not - 7
  40. .errnz IOP_EQ - 8
  41. .errnz IOP_LT - 9
  42. .errnz IOP_GT - 10
  43. .errnz IOP_LE - 11
  44. .errnz IOP_GE - 12
  45. .errnz IOP_NE - 13
  46. .errnz IOP_Add - 14
  47. .errnz IOP_Minus - 15
  48. .errnz IOP_Mod - 16
  49. .errnz IOP_Idiv - 17
  50. .errnz IOP_Mult - 18
  51. .errnz IOP_Div - 19
  52. .errnz IOP_Plus - 20
  53. .errnz IOP_UMinus - 21
  54. .errnz IOP_Pwr - 22
  55. .errnz IOP_LParen - 23
  56. mpIopOpcode LABEL WORD
  57. DW 0 ;stack marker
  58. DW 0 ;)
  59. DW opImp ;IMP
  60. DW opEqv ;EQV
  61. DW opXor ;XOR
  62. DW opOr ;OR
  63. DW opAnd ;AND
  64. DW opNot ;NOT
  65. DW opEQ ;=
  66. DW opLT ;<
  67. DW opGT ;>
  68. DW opLE ;<=
  69. DW opGE ;>=
  70. DW opNE ;<>
  71. DW opAdd ;binary+
  72. DW opSub ;binary-
  73. DW opMod ;MOD
  74. DW opIDv ; 
  75. DW opMul ;*
  76. DW opDiv ;/
  77. DW 0 ;unary+  (never emitted)
  78. DW opUMi ;unary-
  79. DW opPwr ;^
  80. DW opLParen ;(
  81. mpIopPrecedence LABEL BYTE
  82. DB 2*PREC_mark ;stack marker
  83. DB 2*PREC_rPar ;)
  84. DB 2*2 ;IMP
  85. DB 2*3 ;EQV
  86. DB 2*4 ;XOR
  87. DB 2*5 ;OR
  88. DB 2*6 ;AND
  89. DB 2*7 + FOP_unary ;NOT
  90. DB 2*8 ;=
  91. DB 2*8 ;<
  92. DB 2*8 ;>
  93. DB 2*8 ;<=
  94. DB 2*8 ;>=
  95. DB 2*8 ;<>
  96. DB 2*9 ;binary+
  97. DB 2*9 ;binary-
  98. DB 2*10 ;MOD
  99. DB 2*11 ; 
  100. DB 2*12 ;*
  101. DB 2*12 ;/
  102. DB 2*13 + FOP_unary ;unary+
  103. DB 2*13 + FOP_unary ;unary-
  104. DB 2*14 ;^
  105. DB 2*PREC_lPar + FOP_unary;(
  106. PUBLIC pExpTos, stkExpInit
  107. ;Expression stack constants (see prsexp.asm)
  108. CB_EXP_STK EQU 64 ;number of bytes in expression stack
  109. ; 4 bytes per entry, 16 entries
  110. stkExp DB CB_EXP_STK DUP (?) ;parse-time expression stack
  111. stkExpMin EQU stkExp+4 ;minimum legal offset for pExpTos
  112. stkExpInit LABEL BYTE ;value of pExpTos when initialized
  113. pExpTos DW 0 ;points to cur top of expression stack
  114. sEnd DATA
  115. sBegin CP
  116. assumes CS,CP
  117. ;*********************************************************************/
  118. ; ushort NEAR RelOp()
  119. ;
  120. ; Purpose:
  121. ; Called by NtExp() and NtCaseArg() to parse a relational operator.
  122. ; If a 2-token relational operator is parsed, ScanTok() is called
  123. ; once to consume 1st token.  Caller must always call once ScanTok()
  124. ; to skip past token(s).  It is done this way so NtExp() can be faster
  125. ; & smaller.
  126. ;
  127. ; Entry:
  128. ; pTokScan points to potential relational operator token
  129. ;
  130. ; Exit:
  131. ; returns:
  132. ; 0 if token is not a relational operator
  133. ; 1 for = 
  134. ; 2 for < 
  135. ; 3 for > 
  136. ; 4 for <= 
  137. ; 5 for >= 
  138. ; 6 for <> 
  139. ;  Condition codes set based on value in ax
  140. ;
  141. ;*********************************************************************/
  142. ;Register usage:
  143. ; di = iOperator
  144. ; si = points to current token
  145. ;
  146. cProc RelOp <PUBLIC,NEAR,NODATA>,<di>
  147. cBegin RelOp
  148. sub di,di ;default return value to 0
  149. mov bx,[pTokScan] ;bx points to current token
  150. RelOpLoop:
  151. cmp [bx.TOK_class],CL_resword
  152. jne RelOpExit ;brif token isn't a reserved word
  153. mov ax,[bx.TOK_rw_iOperator];ax = operator's index (IOP_xxx)
  154. inc ax ;test for UNDEFINED
  155. je RelOpExit ;brif token isn't an operator
  156. ;Got an operator, see if its a relational operator
  157. ;IOP_xxx is always way less than 255, we can deal with low byte of ax
  158. sub al,9 ;map =,<,> to 0,1,2
  159. cmp al,2
  160. ja RelOpExit ;brif token isn't a relational operator
  161. inc ax ;map =,<,> to 1,2,3
  162. or di,di
  163. jne Got2ndChar ;brif we're dealing with 2nd char
  164. ; or relational operator
  165. xchg di,ax ;save partial return value in di
  166. ;got a relational operator, see if it is a 2-token
  167. ;relational operator like <>, <=, or >=
  168. call Peek1Tok ;examine beyond current token
  169. ; bx points to that token
  170. jmp SHORT RelOpLoop ;examine 2nd char
  171. ;di = 1..3 for 1st char in {=,<,>}
  172. ;ax = 1..3 for 2nd char in {=,<,>}
  173. Got2ndChar:
  174. cmp ax,di
  175. je RelOpExit ;brif same char as 1st (<<, >> or ==)
  176. inc ax ;map 2nd char {=,<,>} to 2,3,4
  177. add di,ax ;map <=, >=, <> to 4,5,6
  178. call ScanTok ;skip 1st relational operator
  179. RelOpExit:
  180. xchg ax,di ;ax = return value
  181. or ax,ax ;set condition codes for caller
  182. cEnd RelOp
  183. ;*********************************************************************
  184. ; STATICF(boolean) PopTillLParen()
  185. ;
  186. ; Purpose:
  187. ; This is called when we have encountered a right paren while
  188. ; parsing an expression.  It causes all operators which have been
  189. ; stacked to be emitted, up to the matching stacked left paren.
  190. ; If no matching left paren is found on the stack, it means we
  191. ; parsed a sub-expression like x+y), so NtExp() should exit
  192. ; and let its caller parse the right paren.  Maybe it marks the
  193. ; end of a function, sub, or array arg list.
  194. ;
  195. ; Exit:
  196. ; If 1 left paren was popped of the stack, returns psw.EQ,
  197. ;  else if no left parens were found on stack, returns psw.NE
  198. ;
  199. ;*********************************************************************/
  200. cProc PopTillLParen <NEAR,NODATA>,<si,di>
  201. cBegin PopTillLParen
  202. mov si,[pExpTos] ;si points to top of expression stack
  203. PopLoop: ;while (PREC_lPar < *pExpTosReg) {
  204. cmp WORD PTR [si],PREC_lPar
  205. jbe PopDone
  206. inc si ;pop stacked operator's precedence
  207. inc si
  208. lodsw ;pop and emit stacked operator's opcode
  209. call Emit16_AX
  210. jmp SHORT PopLoop
  211. PopDone:
  212. mov [pExpTos],si ;save pointer to top-of-stack
  213. ;if top-of-stack is left paren, return psw.EQ
  214. cmp WORD PTR [si],PREC_lPar
  215. cEnd PopTillLParen
  216. ;*********************************************************************
  217. ; PARSE_RESULT NEAR NtExp()
  218. ;
  219. ; Purpose:
  220. ; Parse an expression and emit code for it.
  221. ; Guarenteed to give Expression To Complex error before
  222. ; more than 16 (CB_EXP_STK/4) entries get pushed onto the expression
  223. ; stack.  This controls unrestricted stack (SS) usage.
  224. ;
  225. ; Entry:
  226. ; pTokScan points to 1st token of expression to be parsed
  227. ; If the static variable [oNamConstPs] is non-zero, intrinsic
  228. ;    functions are not allowed
  229. ;
  230. ; Exit:
  231. ; pTokScan points to 1st token after expression
  232. ; cIdArgs is bumped by 1 (no matter how much recursion takes place).
  233. ; The return value is PR_GoodSyntax, PR_NotFound or PR_BadSyntax.
  234. ; If the result is not PR_BadSyntax, mkVar.flags is preserved across
  235. ; the call
  236. ; Condition codes set based on value in al
  237. ;
  238. ;*******************************************************************
  239. cProc NtExp <PUBLIC,NEAR,NODATA>,<si,di>
  240. localB fConsumed
  241. cBegin NtExp
  242. push [mkVar.MKVAR_flags] ;preserve this for caller
  243. ;Push a low-precedence stopper onto the stack which prevents any
  244. ;operators already on the stack from being emitted as a result of
  245. ;this recursive invocation of NtExp.
  246. sub [pExpTos],2 ;make room for marker on exp stack
  247. mov bx,[pExpTos]
  248. mov WORD PTR [bx],PREC_mark ;push minimum precedence
  249. mov [fConsumed],0 ;we haven't consumed anything yet
  250. ;-------------------------------------------------------------------
  251. ;State which expects a term (function, constant, or variable).
  252. ; If we don't get one, we either return PR_BadSyntax if we've consumed
  253. ; 1 or more tokens, or PR_NotFound if we've consumed no tokens
  254. ;
  255. State1:
  256. mov bx,[pTokScan] ;bx points to current token
  257. mov ax,[bx.TOK_class] ;ax = token's class
  258. cmp al,CL_id
  259. je GotId ;brif token is an id
  260. cmp al,CL_resword
  261. je GotResWord ;brif token is a reserved word
  262. cmp al,CL_lit
  263. jne NotTerm ;brif token is not a constant
  264. call NtLit ;try to parse a constant
  265. ; It is guarenteed that NtLit cannot
  266. ; return PR_NotFound if the token's
  267. ; class is CL_lit
  268. jmp SHORT CheckResult
  269. GotId: call NtIdAryElem ;Try to parse an id (may recurse)
  270. ; It is guarenteed that NtIdAryElem
  271. ; cannot return PR_NotFound
  272. ; if the token's class is CL_id
  273. dec [cIdArgs] ;NtIdAryElem() bumped cIdArgs,
  274. ; NtExp() bumps it on exit, and we are
  275. ; only supposed to bump it once per
  276. ; invocation of NtExp().
  277. CheckResult:
  278. or al,al ;test return code
  279. jg State2 ;brif PR_GoodSyntax
  280. jmp NtExpExit ;return PR_BadSyntax result
  281. ;bx points to current token's descriptor
  282. GotResWord:
  283. mov ax,[bx.TOK_rw_iOperator]
  284. inc ax ;test for UNDEFINED
  285. je NotOperator ;brif didn't get an operator
  286. dec ax ;ax = IOP_xxx for operator
  287. cmp al,IOP_Add
  288. je Scan_State1 ;brif unary plus
  289. ; no need to emit a unary +
  290. cmp al,IOP_Minus
  291. jne NotMinus ;brif not if unary minus
  292. mov al,IOP_UMinus ;convert to unary form of -
  293. ;ax = operator index (IOP_xxx) for current token
  294. NotMinus:
  295. mov di,ax ;di = operator index
  296. test mpIopPrecedence[di],FOP_unary
  297. je NotTerm ;brif not a unary operator
  298. cmp al,IOP_LParen
  299. jne ConsumeOp ;brif token is not '('
  300. ; -- consume & stack/emit operator
  301. sub [pExpTos],2
  302. mov bx,[pExpTos]
  303. mov WORD PTR [bx],PREC_lPar ;push precedence for '('
  304. ; this precedence can only be popped
  305. ; by right paren
  306. cmp bx,dataOFFSET stkExpMin
  307. jb ExpTooComplex ;brif stack overflow
  308. Scan_State1:
  309. call ScanTok ;skip current token
  310. mov [fConsumed],1 ;Now we can't return PR_NotFound
  311. jmp State1 ; because we've consumed something
  312. NotOperator:
  313. call NtIntrinsic ;try to parse intrinsic function
  314. jg SHORT State2 ;brif PR_GoodSyntax (change state)
  315. jl J1_NtExpExit ;brif PR_BadSyntax
  316. NotTerm:
  317. cmp [fConsumed],1
  318. je ExpectedExp ;error if we needed to see a term
  319. ; i.e. we've consumed anything
  320. ;else we never even consumed 1 token, return NotFound
  321. sub al,al ;return(PR_NotFound)
  322. jmp SHORT J1_NtExpExit
  323. ;-------------------------------------------------------------------
  324. ;Error handler's (placed here so they can be reached by SHORT jumps)
  325. ;
  326. ExpTooComplex:
  327. mov ax,MSG_ExpTooComplex ;Error: expression too complex
  328. call PErrMsg_AX ;produce parser error msg
  329. ; al = PR_BadSyntax
  330. jmp SHORT J1_NtExpExit
  331. ;we've encountered something like <term><operator><garbage>
  332. ;
  333. ExpectedExp:
  334. mov ax,MSG_ExpExp ;Error: Expected expression
  335. ExpErrMsg:
  336. call PErrExpMsg_AX ;Error: Expected <ax>
  337. ; al = PR_BadSyntax
  338. J1_NtExpExit:
  339. jmp NtExpExit
  340. ;-------------------------------------------------------------------
  341. ;This code is for the state where we are expecting a binary operator
  342. ; or end-of-expression
  343. ;
  344. State2:
  345. mov bx,[pTokScan] ;bx points to current token
  346. cmp [bx.TOK_class],CL_resword
  347. jne EndOfExp ;brif not reserved word
  348. mov ax,[bx.TOK_rw_iOperator];ax = IOP_xxx for token
  349. inc ax ;test for UNDEFINED
  350. je EndOfExp ;brif its not an operator
  351. dec ax ;ax = operator's IOP_xxx
  352. mov di,ax ;di = operator's IOP_xxx
  353. test mpIopPrecedence[di],FOP_unary
  354. jne EndOfExp ;brif not binary operator (exit)
  355. cmp al,IOP_RParen ;check for right paren
  356. jne NotRightParen ;brif not
  357. ;Now we call PopTillLParen to cause all operators stacked
  358. ; since the last scanned left paren to be emitted.
  359. ; It also detects if the parenthesis for this expression
  360. ; don't balance, i.e.  the expression (a)), in which
  361. ; case we return, because the right paren we're looking
  362. ; at may be for an array reference.  If it is an error,
  363. ; it will be caught by a higher level.
  364. call PopTillLParen
  365. jne EndOfExp ;brif we got a right paren, but it
  366. ; was beyond the expression we were
  367. ; called to parse.  Exit without
  368. ; consuming this right paren.
  369. add [pExpTos],2 ;pop left paren's precedence
  370. mov ax,opLParen ;emit opLParen pcode
  371. call Emit16_AX
  372. call ScanTok ;skip right paren
  373. jmp SHORT State2 ;state remains ExpBinaryOp
  374. ;Check for relational operator
  375. ; di = IOP_xxx for operator
  376. ;
  377. NotRightParen:
  378. call RelOp ;see if its a relational operator
  379. je ConsumeOp ;branch if not
  380. ;iop = RelOp() + IOP_EQ - 1
  381. add al,IOP_EQ - 1 ;ax = operator index - IOP_EQ - 1
  382. xchg di,ax ;di = IOP for relational operator
  383. ;This is executed when we have scanned an operator while parsing
  384. ; an expression.  All stacked operators with precedence greator or
  385. ; equal to the scanned operator are emitted, then the scanned operator
  386. ; is stacked.  This is how we convert infix to postfix (or reverse polish).
  387. ; di = IOP_xxx for operator
  388. ;
  389. ConsumeOp:
  390. mov si,[pExpTos] ;si points to top of exp stack
  391. mov al,mpIopPrecedence[di] ;al = operator's precedence
  392. sub ah,ah ;ax = operator's precedence
  393. shl di,1 ;di = IOP_xxx * 2
  394. push mpIopOpcode[di] ;save current operator's opcode
  395. mov di,ax ;di = operator's precedence
  396. test al,FOP_unary
  397. jne EmitDone ;brif unary operator (must be stacked
  398. ; until we emit the term it applies to)
  399. EmitLoop:
  400. cmp [si],di
  401. jb EmitDone ;brif stacked operand's precedence
  402. ; is less than precedence of
  403. ; current operator
  404. ; (i.e. leave relatively high precedence
  405. ;  operators on the stack)
  406. inc si ;pop stacked operator's precedence
  407. inc si
  408. lodsw ;pop and emit stacked operator's opcode
  409. call Emit16_AX ;emit the stacked opcode
  410. jmp SHORT EmitLoop
  411. EmitDone:
  412. sub si,4 ;make room for new entry
  413. mov [si],di ;push current operator's precedence
  414. pop [si+2] ;push current operator's opcode
  415. mov [pExpTos],si ;save exp stack ptr
  416. cmp si,dataOFFSET stkExpMin
  417. jbe J_ExpTooComplex ;brif exp stack overflow
  418. jmp Scan_State1 ;scan token, advance state
  419. J_ExpTooComplex:
  420. jmp ExpTooComplex ;Error: Expression too complex
  421. ;Now we call PopTillLParen to cause all operators stacked by this
  422. ; recursive invocation of NtExp to be emitted.  It also detects
  423. ; if the parenthesis for this expression don't balance, i.e.
  424. ; the expression ((a+5)
  425. ;
  426. EndOfExp:
  427. call PopTillLParen
  428. jne ParensBalance ;brif paranthesis are balanced
  429. mov ax,MSG_RightParen ;Error: Expected ')'
  430. jmp ExpErrMsg
  431. ;Now we pop the minimum precedence operator stack marker which was
  432. ;stacked when we entered this recursive invocation of NtExp
  433. ;
  434. ParensBalance:
  435. inc [cIdArgs]
  436. mov al,PR_GoodSyntax ;This is (and must remain) the only
  437. ; exit which returns PR_GoodSyntax
  438. NtExpExit:
  439. add [pExpTos],2 ;pop off initial stopper
  440. pop [mkVar.MKVAR_flags] ;restore caller's mkVar.flags
  441. or al,al ;set condition codes for caller
  442. cEnd NtExp
  443. subttl Intrinsic Function Nonterminal
  444. ;**********************************************************************
  445. ; PARSE_RESULT NEAR NtIntrinsic()
  446. ;
  447. ; Purpose:
  448. ; Parse an intrinsic function.
  449. ;
  450. ; Entry:
  451. ; If the static variable [oNamConstPs] is non-zero, intrinsic
  452. ;    functions are not allowed
  453. ;
  454. ; Exit:
  455. ; The value of cIdArgs is preserved
  456. ; If no intrinsic is found, no tokens are consumed, no opcodes
  457. ;    are emitted, and the return value is PR_NotFound.
  458. ; If it is found, a corresponding opcode is emitted and
  459. ;    Parse() is called to check the syntax and generate code
  460. ;    for it.  If the syntax for the intrinsic is good, the
  461. ;    return code is PR_GoodSyntax.  If not the return code
  462. ;    is PR_BadSyntax.
  463. ; Condition codes set based on value in al
  464. ;
  465. ;******************************************************************
  466. cProc NtIntrinsic <PUBLIC,NODATA,NEAR>,<si,di>
  467. cBegin NtIntrinsic
  468. sub al,al ;prepare to return PR_NotFound 
  469. mov bx,[pTokScan] ;bx points to current token
  470. cmp [bx.TOK_class],CL_resWord
  471. jne NtIntrExit ;brif not a reserved word
  472. mov dx,[bx.TOK_rw_rwf] ;dx = reserved word flags
  473. test dx,RWF_FUNC
  474. je NtIntrExit ;brif token isn't for intrinsic func
  475. cmp [oNamConstPs],0
  476. je NotInCONST ;brif not in CONST a=<expression> stmt
  477. mov ax,MSG_InvConst ;Error: Invalid Constant
  478. call PErrMsg_AX ; al = PR_BadSyntax
  479. jmp SHORT NtIntrExit
  480. NotInCONST:
  481. push [pCurStkMark] ;preserve caller's pCurStkMarker
  482. push [cIdArgs] ;preserve caller's cIdArgs
  483. mov [cIdArgs],0 ;reset cIdArgs to 0 for this
  484. ; intrinsic function's code generator
  485. ;Fetch info for a particular intrinsic function out of the
  486. ;parser's reserved word table 'tRw'.
  487. mov si,[bx+TOK_rw_pArgs] ;si -> pRwArgs in tRw
  488. lods WORD PTR cs:[si] ;ax=state table offset for func's syntax
  489. mov cx,ax ;cx=state table offset
  490. sub di,di ;default to no code generator
  491. test dx,RWF_FUNC_CG
  492. je NoFuncCg ;branch if no code generator for func
  493. lods WORD PTR cs:[si] ;ax=adr of code generation func
  494. mov di,ax ;di=adr of code generation func
  495. lods WORD PTR cs:[si] ;ax=arg to pass to code generation func
  496. mov si,ax ;si=code generation arg
  497. NoFuncCg:
  498. push cx ;pass oState to Parse
  499. call ScanTok ;skip keyword token 
  500. pop ax ;ax = oState
  501. add ax,OFFSET CP:tState ;ax = pState = &(tState[oState])
  502. mov [pStateLastScan],ax
  503. call NtParse ;try to parse intrinsic function
  504. jle NtIntrNotGood ;branch if result isn't PR_GoodSyntax
  505. or di,di
  506. je NtIntrGoodSyntax ;branch if no function code generator
  507. mov ax,si ;pass arg to code generation routine
  508. ; (usually, this is an opcode)
  509. call di ;invoke code generation routine 
  510. NtIntrGoodSyntax:
  511. mov al,PR_GoodSyntax ;return PR_GoodSyntax
  512. jmp SHORT NtIntrRestore
  513. NtIntrNotGood:
  514. jl NtIntrRestore ;branch if result == PR_BadSyntax
  515. call PErrState ;Generate error message "Expected
  516. ; <a> or <b> or ..." 
  517. ;al = PR_BadSyntax
  518. NtIntrRestore:
  519. pop [cIdArgs] ;restore caller's cIdArgs
  520. pop [pCurStkMark] ;restore caller's pCurStkMarker
  521. NtIntrExit:
  522. or al,al ;set condition codes for caller
  523. cEnd NtIntrinsic
  524. subttl Literal Nonterminals
  525. UNARY_LIT EQU 0
  526. ; Used when CASE could only be followed by literal instead of Exp.
  527. ; May easily be useful for some future construct.
  528. ; Handles up to 1 unary minus.  Could easily be changed
  529. ; to handle unary +, we would just need to add the opcode.
  530. ;**********************************************************************
  531. ; PARSE_RESULT NEAR NtLit()
  532. ;
  533. ; Purpose:
  534. ; Parse any form of literal and, if found, generate a corresponding
  535. ; literal opcode.
  536. ;
  537. ; Exit:
  538. ; Returns either PR_GoodSyntax, PR_NotFound or PR_BadSyntax
  539. ; Condition codes set based on value in al
  540. ;
  541. ;******************************************************************
  542. cProc NtLit <PUBLIC,NODATA,NEAR>,<si,di>
  543. cBegin NtLit
  544. mov di,[pTokScan] ;di points to current token
  545. cmp [di.TOK_class],CL_lit
  546. jne LitNotFound ;brif already got a unary op
  547. sub ax,ax
  548. or al,[di.TOK_lit_errCode] ;ax = lexical analyzer's error code
  549. jne LitSnErr ;brif lexical analyzer found an error
  550. ; in literal's format
  551. lea si,[di.TOK_lit_value_I2];si points to literal's value
  552. mov bl,[di.TOK_lit_litType] ;bl = LIT_xxx for literal
  553. cmp bl,LIT_STR
  554. je GotLitSD
  555. cmp bl,LIT_I2
  556. jne @F ;branch if not a decimal integer
  557. mov ax,[si]  ;ax = value
  558. cmp ax,opLitI2Max ; Is value within pcode limit
  559. ja @F ;branch if value isn't 0..10
  560. .erre OPCODE_MASK EQ 03ffh ; Assure following code is ok
  561. mov ah,al
  562. mov al,0 ; AX = literal * 0100h
  563. shl ax,1 ; AX = literal * 0200h
  564. shl ax,1 ; AX = literal * 0400h
  565. add ax,opLitI2 ;opcode = opLitI2 w/value in upper bits
  566. call Emit16_AX
  567. jmp SHORT NtLitGoodSyntax
  568. @@:
  569. sub bh,bh ;bx = LIT_xxx for literal
  570. mov al,[tLitCwValue + bx] ;al = # words in literal's value
  571. sub ah,ah ;ax = # words in literal's value
  572. mov di,ax ;di = # words in literal's value
  573. shl bx,1 ;bx = 2 * LIT_xxx for literal
  574. mov ax,[tLitOpcodes + bx] ;ax = opcode
  575. call Emit16_AX ;emit the opcode
  576. EmitLitLoop:
  577. lodsw ;ax = next word of literal's value
  578. call Emit16_AX
  579. dec di
  580. jne EmitLitLoop ;branch if more words to emit
  581. jmp SHORT NtLitGoodSyntax
  582. ;Got a string constant like "xxxxxxx"
  583. ;Emit all source characters between the double quotes.
  584. ;If <cbText> is odd, <cbText> is emitted as an odd value,
  585. ;and an extra pad byte is appended to keep pcode even-byte alligned.  
  586. ;
  587. GotLitSD:
  588. mov ax,opLitSD
  589. call Emit16_AX
  590. mov ax,[di.TOK_oSrc] ;ax = column token started in
  591. inc ax ;ax = oSrc + 1 (skip ")
  592. push ax ;pass it to EmitSrc
  593. mov ax,[si] ;ax = length of string literal in bytes
  594. ;TOK_lit_value_cbStr
  595. push ax ;pass size of string to EmitSrc
  596. call Emit16_AX ;emit size of the string
  597. call EmitSrc ;emit the string itself
  598. NtLitGoodSyntax:
  599. call ScanTok ;skip literal token
  600. mov al,PR_GoodSyntax
  601. NtLitExit:
  602. or al,al ;set condition codes for caller
  603. cEnd NtLit
  604. LitNotFound:
  605. sub ax,ax ;prepare to return PR_NotFound
  606. jmp SHORT NtLitExit ;brif we didn't consume unary opcode
  607. ;ax = error encountered by lexical analyzer when scanning number
  608. LitSnErr:
  609. call PErrMsg_AX ; al = PR_BadSyntax
  610. jmp SHORT NtLitExit
  611. sEnd CP
  612. sBegin DATA
  613. ;Tables used by NtLit
  614. ;Following tables assume following constants:
  615. OrdConstStart 0
  616. OrdConst LIT_I2 ; % suffix
  617. OrdConst LIT_O2 ; &O prefix
  618. OrdConst LIT_H2 ; &H prefix
  619. OrdConst LIT_I4 ; & suffix
  620. OrdConst LIT_O4 ; &&O prefix
  621. OrdConst LIT_H4 ; &&H prefix
  622. OrdConst LIT_R4 ; ! suffix
  623. OrdConst LIT_R8 ; # suffix
  624. OrdConst LIT_STR ; "xxx"
  625. tLitOpcodes LABEL WORD
  626. DW opLitDI2 ;LIT_I2  (% suffix)
  627. DW opLitOI2 ;LIT_O2  (&O prefix)
  628. DW opLitHI2 ;LIT_H2  (&H prefix)
  629. DW opLitDI4 ;LIT_I4  (& suffix)
  630. DW opLitOI4 ;LIT_O4  (&&O prefix)
  631. DW opLitHI4 ;LIT_H4  (&&H prefix)
  632. DW opLitR4 ;LIT_R4  (! suffix)
  633. DW opLitR8 ;LIT_R8  (# suffix)
  634. tLitCwValue LABEL BYTE
  635. DB 1 ;LIT_I2  (% suffix)
  636. DB 1 ;LIT_O2  (&O prefix)
  637. DB 1 ;LIT_H2  (&H prefix)
  638. DB 2 ;LIT_I4  (& suffix)
  639. DB 2 ;LIT_O4  (&&O prefix)
  640. DB 2 ;LIT_H4  (&&H prefix)
  641. DB 2 ;LIT_R4  (! suffix)
  642. DB 4 ;LIT_R8  (# suffix)
  643. sEnd DATA
  644. sBegin CP
  645. ;**********************************************************************
  646. ; PARSE_RESULT NEAR NtLitI2() - Parse & emit 16-bit integer
  647. ; Purpose:
  648. ; Parse and emit a 16-bit signed integer.  Note this is very
  649. ; different from NtLit() in that it emits no opcode, just
  650. ; a 16 bit value.  It is the responsibility of the caller
  651. ; to emit the opcode before calling this function.
  652. ; If a numeric literal is found, but it is > 32k,
  653. ; an Overflow error message is generated.
  654. ; Exit:
  655. ; Returns PR_GoodSyntax, PR_BadSyntax or PR_NotFound
  656. ; Condition codes set based on value in al
  657. ;
  658. ;******************************************************************
  659. PUBLIC NtLitI2
  660. NtLitI2 PROC NEAR
  661. sub al,al ;prepare to return PR_NotFound
  662. mov bx,[pTokScan] ;bx points to current token
  663. cmp [bx.TOK_class],CL_lit
  664. jne NtLitI2Exit ;branch if token isn't a literal
  665. cmp [bx.TOK_lit_type],ET_I2
  666. jne NtLitI2Ov ;brif token isn't a signed 16 bit int
  667. mov ax,[bx.TOK_lit_value_I2];ax = value
  668. call Emit16_AX ;emit it
  669. call ScanTok ;consume token
  670. mov al,PR_GoodSyntax ;return PR_GoodSyntax
  671. NtLitI2Exit:
  672. or al,al ;set condition codes for caller
  673. ret
  674. NtLitI2Ov:
  675. mov ax,ER_OV ;Overflow
  676. jmp PErrMsg_AX ;al = PR_BadSyntax
  677. ; return to caller
  678. NtLitI2 ENDP
  679. ;**********************************************************************
  680. ; PARSE_RESULT NEAR NtLit0() - Parse the literal 0, emit nothing
  681. ;******************************************************************
  682. PUBLIC NtLit0
  683. NtLit0 PROC NEAR
  684. sub cx,cx ;expect constant 0
  685. NtLit1Shared:
  686. sub al,al ;prepare to return PR_NotFound
  687. mov bx,[pTokScan] ;bx points to current token
  688. cmp [bx.TOK_class],CL_lit
  689. jne NtLit0Exit ;branch if token isn't a literal
  690. cmp [bx.TOK_lit_type],ET_I2
  691. jne NtLit0Exit ;brif token isn't a signed 16 bit int
  692. cmp [bx.TOK_lit_value_I2],cx
  693. jne NtLit0Exit ;branch if token isn't 0
  694. call ScanTok ;consume token
  695. mov al,PR_GoodSyntax ;return PR_GoodSyntax
  696. NtLit0Exit:
  697. ret
  698. NtLit0 ENDP
  699. ;**********************************************************************
  700. ; PARSE_RESULT NEAR NtLit1() - Parse the literal 1, emit nothing
  701. ;******************************************************************
  702. PUBLIC NtLit1
  703. NtLit1 PROC NEAR
  704. mov cx,1 ;expect constant 1
  705. jmp SHORT NtLit1Shared
  706. NtLit1 ENDP
  707. ;**********************************************************************
  708. ; PARSE_RESULT NEAR NtLitString() - Parse a string literal
  709. ;******************************************************************
  710. cProc NtLitString <PUBLIC,NODATA,NEAR>
  711. cBegin NtLitString
  712. sub al,al ;prepare to return PR_NotFound
  713. mov bx,[pTokScan] ;bx points to current token
  714. cmp [bx.TOK_lit_type],ET_SD
  715. jne NtLitStringExit ;branch if token isn't string constant
  716. call NtLit ;ax = result of parsing the string
  717. NtLitStringExit:
  718. cEnd NtLitString
  719. sEnd CP
  720. end