Module Stream = Begin Require 'bliss.req'; ! STREAM MANAGEMENT ROUTINES ! concatenate two streams together Global Routine stream_concat(FIRST : Ref Vector,SECOND : Ref Vector) = Begin Local POINT : Ref Vector; If .FIRST Eqla 0 Then Return .SECOND; POINT = .FIRST; Until .POINT[strm_next] Eqla 0 Do POINT = .POINT[strm_next]; POINT[strm_next] = .SECOND; Return .FIRST End; ! stack a stream Global Routine stream_push(STKADD : Ref Vector) = Begin Local SPACE : Ref Vector, LEN : Integer; LEN = SZ_STREAM(.STKADD[strm_size]); SPACE = GETSPACE(.LEN); MOVECORE(.STKADD,.SPACE,.LEN); STKADD[strm_next] = .SPACE; ! NOTE: LENGTH NOT CHANGED Return .SPACE End; ! unstack a stream Global Routine stream_pop(STKADD : Ref Vector) : Novalue = Begin Local SPACE : Ref Vector, LEN : Integer; SPACE = .STKADD[strm_next]; LEN = SZ_STREAM(.SPACE[strm_size]); MOVECORE(.SPACE,.STKADD,.LEN); RELEASESPACE(.SPACE,.LEN) End; ! DETACH A STREAM FROM ITS BASE AND RESET THE BASE TO EMPTINESS; ! REVERSE POINTERS IN THE STREAM AND RETURN THE NEW BASE AS VALUE. Global Routine stream_quit(STKADD : Ref Vector) = Begin Local CURRENT : Ref Vector, NEXT : Ref Vector, TEMP : Ref Vector; CURRENT = 0; NEXT = stream_push(.STKADD); Do Begin TEMP = .NEXT[strm_next]; NEXT[strm_next] = .CURRENT; CURRENT = .NEXT; NEXT = .TEMP End While .NEXT Neqa 0; STKADD[strm_next] = 0; STKADD[strm_size] = 0; Return .CURRENT End; ! allocate a word in a stream and return the address of that word Global Routine stream_append(STKADD : Ref Vector,Max : Integer) = Begin ! if the end of the stream is reached then stack and reset it If .STKADD[strm_size] Geq .Max - 2 Then Begin stream_push(.STKADD); STKADD[strm_size] = 1 End Else STKADD[strm_size] = .STKADD[strm_size] + 1; Return STKADD[strm_data(.STKADD[strm_size]-1)] End; ! return the address of the next word in a stream Global Routine stream_next = Begin mac_ibody = .mac_ibody+1; If .mac_ibody Gtr .mac_body[strm_size] Then Begin mac_ibody = 1; mac_body = .mac_body[strm_next] End; Return mac_body[strm_data(.mac_ibody-1)] End; ! test for end of stream Global Routine stream_test_eof = Begin If .mac_ibody Eql .mac_body[strm_size] Then Return (.mac_body[strm_next] Eqla 0) Else Return FALSE End; ! release the contents of a stream Global Routine stream_release(CURRENT : Ref Vector) : Novalue = Begin Local NEXT : Ref Vector; If .CURRENT Eqla 0 Then Return; Do Begin NEXT = .CURRENT[strm_next]; RELEASESPACE(.CURRENT,SZ_STREAM(.CURRENT[strm_size])); CURRENT = .NEXT End While .CURRENT Neqa 0 End; ! fetch the address of the next parameter Global Routine params_next = Begin mac_iarg = .mac_iarg+1; If .mac_iarg Geq SZ_ARG_BUFF Then Begin mac_iarg = 1; mac_argv = .mac_argv[strm_next] End; Return mac_argv[strm_data(.mac_iarg-1)] End; ! test for end of parameters Global Routine params_test_eof = Begin If .mac_iarg Eql .mac_argv[strm_size] Then Return (.mac_argv[strm_next] Eqla 0) Else Return FALSE End; ! store a symbol and delimiter into a stream Global Routine StoreLexeme(r : Ref Vector,n : Integer,s : Ref GT,d : Integer) : Novalue = Begin Local p : Ref GT, code, data; ! remove any wrapper around symbols If .s[gt_type] Eql T_VARIABLE Then s = .s[gt_disp]; ! get the assumed code and data code = .s[gt_type]; data = .s; ! adjust teh code and data depending on the data SelectOne .code Of Set [T_NIL]: data = 0; [T_LITERAL]: data = .s[gt_disp]; [T_STRING]: 0; [T_NAME]: 0; [T_SYMBOL]: ! change macro arguments to their index If .s[st_code] Eql S_MACRO_ARG Then Begin code = T_MACRO_ARG; data = .s[st_which] End ! change literal symbols to the literals themselves. this ! takes care of the possibility of COMPILETIME variables ! being modified between now and the use of the stream. Else If .s[st_code] Eql S_LITERAL Then Begin code = T_LITERAL; data = .s[gt_disp] End ! if tracing, only trace names, not symbols. the symbol may ! go *poof* depending on the macro. Else If .r Eqla trace_buff Then Begin code = T_NAME; data = .s[st_name] End; [Otherwise]: Punt(999) Tes; p = stream_append(.r,.n); p[lex_addr] = .data; p[lex_type] = .code; p[lex_delim] = .d End; End Eludom