1 ;; Native x86 GNU/Linux Forth System, Direct Threaded Code
3 ;; Copyright (C) 2020 Ketmar Dark // Invisible Vector
5 ;; This program is free software: you can redistribute it and/or modify
6 ;; it under the terms of the GNU General Public License as published by
7 ;; the Free Software Foundation, version 3 of the License ONLY.
9 ;; This program is distributed in the hope that it will be useful,
10 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ;; GNU General Public License for more details.
14 ;; You should have received a copy of the GNU General Public License
15 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
17 ;; if set to true (non-zero), "PARSE-NAME" will understand comments without space delimiters
18 ;; (except a lone banana)
19 urword_value
"PARSE-NAME-ADV-COMMENTS",parse_name_adv_comments
,1
22 ;DIGIT ( c n1 -- n2 tf ok)
24 ;Converts the ascii character c (using base n1) to its binary equivalent
25 ;n2, accompanied by a true flag. If the conversion is invalid, leaves
27 urword_code
"DIGIT",digit
63 urword_forth
"DIGIT?",digitq
64 ;; ( ch base -- flag )
72 ;; convert the ASCII text beginning at addr with regard to BASE.
73 ;; the new value is accumulated into unsigned number u0, being left as u1.
74 ;; addr1 and count1 are unparsed part of the string
75 ;; will never read more than count bytes
76 ;; doesn't skip any spaces, doesn't parse prefixes and signs
78 urword_forth
"(NUMBER-PARSE-SIMPLE)",par_number_parse_simple
79 ;; ( addr count u0 -- addr1 count1 u1 )
86 ;; first must be a digit
87 UF over cpeek base @ digitq
103 UF rpop exit
;; replace with BREAK
105 UF rpop base @ umul
+ rpush
108 UF
1dec swap
1inc swap
114 ;; k8: non-conforming, because we cannot parse double numbers
115 urword_forth
">NUMBER",in_number
116 ;; ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 )
118 UF par_number_parse_simple
123 urword_forth
"NUMBER-PARSE-PFX-SIGIL",number_parse_sigil
124 ;; ( addr count -- addr count newbase )
132 ;; ( addr count char )
133 UF dup
36 equal
;; dollar
135 UF drop swap
1inc swap
1dec
138 UF dup
35 equal
;; hash
140 UF drop swap
1inc swap
1dec
141 UF shit2012shit
1 and
149 UF
37 equal
;; percent
151 UF swap
1inc swap
1dec
157 urword_forth
"NUMBER-PARSE-PFX-0X",number_parse_0x
158 ;; ( addr count -- addr count newbase )
163 UF over cpeek
48 equal
167 UF over
1inc cpeek upcase_char
170 ;; ( addr count char )
171 UF drop swap
2inc swap
2dec
176 UF drop swap
2inc swap
2dec
181 UF drop swap
2inc swap
2dec
186 UF swap
2inc swap
2dec
192 urword_forth
"NUMBER-PARSE-PFX-&",number_parse_pfxamp
193 ;; ( addr count -- addr count newbase )
198 UF over cpeek
38 equal
202 UF over
1inc cpeek upcase_char
205 ;; ( addr count char )
206 UF drop swap
2inc swap
2dec
211 UF drop swap
2inc swap
2dec
216 UF drop swap
2inc swap
2dec
221 UF swap
2inc swap
2dec
228 urword_forth
"(NUMBER-GOOD-BIN-DIGIT?)",par_number_isbindig
238 urword_forth
"(NUMBER-PARSE-BOOL?)",number_parse_boolq
240 ;; ( addr count -- flag )
245 ;; first must be digit
246 UF over cpeek
2 digitq
254 UF i cpeek par_number_isbindig
261 urword_forth
"NUMBER-PARSE-SFX",number_parse_sfx
262 ;; ( addr count -- addr count newbase )
268 UF
2dup
+ 1dec cpeek upcase_char
279 ;; the following suffix is allowed only if all digits are right
284 UF
2dup number_parse_boolq
294 ;; will return base according to prefix/suffix, and remove pfx/sfx from the string
295 ;; returns 0 if no special base change found
296 urword_forth
"NUMBER-PARSE-PFX-SFX",number_parse_prefix_suffix
297 ;; ( addr count -- addr count newbase )
298 UF number_parse_sigil qdup
302 UF number_parse_0x qdup
306 UF number_parse_pfxamp qdup
314 urword_forth
"NUMBER",number
315 ;; ( addr count -- n true // false )
316 ; convert a character string left at addr to a signed number, using the current numeric base.
322 ;; ok, we have at least one valid char
323 ;; check for leading minus (only if 2012 so-called-standard idiocity is not turned on)
324 UF shit2012shit
1 and
328 UF over cpeek
45 equal
330 UF swap
1inc swap
1dec 1
336 ;; ( negflag addr count )
337 UF base @ rpush
;; it can be changed by number prefix/suffix
338 UF number_parse_prefix_suffix
344 ;; check for leading minus (only if 2012 so-called-standard idiocity is turned on)
345 UF shit2012shit
1 and
349 UF over cpeek
45 equal
351 UF swap
1inc swap
1dec
356 ;; zero count means "nan"
364 ;; ( negflag addr count | oldbase )
365 UF
0 par_number_parse_simple
366 ;; ( negflag addr count u | oldbase )
369 ;; ( negflag addr count u )
370 ;; if not fully parsed, it is nan
372 ;; ( negflag addr u count )
377 ;; ( negflag addr u )
387 ;; scans TIB, returns parsed word
388 ;; doesn't do any copying
389 ;; trailing delimiter is skipped
390 ;; HACK: sets (WORD-LAST-DELIMITER)
391 ;; this is so "comment-to-eol" could work
392 urword_code
"(WORD)",par_word
394 ;; ( c skip-leading-delim? -- addr count )
395 ; reset last delimiter (it will be set later)
396 mov edx,[fvar_tibsize_data
]
397 sub edx,[fvar_inptr_data
]
399 mov edi,[fvar_tib_data
]
400 add edi,[fvar_inptr_data
]
401 ; do we need to skip leading delimiters?
403 pop TOS
; get char in TOS
407 ; skip leading delimiters
423 pop TOS
; get char in TOS
426 ; remember current position
428 ; skip until delimiter
432 ; count lines here, so we won't have to call it on word completion
450 ld
[fvar_par_last_read_char_data
],eax
452 ; the word is never empty here
454 ; EDI: word end (after the last char, at a delimiter)
457 mov eax,[fvar_tibsize_data
]
459 mov [fvar_inptr_data
],eax
460 ; calc and store counter
461 pop ecx ; start address
462 mov eax,edi ; EAX=end address
463 sub eax,ecx ; EAX=length
477 add esp,4 ; drop char, as we didn't poped it yet
481 mov eax,[fvar_tibsize_data
]
485 mov [fvar_inptr_data
],eax
486 ; push current tib position, and zero length
487 add eax,[fvar_tib_data
]
492 ; zero flag: equality
496 ld
[fvar_par_last_read_char_data
],eax
498 jnc .cmp_cl_memedi_nonzero
500 .
cmp_cl_memedi_nonzero:
502 jnz .cmp_cl_memedi_ok
505 jnc .cmp_cl_memedi_ok
514 cp
dword [fvar_tiblineno_data
],0
516 inc dword [fvar_tiblineno_data
]
521 ;; this is a leftover from '"WORD" is always using real here'
522 ;urword_forth "WORD-HERE",word_here
525 urword_alias
"WORD-HERE",word_here
,here
527 urword_forth
"(WORD-OR-PARSE)",par_word_or_parse
529 ;; ( c skip-leading-delim? -- wordhere )
531 UF
1020 umin
;; truncate length
532 UF dup word_here
! ;; set counter
533 UF word_here cellinc swap move
;; copy string
534 UF word_here count
+ 0cpoke
;; put trailing zero byte
538 ;; HACK: sets (WORD-LAST-DELIMITER)
539 ;; this is so "comment-to-eol" could work
540 ;; WARNING! it is using "HERE", so "DP-TEMP" is in effect
541 ;; artificial word length limit: 1020 chars
542 ;; longer words will be properly scanned, but truncated
543 ;; adds trailing zero after the string (but doesn't include it in count)
544 ;; string is cell-counted
545 urword_forth
"WORD",word_obsolete
547 UF
1 par_word_or_parse
550 urword_forth
"PARSE-TO-HERE",parse_to_here
552 UF
0 par_word_or_parse
555 urword_forth
"PARSE",parse
556 ;; ( c -- addr count )
557 UF
0 par_word
;; parse, don't skip leading delimiters
560 urword_forth
"PARSE-SKIP-BLANKS",par_parse_skip_blanks
573 urword_forth
"PARSE-SKIP-BLANKS-NO-EOL",par_parse_skip_blanks_no_eol
582 UF dup
13 equal swap
10 equal
or
590 urword_forth
"PARSE-SKIP-BLANKS-EX",par_parse_skip_blanks_ex
591 ;; ( skipeol-flag -- )
593 UF par_parse_skip_blanks
595 UF par_parse_skip_blanks_no_eol
600 ;; simple heuristic: if the word ends with ")", try to find it in current vocabs
601 ;; as our searching is very fast, and this word is not invoked that often, it is ok
602 urword_forth
"(PARSE-GOOD-COMMENT?)",par_parse_good_commentq
603 ;; ( addr count -- addr count flag )
605 UF
2dup endcr pardottype
"CHECKING: <" type pardottype
">: "
606 UF
2dup wfind_str dup
617 ;; sorry for this huge mess
618 urword_forth
"(PARSE-NAME-EX)",par_parse_name_ex
620 ;; ( -- addr count 1 // 0 )
621 UF par_tibstate_rpush
624 ;; if word length is enough for normal comment processing, do it
627 ;; empty word, or one-char word
628 UF par_tibstate_rdrop true exit
630 ;; check for single-char backslash
631 UF over cpeek
92 equal
633 UF par_parse_good_commentq
635 UF
2drop par_tibstate_rpop
636 UF par_parse_skip_blanks
646 ;; check for double-char comments
649 UF par_tibstate_rdrop true exit
651 ;; check two chars at once
653 ;; two semicolons or two slashes
654 UF dup
0x3b3b equal over
0x2f2f equal
or
657 UF par_parse_good_commentq
659 UF
2drop par_tibstate_rpop
660 UF par_parse_skip_blanks
670 UF dup
0x2a28 equal over
0x2b28 equal
or
672 ;; UF nrot 2drop par_tibstate_rpop
673 UF nrot par_parse_good_commentq
675 UF
2drop par_tibstate_rpop
678 UF par_parse_skip_blanks
679 ;; skip two word chars
680 UF tib_getch tib_getch
2drop
685 UF comment_multiline_nested
691 UF drop par_tibstate_rdrop
695 urword_forth
"PARSE-NAME",parse_name
697 UF
bl 1 par_word
;; parse, skip leading delimiters
700 urword_forth
"PARSE-NAME-EX",parse_name_ex
702 UF parse_name_adv_comments
704 ;; save current tib, so we will be able to reparse comments