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

操作系统开发

开发平台:

Visual C++

  1. TITLE prscg.asm - Parser Code Generation Functions
  2. ;==========================================================================
  3. ;
  4. ;  Module:  prscg.asm - Parser Code Generation Functions
  5. ;  Subsystem:  Parser
  6. ;  System:  Quick BASIC Interpreter
  7. ;
  8. ;==========================================================================
  9. include version.inc
  10. PRSCG_ASM = ON
  11. includeOnce architec
  12. includeOnce context
  13. includeOnce heap
  14. includeOnce opmin
  15. includeOnce opcontrl
  16. includeOnce opstmt
  17. includeOnce opintrsc
  18. includeOnce parser
  19. includeOnce pcode
  20. includeOnce prstab
  21. includeOnce psint
  22. includeOnce qbimsgs
  23. includeOnce rtps
  24. includeOnce scanner
  25. includeOnce txtmgr
  26. includeOnce ui
  27. includeOnce util
  28. includeOnce variable
  29. ;--------------------------------------------------------------------------
  30. ; Code Generation Overview
  31. ;
  32. ; During the course of interpreting the parse state tables, NtParse()
  33. ; encounters MARK(nnn) directives.  These cause NtParse to push
  34. ; the current pcode offset and the constant nnn onto a stack as follows:
  35. ;
  36. ; Given BNF of
  37. ;     exp MARK(1) exp MARK(2) exp
  38. ;
  39. ; Before parsing the statement, the marker stack looks like:
  40. ;    high memory:
  41. ; maxStkMark-->        <--pCurStkMark
  42. ;           :
  43. ; minStkMark-->
  44. ;    low memory:
  45. ;
  46. ; After parsing the statement, but before calling the code generation
  47. ; function for the statement, the marker stack looks like:
  48. ;    high memory:
  49. ; maxStkMark-->[oDstPcode]
  50. ;
  51. ;                    [oDstPcode]
  52. ; <--pCurStkMark
  53. ;           :
  54. ; minStkMark-->
  55. ;    low memory:
  56. ;
  57. ; Code generation functions use the information on the marker stack to
  58. ; decide how to alter pcode already emitted to the pcode buffer during
  59. ; parsing.
  60. ; An Argument may be passed to a code generation function in ax.
  61. ;
  62. ;--------------------------------------------------------------------------
  63. assumes ds,DATA
  64. assumes ss,DATA
  65. assumes es,NOTHING
  66. sBegin DATA
  67. sEnd DATA
  68. sBegin CP
  69. assumes cs,CP
  70. ;*********************************************************************
  71. ; VOID InsertOp(ax:opcode, bx:oDst)
  72. ;
  73. ; Purpose:
  74. ; Insert an opcode at a given offset into the pcode buffer
  75. ; If out-of-memory, ps.errCode = ER_OM on exit
  76. ;
  77. ; Entry:
  78. ; bx = offset into ps.bdpDst where word is to be inserted
  79. ; ax = word to be inserted
  80. ; Exit:
  81. ; Caller's can depend on bx being preserved
  82. ; If an out-of-memory error occurs, ps.errCode = ER_OM
  83. ;
  84. ;*********************************************************************
  85. InsertOp PROC NEAR
  86. ;make room for 2 bytes in pcode buffer before oDst
  87. ; BdShiftRight((bd *)&ps.bdpDst, oDst, (ushort)2))
  88. push bx ;save caller's bx
  89. push ax ;save opcode
  90. push bx ;save oDst
  91. PUSHI ax,<dataOFFSET ps.PS_bdpDst>
  92. push bx ;pass oDst
  93. PUSHI ax,2
  94. call BdShiftRight ;grow buf, can cause heap movement
  95. or ax,ax
  96. je InsOpOmErr ;brif out-of-memory
  97. call SetDstPbCur ;update ps.bdpDst.pbCur,
  98. pop bx ;restore bx = oDst
  99. add bx,[ps.PS_bdpDst.BDP_pb]
  100. pop [bx] ;pop and store opcode
  101. InsOpExit:
  102. pop bx ;restore caller's bx
  103. ret
  104. InsOpOmErr:
  105. call ParseErrOm ;Error "Out of memory"
  106. pop bx
  107. pop ax
  108. jmp SHORT InsOpExit
  109. InsertOp ENDP
  110. ;*********************************************************************
  111. ; VOID NEAR CgOn(ax:opcode)
  112. ;
  113. ; Purpose:
  114. ; Called after the RESTORE/RETURN statement has been parsed.
  115. ; It generates code for the statement.
  116. ;
  117. ; Entry:
  118. ; The top of the MARK stack (*pCurStkMark) is 1 or 2 for
  119. ;    1 for RESTORE
  120. ;    2 for RESTORE <label>
  121. ; opcode = the opcode to emit if top of MARK stack = 1
  122. ;    This can be opStRestore0 or opStReturn0
  123. ;
  124. ; The bnf which causes this to occur is:
  125. ;   tkON (event (tkGOSUB ((Lit0 EMIT(opEvGosub) EMIT(UNDEFINED)) |
  126. ; (EMIT(opEvGosub) LabLn)))) |
  127. ;     (tkERROR tkGOTO ((Lit0 EMIT(opStOnError) EMIT(UNDEFINED)) |
  128. ; (EMIT(opStOnError) LabLn))) |
  129. ;     (Exp (tkGOTO MARK(1) | tkGOSUB MARK(2)) LabLn {tkComma LabLn})
  130. ; <CgOn()>
  131. ;
  132. ;*********************************************************************
  133. PUBLIC CgOn
  134. CgOn PROC NEAR
  135. mov bx,[pCurStkMark]
  136. cmp bx,MAX_STK_MARK
  137. je OnExit ;brif no MARK directives from BNF
  138. push [bx] ;save markId
  139. mov bx,[bx+2] ;bx = offset into pcode which preceeded
  140. ; markId
  141. mov ax,[ps.PS_bdpDst.BDP_cbLogical]
  142. sub ax,bx ;ax = byte count of operands
  143. call InsertOp ;insert word AX at offset BX
  144. ; (bx is preserved)
  145. pop ax ;restore ax = markId
  146. cmp al,1 ;markId
  147. mov ax,opStOnGoto
  148. je GotGoto ;brif if MARK(1) directive (GOTO)
  149. mov ax,opStOnGosub ;else it must be MARK(2) (GOSUB)
  150. GotGoto:
  151. call InsertOp ;insert word AX at offset BX
  152. OnExit:
  153. ret
  154. CgOn ENDP
  155. ;*********************************************************************
  156. ; VOID NEAR CgInsert0or1(opcode)
  157. ;
  158. ; Purpose:
  159. ; Called after the RESTORE/RETURN statement has been parsed.
  160. ; It generates code for the statement.
  161. ; If out-of-memory, ps.errCode = ER_OM on exit
  162. ;
  163. ; Entry:
  164. ; The top of the MARK stack (*pCurStkMark) is 1 or 2 for
  165. ;    1 for RESTORE/RETURN/RESUME
  166. ; (generated pcode = opStRestore0/opStReturn0/opStResume0)
  167. ;    2 for RESTORE/RETURN/RESUME <label>
  168. ; (generated pcode = opStRestore1/opStReturn1/opStResume <label>)
  169. ;    3 for RESUME 0
  170. ; (generated pcode = opStResume <UNDEFINED>)
  171. ;    4 for RESUME NEXT
  172. ; (generated pcode = opStResumeNext)
  173. ;
  174. ; opcode = the opcode to emit if top of MARK stack = 1
  175. ;    This can be opStRestore0, opStReturn0, or opStResume0
  176. ;
  177. ; The bnf which causes this to occur is:
  178. ;    tkRESTORE MARK(1) [LabLn MARK(2)]
  179. ;  <CgInsert0or1(opStRestore0)>
  180. ;    tkRETURN MARK(1) [LabLn MARK(2)]
  181. ;  <CgInsert0or1(opStReturn0)>
  182. ;    tkRESUME MARK(1) [(LabLn MARK(2)) | (Lit0 MARK(3)) |
  183. ;                      (tkNEXT MARK(4))]
  184. ; <CgResume(opStResume0)>
  185. ;
  186. ;*********************************************************************
  187. PUBLIC CgInsert0or1
  188. CgInsert0or1 PROC NEAR
  189. xchg dx,ax ;save opcode in dx
  190. mov bx,[pCurStkMark]
  191. mov al,[bx] ;al = markId
  192. cmp al,1
  193. je InsMark1 ;brif got RESUME or RETURN or RESTORE
  194. ; with no parameter
  195. cmp al,2
  196. je InsMark2
  197. cmp al,3
  198. je InsMark3 ;brif got RESUME 0
  199. ;else it must be MARK(4) RESUME NEXT
  200. mov ax,opStResumeNext
  201. jmp SHORT InsEmit
  202. ;got RESUME or RETURN or RESTORE with no parameter
  203. InsMark1:
  204. xchg ax,dx ;ax = opcode
  205. InsEmit:
  206. call Emit16_AX
  207. jmp SHORT InsExit
  208. InsMark2:
  209. push dx ;save opcode
  210. ;make room for 2 more bytes at end of pcode buffer
  211. PUSHI ax,<dataOFFSET ps.PS_bdpDst>
  212. PUSHI ax,2
  213. call BdGrow ;grow buf, can cause heap movement
  214. or ax,ax
  215. je InsOmErr
  216. ;move label's oNam forward in buffer by 2 bytes
  217. mov bx,[ps.PS_bdpDst.BDP_pbCur]
  218. mov ax,[bx-2]
  219. mov [bx],ax
  220. ;Insert opcode before label's oNam
  221. pop ax ;ax = opcode
  222. inc ax ;map to opcode variant with no parm
  223. ; opStResumeLab opStRestoreLab or
  224. ; opStReturnLab
  225. mov [bx-2],ax ;store opcode
  226. call SetDstPbCur ;update ps.bdpDst.pbCur
  227. jmp SHORT InsExit
  228. ;map RESUME 0 to opStResume(UNDEFINED)
  229. InsMark3:
  230. mov ax,opStResume
  231. call Emit16_AX
  232. mov ax,UNDEFINED
  233. call Emit16_AX
  234. InsExit:
  235. ret
  236. InsOmErr:
  237. jmp ParseErrOm ;Error "Out of memory"
  238. ; and return to caller
  239. CgInsert0or1 ENDP
  240. ;*********************************************************************
  241. ; ErrIfPrsHasTxtTbl()
  242. ; Purpose:
  243. ; If the current prs (prsCur) has a text table, generate an error.
  244. ; This is called by functions which are about to do something which
  245. ; can only be done to a "compiled" (external) procedure, not a
  246. ; pcoded procedure.
  247. ;
  248. ; Exit:
  249. ; returns FALSE if prsCur has a text table (condition codes set)
  250. ;
  251. ;*********************************************************************
  252. ErrIfPrsHasTxtTbl PROC NEAR
  253. sub ax,ax ;prepare to return FALSE
  254. test [txdCur.TXD_flags],FTX_mrs
  255. jne ErrNoText ;brif prs has no text table
  256. mov ax,MSG_InvDecl OR PSERR_fAlert
  257. call ParseErr0
  258. mov ax,sp ;return TRUE (non-zero)
  259. ErrNoText:
  260. or ax,ax ;set condition codes for caller
  261. ret
  262. ErrIfPrsHasTxtTbl ENDP
  263. ;*********************************************************************
  264. ; VOID NEAR CgDeclare(opcode)
  265. ;
  266. ; Purpose:
  267. ; Called after the DECLARE, SUB, FUNCTION or DEF FN statement has
  268. ; been parsed.  It generates code for the statement.
  269. ; The prs has already been created (by MakeProc in prsid.asm),
  270. ; and is active for all statements except DECLARE.
  271. ;
  272. ; Entry:
  273. ; Structure pdcl is filled in by parser terminal recognizers like
  274. ;    NtIdSubDecl, NtIdFn [QB4], etc. to describe to prs being declared/defined
  275. ; The MARK stack (*pCurStkMark) contains entries built by the bnf:
  276. ;    MARK 1    indicates CDECL was present
  277. ;    MARK 2 -> ALIAS's string literal
  278. ;    MARK 3 -> start of formal parm list
  279. ;    MARK 4    indicates STATIC was found
  280. ;    MARK 5 -> single line DEF FN's definition expression
  281. ;    MARK 6    indicates ([parmlist]) was seen
  282. ;    MARK 7 -> LIB's string literal [EB specific] [07]
  283. ;    MARK 8    indicates AUTO was found [EB specific] [07]
  284. ;
  285. ; BNF which builds entry pcode:
  286. ;    tkDECLARE
  287. ;       (tkFUNCTION IdFuncDecl [tkCDECL MARK(1)]
  288. ;          [tkALIAS MARK(2) LitString] MARK(3) parms) |
  289. ;       (tkSUB IdSubDecl [tkCDECL MARK(1)] 
  290. ;          [tkALIAS MARK(2) LitString] MARK(3) parms)
  291. ;      <CgDeclare(opStDeclare)>
  292. ;    tkDEF IdFn MARK(3) parms [tkEQ MARK(5) Exp]
  293. ;      <CgDeclare(opStDefFn)>
  294. ;    tkFUNCTION IdFuncDef MARK(3) parms [tkSTATIC MARK(4)]
  295. ;      <CgDeclare(opStFunction)>
  296. ;    tkSUB IdSubDef MARK(3) parms [tkSTATIC MARK(4)]
  297. ;      <CgDeclare(opStSub)>
  298. ;
  299. ; For the statement DECLARE SUB X CDECL ALIAS "abc" (BYVAL A(), B, ...)
  300. ; The pcode buffer contains:
  301. ;               <"abc"> <idA> <idB> ...
  302. ; MARK(1)MARK(2)^MARK(3)^
  303. ;
  304. ; For the statement SUB X (BYVAL A(), B, ...) STATIC
  305. ; The pcode buffer contains:
  306. ;        <idA> <idB> ...
  307. ; MARK(3)^MARK(8)
  308. ;
  309. ; Where <idX> is 3 16 bit words:  oPrs, oNamProc, oTypProc
  310. ;
  311. ;*********************************************************************
  312. cProc CgDeclare,<PUBLIC,NEAR,NODATA>,<si,di>
  313. localW opcode
  314. localW oDstParms
  315. localW oDstAlias
  316. localW oDstEndDef
  317. localW cbLibInfo
  318. localW procAtr
  319. procAtr_LO EQU  BYTE PTR (procAtr)
  320. procAtr_HI EQU  BYTE PTR (procAtr+1)
  321. cBegin
  322. mov [opcode],ax
  323. mov ax,[ps.PS_bdpDst.BDP_cbLogical]
  324. mov [oDstEndDef],ax ;save current size of output
  325. sub ax,ax
  326. mov [procAtr],ax
  327. mov [oDstAlias],ax
  328. mov [cbLibInfo],ax
  329. mov al,[pdcl.PDCL_procType]
  330. .errnz DCLA_procType - 0300h
  331. or [procAtr_HI],al ;save procType in pcode field
  332. mov al,[pdcl.PDCL_oTyp] ;al = value for low byte of ProcAtr
  333. ;  word which DCLA_Explicit,
  334. ;  DCLA_AsClause, and DCLA_oTyp
  335. mov [procAtr_LO],al ;save oTyp in pcode field
  336. sub ax,ax
  337. cmp [pdcl.PDCL_fDeclare],al
  338. je NotDeclare ;brif not DECLARE stmt
  339. cmp [pdcl.PDCL_cParms],ax
  340. jne MarkDisp ;brif got a parm list
  341. dec [pdcl.PDCL_cParms] ;set to UNDEFINED so scanner knows
  342. ; to not use this for parm
  343. ; type/count checking
  344. jmp SHORT MarkDisp
  345. NotDeclare:
  346. ;If we don't get MARK(4), this SUB/FUNCTION has no STATIC keyword
  347. and [prsCur.PRS_flags],NOT FP_STATIC
  348. ;-------------------------------------------------
  349. ;walk through MARK(xxx) entries from left to right
  350. ;-------------------------------------------------
  351. MarkDisp:
  352. mov si,MAX_STK_MARK
  353. DeclMarkLoop:
  354. cmp [pCurStkMark],si
  355. jne DeclNextMark
  356. jmp SHORT DeclEndOfMarks
  357. DeclNextMark:
  358. dec si
  359. dec si
  360. mov di,[si] ;di = oDstOpcode
  361. dec si
  362. dec si
  363. mov ax,[si] ;ax = al = markId
  364. dec ax
  365. DbAssertRel ax,be,9,CP,<Unexpected MARK in CgDeclare()>
  366. shl ax,1
  367. xchg ax,bx ;bx = 2 * (markId - 1)
  368. jmp WORD PTR cs:DeclDispTbl[bx] ;dispatch based on markId
  369. DeclDispTbl:
  370. DW DeclMark1 ;CDECL
  371. DW DeclMark2 ;ALIAS
  372. DW DeclMark3 ;parms (before left paren)
  373. DW DeclMark4 ;STATIC
  374. DW DeclMark5 ;single line DEF
  375. DW DeclMark6 ;1st parm (after left paren)
  376. ;MARK(1):  Got CDECL directive
  377. DeclMark1:
  378. call ErrIfPrsHasTxtTbl
  379. jne DeclMarkLoop ;brif prs has a text table
  380. .errnz DCLA_cdecl - 8000h
  381. or [procAtr_HI],80h ;remember we got CDECL
  382. jmp SHORT DeclMarkLoop
  383. ;MARK(2):  Got ALIAS directive
  384. DeclMark2:
  385. call ErrIfPrsHasTxtTbl
  386. mov [oDstAlias],di ;save offset to opLitSD("<alias>")
  387. jmp SHORT DeclMarkLoop
  388. ;MARK(3):  got offset to formal parm list
  389. DeclMark3:
  390. mov [oDstParms],di
  391. jmp SHORT DeclMarkLoop
  392. ;MARK(4):  got STATIC keyword at end of proc definition
  393. DeclMark4:
  394. or [prsCur.PRS_flags],FP_STATIC
  395. jmp SHORT DeclMarkLoop
  396. ;MARK(5):  got single line DEF FN
  397. DeclMark5:
  398. mov [oDstEndDef],di
  399. mov ax,opEndSingleDef
  400. call Emit16_AX
  401. mov ax,2
  402. call Emit16_AX ;emit cntEos word
  403. call Emit16_0 ;emit space for link field
  404. jmp SHORT DeclMarkLoop
  405. ;MARK(6):  got ( [parmlist] )
  406. DeclMark6:
  407. cmp [pdcl.PDCL_cParms],UNDEFINED ;so scanner knows to not use this
  408. ; for parm type/count checking
  409. jne DeclMarkLoop ;brif got a parm list
  410. inc [pdcl.PDCL_cParms] ;so scanner knows to use this declare
  411. ; for parm type/count checking
  412. jmp SHORT DeclMarkLoop
  413. DeclEndOfMarks:
  414. ;Copy Alias text after formal parms
  415. mov ax,[oDstAlias]
  416. or ax,ax
  417. je NoAliasArg
  418. call CopyLit ;ax = cbAlias
  419. mov [cbLibInfo],ax
  420. shl al,1
  421. shl al,1
  422. .errnz DCLA_cbAlias - 7C00h
  423. or [procAtr_HI],al ;save cbAlias in pcode field
  424. ;squeeze source of ALIAS lit out of pcode buffer
  425. ;BdShiftLeft((bd *)&ps.bdpDst, oDstAlias, oDstParms - oDstAlias)
  426. PUSHI ax,<dataOFFSET ps.PS_bdpDst>
  427. push [oDstAlias]
  428. mov ax,[oDstParms]
  429. sub ax,[oDstAlias] ;ax = number of bytes to delete
  430. push ax
  431. sub [oDstParms],ax ;update for the left shift
  432. sub [oDstEndDef],ax ;update for the left shift
  433. call BdShiftLeft ;grow buf, can cause heap movement
  434. NoAliasArg:
  435. ;Now make room for things to insert before parm list:
  436. ; opcode, byte-count-till-end-of-stmt, link field for DEF FNs, oPrs
  437. mov si,10 ;assume we need to insert 10 bytes
  438. cmp [pdcl.PDCL_procType],PT_DEFFN
  439. jne NotDefFn1 ;brif not DEF FN stmt
  440. inc si ;need 2 extra bytes for link field
  441. inc si
  442. NotDefFn1:
  443. ;BdShiftRight((bd *)&ps.bdpDst, oDstParms, cbInsert)
  444. PUSHI ax,<dataOFFSET ps.PS_bdpDst>
  445. push [oDstParms]
  446. push si ;pass cbInsert parm
  447. call BdShiftRight
  448. or ax,ax
  449. jne ShiftOk ;brif no out-of-memory error
  450. call ParseErrOm ;Error "Out of memory"
  451. jmp SHORT DeclExit
  452. ShiftOk:
  453. call SetDstPbCur ;update ps.bdpDst.pbCur after BdShift...
  454. push ds
  455. pop es ;es = ds for stosw below
  456. mov di,[oDstParms]
  457. add di,[ps.PS_bdpDst.BDP_pb]
  458. mov ax,[opcode]
  459. stosw ;store opcode in pcode buffer
  460. ;emit cntEos operand
  461. mov ax,[oDstEndDef]
  462. sub ax,[oDstParms]
  463. add ax,si ;include cbInsert
  464. add ax,[cbLibInfo] ;add #bytes in LIB and ALIAS clause
  465. sub ax,4
  466. inc ax ;round up to even byte count
  467. and al,0FEH
  468. stosw ;store cntEos operand
  469. cmp [pdcl.PDCL_procType],PT_DEFFN
  470. jne NotDefFn2 ;brif not DEF FN stmt
  471. stosw ;leave room for DEF FN link field
  472. NotDefFn2:
  473. mov ax,[pdcl.PDCL_oPrs]
  474. or ax,ax
  475. jns NotUnboundDefFn
  476. mov ax,[pdcl.PDCL_oNam] ;for [DECLARE] DEF FNs, in SS_RUDE
  477. ;state, emit the oNam
  478. NotUnboundDefFn:
  479. stosw ;store oPrs/oNam operand
  480. mov ax,[procAtr]
  481. stosw ;store proc's oTyp
  482. mov ax,[pdcl.PDCL_cParms]
  483. stosw ;store cParms operand
  484. DeclExit:
  485. cEnd
  486. ;*********************************************************************
  487. ; CopyLit(ax:oDstLit)
  488. ; Purpose:
  489. ; Move the ASCII text of an opLitSD to the end of the pcode buffer.
  490. ; If string is longer than 255 bytes, it is truncated.
  491. ; Entry:
  492. ; ax = offset into pcode buffer to opLitSD opcode
  493. ; [EB] bx = TRUE iff length of string is to output as byte preceeding
  494. ;   text of string. 
  495. ; Exit:
  496. ; string is moved to end of pcode buffer and the opLitSd is removed
  497. ; ax = length of string
  498. ;
  499. ;*********************************************************************
  500. CopyLit PROC NEAR
  501. push si
  502. mov si,ax
  503. add si,[ps.PS_bdpDst.BDP_pb]
  504. lodsw ;skip opLitSD opcode
  505. DbAssertRel ax,e,opLitSD,CP,<CopyLit: expected opLitSD> 
  506. lodsw ;ax = cb operand from opLitSD
  507. or ah,ah
  508. je LenOk
  509. mov ax,255 ;truncate string
  510. LenOk:
  511. push ax ;save for return value
  512. inc ax ;round up to word count
  513. shr ax,1
  514. mov cx,ax
  515. jcxz CLitExit ;brif entire string has been copied
  516. CLitLoop:
  517. push cx ;save word count
  518. lodsw ;ax = next 2 bytes of string
  519. sub si,[ps.PS_bdpDst.BDP_pb] ;Emit16 can cause heap movement
  520. call Emit16_AX
  521. add si,[ps.PS_bdpDst.BDP_pb] ;reconvert offset to pointer
  522. pop cx ;restore word count
  523. loop CLitLoop
  524. CLitExit:
  525. pop ax ;ax = string length
  526. pop si
  527. ret
  528. CopyLit ENDP
  529. ;*********************************************************************
  530. ; CgCall(opcode)
  531. ; Purpose:
  532. ; Called to generate pcode for the following bnf:
  533. ;  tkCALL (MARK(1) IdImplicit
  534. ;    [tkLParen IdCallArg {tkComma IdCallArg} tkRParen])
  535. ;  tkCALLS MARK(1) IdImplicit
  536. ;    [tkLParen IdCallArg {tkComma IdCallArg} tkRParen]
  537. ;
  538. ;*********************************************************************
  539. PUBLIC CgCall
  540. CgCall PROC NEAR
  541. push si ;save caller's si
  542. mov bx,MAX_STK_MARK
  543. mov si,[bx-2] ;si=offset in pcode for item after MARK
  544. push ax ;save opcode for Emit16 below
  545. mov bx,[ps.PS_bdpDst.BDP_pb]
  546. mov ax,[bx][si] ;ax = oNamIdSub
  547. call SubRef ;ax = oPrs for sub being called
  548. ;We can ignore error results, because
  549. ;if error occurs, no code will ever
  550. ;try to activate this oPrs, because
  551. ;line will be stored as opReParse
  552. ;delete the information emitted by NtIdImplicit()
  553. ;BdShiftLeft((bd *)&ps.bdpDst, oDstCur, 2)
  554. PUSHI dx,<dataOFFSET ps.PS_bdpDst>
  555. push si
  556. PUSHI dx,2
  557. mov si,ax ;si = oPrs
  558. call BdShiftLeft ;grow buf, can cause heap movement
  559. call SetDstPbCur ;set ps.bdpDst.pbCur after BdShiftLeft
  560. call Emit16 ;emit opcode pushed ~15 lines above
  561. push [cIdArgs]
  562. call Emit16 ;emit arg count
  563. push si ;push oPrs
  564. call Emit16
  565. pop si ;restore caller's si
  566. ret
  567. CgCall ENDP
  568. ;*********************************************************************
  569. ; VOID NEAR CgRun(opcode)
  570. ; Purpose:
  571. ; Invoked to generate code for the following bnf:
  572. ;  tkRUN [(Ln MARK(1)) | (Exp MARK(2))]; <CgRun()>
  573. ;
  574. ;*********************************************************************
  575. PUBLIC CgRun
  576. CgRun PROC NEAR
  577. mov bx,[pCurStkMark]
  578. cmp bx,MAX_STK_MARK
  579. mov ax,opStRunMain ;ax = opcode to emit for RUN
  580. je RunEmitExit ;brif simple RUN (no MARKs)
  581. DbAssertRelB [bx],be,2,CP,<Invalid MARK id in CgRun()>
  582. cmp BYTE PTR [bx],1
  583. jne RunFile ;brif markId != 1  (RUN <filename>)
  584. ;Got RUN <line number>, insert opStRunLabel before Ln
  585. mov bx,[bx+2] ;bx = pcode offset
  586. dec bx
  587. dec bx ;bx = pcode offset where opcode is to go
  588. mov ax,opStRunLabel
  589. call InsertOp ;insert word AX at offset BX
  590. jmp SHORT RunExit
  591. RunFile:
  592. mov ax,opStRunFile
  593. RunEmitExit:
  594. call Emit16_AX
  595. RunExit:
  596. ret
  597. CgRun ENDP
  598. ;*********************************************************************
  599. ; VOID NEAR CgInput(opcode)
  600. ; Purpose:
  601. ; Invoked to generate code for the following bnf:
  602. ;
  603. ; tkINPUT 
  604. ;  [(lbsInpExpComma MARK(16)) |
  605. ;   (tkSColon MARK(2) [LitString MARK(4) (tkSColon | (tkComma MARK(1)))])|
  606. ;   (LitString MARK(4) (tkSColon | (tkComma MARK(1))))]
  607. ;  MARK(8) IdAryElemRef EMIT(opStInput) {tkComma IdAryElemRef
  608. ;                                              EMIT(opStInput)}
  609. ;  EMIT(opInputEos)
  610. ;    <CgInput(opInputPrompt)>
  611. ;
  612. ; tkLINE tkINPUT
  613. ;  [(lbsInpExpComma MARK(16)) |
  614. ;   (tkSColon MARK(2) [LitString MARK(4) (tkSColon | (tkComma MARK(1)))]) |
  615. ;   (LitString MARK(4) (tkSColon | (tkComma MARK(1))))]
  616. ;  IdAryElemRef
  617. ;    <CgInput(opStLineInput)>
  618. ;
  619. ; It maps syntax to pcode as follows:
  620. ;    INPUT [;] [prompt (,|;) <list> =>
  621. ;     [sdExp] opInputPrompt(cnt,mask,<typelist>)
  622. ; If prompt is followed by a semicolon, FINP_QSupress is not ORed into
  623. ;          'mask' which causes a question mark to be appended to the prompt
  624. ;          string.
  625. ; The optional semicolon after INPUT causes FINP_CrLf not to be ORed into
  626. ;    'mask' which causes the user's terminating carriage return not to be
  627. ;    echoed.
  628. ;
  629. ;*********************************************************************
  630. PUBLIC CgInput
  631. CgInput PROC NEAR
  632. .errnz FINP_QSupress - 1
  633. .errnz FINP_CrLf - 2
  634. .errnz FINP_Prompt - 4
  635. push si ;save caller's si
  636. push di ;save caller's di
  637. sub di,di ;init bit mask
  638. mov bx,MAX_STK_MARK
  639. ;OR bit mask with to 1 for comma after prompt (MARK(1)),
  640. ;      2 for semicolon after INPUT (MARK(2)),
  641. ;      4 for prompt (MARK(4))
  642. InpMarkLoop:
  643. cmp [pCurStkMark],bx
  644. je InpMarkLoopDone
  645. dec bx
  646. dec bx
  647. mov si,[bx] ;si = oDstOpcode from mark stack
  648. dec bx
  649. dec bx
  650. cmp WORD PTR [bx],16
  651. jne NotMark16 ;brif markId != 16
  652. cmp ax,opStLineInput
  653. je InpMarkLoop ;brif not INPUT #n
  654. jmp SHORT InpExit ;If INPUT #n, pcode is already complete
  655. NotMark16:
  656. or di,[bx]
  657. DbAssertRel di,b,16,CP,<Invalid markId in CgInput>
  658. jmp SHORT InpMarkLoop
  659. ;di = bit mask (built by ORing markIds)
  660. ;ax = opcode
  661. ;
  662. InpMarkLoopDone:
  663. cmp ax,opStLineInput
  664. jne NotLineInput
  665. call Emit16_AX ;emit opcode
  666. push di ;emit bit mask
  667. call Emit16
  668. jmp SHORT InpExit
  669. ;It was INPUT, not LINE INPUT
  670. ;insert opStInputPrompt[cbOperands:16,mask:8,types:8]
  671. ;don't count string literal in cInputItems (its in cIdArgs)
  672. ;count mask in cInputItems (cancels string literal)
  673. ;di = bit mask (built by ORing markIds)
  674. ;ax = opcode
  675. ;
  676. NotLineInput:
  677. push ax ;save opcode on stack
  678. mov ax,[cIdArgs]
  679. shr ax,1 ;round down to word count
  680. mov cx,ax ;cx = word count
  681. mov bx,si ;bx = oDstOpcode (place to insert ops)
  682. jcxz InpLoopDone
  683. ;emit garbage typelist (scanner will fill in)
  684. InpLoop:
  685. push cx ;save word count
  686. call InsertOp ;insert word AX at offset BX
  687. ;any value in ax would do, scanner fills
  688. ; (bx is preserved)
  689. pop cx ;restore word count
  690. loop InpLoop
  691. ;now emit mask and space for 1st entry in type list
  692. InpLoopDone:
  693. mov ax,di
  694. and al,7 ;mask off bits > 7
  695. call InsertOp ;insert word AX at offset BX
  696. ; (bx is preserved)
  697. mov ax,[cIdArgs]
  698. inc ax
  699. call InsertOp ;insert word AX at offset BX
  700. ; (bx is preserved)
  701. pop ax ;ax = opcode (pushed ~25 lines above)
  702. call InsertOp ;insert word AX at offset BX
  703. InpExit:
  704. pop di ;save caller's di
  705. pop si ;save caller's si
  706. ret
  707. CgInput ENDP
  708. ;*********************************************************************
  709. ; CgStmtCnt(opcode)
  710. ; Purpose:
  711. ; Called for statements like CLEAR, CLOSE, COLOR, ERASE, FIELD, LOCATE
  712. ; and SCREEN, which take as an operand the number of arguments
  713. ; preceding them.
  714. ;
  715. ;*********************************************************************
  716. PUBLIC CgStmtCnt
  717. CgStmtCnt PROC NEAR
  718. call Emit16_AX ;emit the opcode
  719. mov ax,[cIdArgs]
  720. jmp Emit16_AX ;emit the arg count
  721. ;and return to caller
  722. CgStmtCnt ENDP
  723. ;*********************************************************************
  724. ; CgCntHigh(opcode)
  725. ;
  726. ; Purpose:
  727. ;
  728. ;   Called for the Format$ function.
  729. ;
  730. ;*********************************************************************
  731. ;Added with [11]
  732. ;End of [11]
  733. ;*********************************************************************
  734. ; CgLineStmt(opcode)
  735. ;
  736. ; Purpose:
  737. ; Invoked to generate code for the following bnf:
  738. ;    tkLINE [coordStep] tkMinus coord2Step
  739. ; [tkComma [Exp MARK(1)]
  740. ;   [tkComma [(RwBF MARK(3)) | (RwB (RwF MARK(3)) | MARK(2))]
  741. ;     [tkComma Exp MARK(4)]]]
  742. ; <CgLineStmt(opStLine)>
  743. ;
  744. ;*********************************************************************
  745. PUBLIC CgLineStmt
  746. CgLineStmt PROC NEAR
  747. push si ;save caller's si
  748. sub dx,dx ;operand = 0
  749. mov cx,ax ;cx = opcode
  750. mov si,[pCurStkMark]
  751. LineLoop:
  752. cmp si,MAX_STK_MARK
  753. je LineLoopDone
  754. lodsw ;ax = markId
  755. inc si ;skip oDstPcode
  756. inc si
  757. dec ax
  758. je LineMark1 ;brif MARK(1)
  759. dec ax
  760. je LineMark2 ;brif MARK(2)
  761. dec ax
  762. je LineMark3 ;brif MARK(3)
  763. ;MARK(4) means line style parm was specified
  764. inc cx ;convert opStLine, opStLineColor->
  765. ; opStLineStyle, opStLineColorStyle
  766. ;fall into case 1
  767. ;MARK(1) means color parm was specified
  768. LineMark1:
  769. inc cx ;convert opStLine to opStLineColor
  770. jmp SHORT LineLoop
  771. ;MARK(2) means B parm was specified
  772. LineMark2:
  773. mov dl,1 ;operand = 1
  774. jmp SHORT LineLoop
  775. LineMark3:
  776. ;MARK(3) means BF parm was specified
  777. mov dl,2 ;operand = 2
  778. jmp SHORT LineLoop
  779. LineLoopDone:
  780. push dx ;pass operand to Emit16 below
  781. xchg ax,cx ;ax=opcode for Emit16_AX
  782. call Emit16_AX ;emit the opcode
  783. call Emit16 ;emit the operand
  784. pop si ;restore caller's si
  785. ret
  786. CgLineStmt ENDP
  787. ;*********************************************************************
  788. ; CgOpen(opcode)
  789. ;
  790. ; Purpose:
  791. ; Invoked to generate code for the following bnf:
  792. ;  tkOPEN Exp
  793. ;   ([(tkFOR ((tkAPPEND  MARK(1)) |
  794. ;             (tkINPUT   MARK(2)) | 
  795. ;             (tkOUTPUT  MARK(3)) |
  796. ;             (tkRANDOM  MARK(4)) |
  797. ;             (tkBINARY  MARK(5))))]
  798. ;    [tkACCESS ((tkREAD  MARK(6) [tkWRITE MARK(8)]) | (tkWRITE MARK(7)))]
  799. ;    [(tkLOCK ((tkREAD ((tkWRITE MARK(11)) | MARK(9))) |
  800. ;              (tkWRITE MARK(10)))) |
  801. ;     (tkSHARED MARK(12))]
  802. ;    tkAS optFilenum [tkLEN tkEQ Exp MARK(13)])  |
  803. ;   (tkComma optFilenum exp12 MARK(14))
  804. ;     <CgOpen(opStOpen2)>
  805. ;
  806. ;*********************************************************************
  807. tModeMask LABEL WORD
  808. DW MD_APP ; MARK(1) means APPEND was specified
  809. DW MD_SQI ; MARK(2) means INPUT was specified
  810. DW MD_SQO ; MARK(3) means OUTPUT was specified
  811. DW MD_RND ; MARK(4) means RANDOM (or default) was speced
  812. DW MD_BIN ; MARK(5) means BINARY was specified
  813. DW ACCESS_READ * 256 ; MARK(6) means READ was specified
  814. DW ACCESS_WRITE * 256 ; MARK(7) means WRITE was specified
  815. DW ACCESS_BOTH * 256 ; MARK(8) means READ WRITE was specified
  816. DW LOCK_READ * 256 ; MARK(9) means LOCK READ was specified
  817. DW LOCK_WRITE * 256 ; MARK(10) means LOCK WRITE was specified
  818. DW LOCK_BOTH * 256 ; MARK(11) means LOCK READ WRITE was specified
  819. DW LOCK_SHARED * 256 ; MARK(12) means SHARED was specified
  820. PUBLIC CgOpen
  821. CgOpen PROC NEAR
  822. push si ;save caller's si
  823. mov cx,ax ;cx = opcode
  824. sub dx,dx ;mode = 0
  825. mov si,[pCurStkMark]
  826. OpenLoop:
  827. cmp si,MAX_STK_MARK
  828. je OpenLoopDone
  829. lodsw ;ax = markId
  830. inc si ;skip pcode offset
  831. inc si
  832. cmp al,14
  833. je OpenMark14
  834. cmp al,13
  835. je OpenMark13
  836. ;mode |= tModeMask[markId - 1]
  837. xchg bx,ax ;bx = markId
  838. shl bx,1 ;convert to word index
  839. mov ax,tModeMask - 2[bx] ;ax = mask
  840. or dx,ax ;or mask into mode
  841. jmp SHORT OpenLoop
  842. ;MARK(13) means LEN=nnn was specified
  843. OpenMark13:
  844. inc cx ;convert opStOpen2 to opStOpen3
  845. jmp SHORT OpenLoop
  846. OpenLoopDone:
  847. push dx ;save mode
  848. xchg ax,cx ;emit opcode
  849. call Emit16_AX
  850. pop ax ;ax = open mode
  851. test al,MD_APP OR MD_SQI OR MD_SQO OR MD_RND OR MD_BIN
  852. jne OpenEmitExit ;brif open mode was specified
  853. or al,MD_DEFAULT ;default open mode
  854. OpenEmitExit:
  855. call Emit16_AX ;emit open mode
  856. pop si ;restore caller's si
  857. ret
  858. ;MARK(14) means old open syntax
  859. OpenMark14:
  860. mov ax,[cIdArgs]
  861. add ax,opStOpenOld3 - 3 ;ax = old open opcode
  862. jmp SHORT OpenEmitExit
  863. CgOpen ENDP
  864. ;*********************************************************************
  865. ; CgLock(opcode)
  866. ;
  867. ; Purpose:
  868. ; Invoked to generate code for the following bnf:
  869. ; tkLOCK optFileNum
  870. ;  (tkComma (Exp MARK(1) [tkTO MARK(2) Exp]) | (tkTO MARK(3) Exp]))
  871. ;    <CgLock(opStLock)>
  872. ; tkUNLOCK optFileNum
  873. ;  (tkComma (Exp MARK(1) [tkTO MARK(2) Exp]) | (tkTO MARK(3) Exp]))
  874. ;    <CgLock(opStLock)>
  875. ;
  876. ;*********************************************************************
  877. PUBLIC CgLock
  878. CgLock PROC NEAR
  879. push si ;save caller's si
  880. push di ;save caller's di
  881. mov di,ax ;di = opcode
  882. sub dx,dx ;mode = markId = 0
  883. cmp ax,opStUnLock
  884. jne NotUnlock
  885. mov dl,LOCK_UNLOCK ;mode = LOCK_UNLOCK
  886. NotUnlock:
  887. mov si,[pCurStkMark]
  888. LockLoop:
  889. cmp si,MAX_STK_MARK
  890. je LockLoopDone ;brif done with MARK directives
  891. lodsw ;al = markId
  892. xchg cx,ax ;cl = markId
  893. lodsw ;ax = oDstOpcode
  894. cmp cl,1
  895. jne NotMark1 ;brif not MARK(1)
  896. test dl,LOCK_1stToLast
  897. jne NotMark1 ;brif MARK(2) was seen
  898. or dh,LOCK_DefLastArg/256 ;tell executor to default last record
  899. NotMark1:
  900. cmp cl,3
  901. jne NotMark3 ;brif not MARK(3)
  902. xchg bx,ax ;bx = oDstOpcode
  903. ;Emit default 1st record before the 2nd Exp
  904. push dx ;save dx
  905. .erre opLitI2Max GE 1  ; Assure 1 is allowed
  906. mov ax,opLitI2+OPCODE_MASK+1; pass opLitI2 with value of 1
  907. call InsertOp ;insert word AX at offset BX
  908. ; (bx is preserved)
  909. pop dx ;restore dx = mode & markId
  910. or dh,LOCK_Def1stArg/256 ;tell lister to default 1st record
  911. NotMark3:
  912. or dl,LOCK_1stToLast
  913. jmp SHORT LockLoop
  914. LockLoopDone:
  915. push dx ;pass mode to 2nd call of Emit16
  916. xchg ax,di ;pass opcode to Emit16_AX
  917. call Emit16_AX ;emit the opcode
  918. call Emit16 ;emit the mode operand
  919. pop di ;restore caller's di
  920. pop si ;restore caller's si
  921. ret
  922. CgLock ENDP
  923. PUBLIC Cg0or1Args, Cg1or2Args, Cg2or3Args, Cg3or4Args
  924. Cg3or4Args PROC NEAR
  925. dec ax
  926. Cg3or4Args ENDP ;fall into Cg2or3Args
  927. Cg2or3Args PROC NEAR
  928. dec ax
  929. Cg2or3Args ENDP ;fall into Cg1or2Args
  930. Cg1or2Args PROC NEAR
  931. dec ax
  932. Cg1or2Args ENDP ;fall into Cg0or1Args
  933. Cg0or1Args PROC NEAR
  934. mov dx,ax ;save base opcode in dx
  935. add ax,[cIdArgs] ;ax = opcode + cIdArgs
  936. cmp dx,opStMid_2 - 3
  937. je CgMoveOpsToEnd ;brif MID$ statement
  938. J1_Emit16_AX:
  939. jmp Emit16_AX ;emit ax and return to caller
  940. Cg0or1Args ENDP
  941. ;*********************************************************************
  942. ; CgMoveOpsToEnd(opcode)
  943. ;
  944. ; Purpose:
  945. ; Invoked to generate code for the following bnf:
  946. ;   tkLSET MARK(1) idAryElemRef MARK(2) tkEQ Exp
  947. ;     CgMoveOpsToEnd(opStLset)
  948. ;   tkRSET MARK(1) idAryElemRef MARK(2) tkEQ Exp
  949. ;     CgMoveOpsToEnd(opStRset)
  950. ;   tkMID_ tkLParen MARK(1) idAryElemRef MARK(2) exp12 tkRParen tkEQ Exp
  951. ;     Cg3or4Args(opStMid_2)
  952. ; Moves the pcode for idAryElemRef to the end of the buffer
  953. ;
  954. ;*********************************************************************
  955. cProc CgMoveOpsToEnd,<PUBLIC,NEAR,NODATA>,<si,di>
  956. cBegin
  957. push ax ;pass opcode to Emit16 (at end of proc)
  958. mov si,[pCurStkMark]
  959. lodsw ;al = markId (2)
  960. lodsw ;ax = text offset for MARK(2)
  961. xchg di,ax ;bx = text offset for MARK(2)
  962. lodsw ;al = markId (1)
  963. lodsw ;ax = text offset for MARK(1)
  964. xchg si,ax ;si = text offset for MARK(1)
  965. ;setup for BdShiftLeft((bd *)&ps.bdpDst, oDstCur, cbMoved)
  966. PUSHI ax,<dataOFFSET ps.PS_bdpDst>
  967. push si
  968. mov ax,di
  969. sub ax,si
  970. push ax ;pass cbMoved
  971. ;call to BdShiftLeft is after loop
  972. MoveLoop:
  973. cmp si,di
  974. je MoveDone
  975. add si,[ps.PS_bdpDst.BDP_pb] ;si = ptr to next word to be moved
  976. lodsw ;ax = next word to be moved
  977. sub si,[ps.PS_bdpDst.BDP_pb] ;si = offset to next word to be moved
  978. call Emit16_AX ;copy word to end of buffer
  979. jmp SHORT MoveLoop
  980. MoveDone:
  981. ;delete the source of copied words - parms pushed several lines above
  982. call BdShiftLeft ;grow buf, can cause heap movement
  983. call SetDstPbCur ;update ps.bdpDst.pbCur for BdShiftLeft
  984. ;emit opcode - parm pushed several lines above
  985. call Emit16
  986. cEnd
  987. PUBLIC CgCircle
  988. CgCircle PROC NEAR
  989. mov dx,MAX_STK_MARK
  990. cmp [pCurStkMark],dx
  991. je NoCircleMark
  992. inc ax ;got a MARK(1), color parm included
  993. ;map opStCircle to opStCircleColor
  994. NoCircleMark:
  995. jmp Emit16_AX ;emit ax and return to caller
  996. CgCircle ENDP
  997. sEnd CP
  998. end