Rebol[
Title: "Parseen"
Date: 18-Mar-2007/9:57:05+1:00
History: [
26/Apr/2003/11:30 "working version"
21/Dec/2004/13:40 "thru-rule added"
22/Dec/2004/8:05 "lit added"
18-Mar-2007/1:45:14+1:00 "do-block corrected"
18-Mar-2007/9:57:05+1:00 "dialect upgraded"
]
File: %parseen.r
Author: "Ladislav Mecir"
Purpose: {Parse enhancements}
Category: [Advanced]
]
#include-check %build.r
alpha: charset [#"a" - #"z" #"A" - #"Z" #"_"]
digit: charset [#"0" - #"9"]
nondigit: complement digit
alnum: union alpha digit
nonalnum: complement alnum
ws: charset [#" " #"^-" #"^/" #"^M" #"^(page)"]
nonws: complement ws
; a rule that always fails, opposite to none
fail: [end skip]
comment [
; Example # 1
parseen "ab" [not [any "a" "b"]]
parseen "b" [not [any "a" "b"]]
parseen "" [not [any "a" "b"]]
; Example # 2
parseen "ab" [not ["aa"] any "a" "b"]
parseen "aab" [not ["aa"] any "a" "b"]
; Example # 3
parseen [1] [any [not [lit [1]] skip]]
parseen [2] [any [not [lit [1]] skip]]
; Example # 4
parseen [1 a] [not [integer!] to end]
parseen [a 1] [not [integer!] to end]
; Example # 5
parseen [a b c 1 d] [any [not [integer!] skip]]
parseen [a b c d e] [any [not [integer!] skip]]
; Example # 6
result: ""
parseen/all "aa" [to [" " | "
"] result: to end]
probe result
parseen/all "a a
" [to [" " | "
"] result: to end]
probe result
parseen/all "ab
" [to [" " | "
"] result: to end]
probe result
; Example # 7
four-digit: [4 digit]
parseen/all "abcd 1234" [to [four-digit] copy fd four-digit to end]
probe fd
; Example # 8
pm: charset "+-"
parseen "assdasasasa+" [copy t thru [pm]]
probe t
; Example # 9
parseen ['ahoj] [lit 'ahoj]
parseen [ahoj] [lit 'ahoj]
]
use [
enblk
rule
rules
single-rule
rule-block
rule-result
a1 a2
r1 r2
stack
push
pop
] [
enblk: func [
value [any-type!]
] [
either block? get/any 'value [:value] [
head insert/only copy [] get/any 'value
]
]
rules: [
(
push [rule-block]
rule-block: copy []
)
any [end break | rule (insert tail rule-block rule-result)]
(
rule-result: rule-block
pop [rule-block]
)
]
rule: [
(push [single-rule a1 a2 a3])
[
; repetition-like, "enhanced"
'to a1: block! :a1 into rules (
single-rule: build [
any [
[
only rule-result (r1: fail r2: none) |
(r1: none r2: fail) skip
]
r1
]
r2
]
) |
'thru a1: block! :a1 into rules (
single-rule: build [
any [only rule-result (r1: none) break | (r1: fail) skip] r1
]
) |
; their "original versions"
copy single-rule ['to opt skip | 'thru opt skip] |
; set
copy single-rule ['set word!] rule (
insert/only tail single-rule rule-result
) |
; copy
copy single-rule ['copy word!] rule (
insert/only tail single-rule rule-result
) |
; repetition-like, "normal"
[
copy single-rule 1 2 integer! |
copy single-rule 'opt |
copy single-rule 'some |
copy single-rule 'any |
copy single-rule 'into |
(single-rule: copy [])
]
[
a1: block! :a1 into rules (
insert/only tail single-rule rule-result
) |
'lit end | ; invalid LIT use, ignored
'lit
[
set a1 block! |
set a1 paren! (a1: enblk do a1) |
copy a1 skip
]
(
insert/only tail single-rule build [
copy r1 ins length? a1 skip (
r1: unless r1 = only a1 [fail]
)
r1
]
) |
'not end | ; invalid NOT use, ignored
'not rule (
insert/only tail single-rule build [
[only rule-result (r1: fail) | (r1: none)] r1
]
) |
'at end | ; invalid AT use, ignored
'at rule (
insert/only tail single-rule build [
[only rule-result (r1: none) | (r1: fail)] fail | r1
]
) |
'either
rule (a1: rule-result)
rule (a2: rule-result)
rule (
insert/only tail single-rule build [
[only a1 (r1: only a2) | (r1: only rule-result)] r1
]
) |
'check set a1 paren! (
insert/only tail single-rule build [
(r1: unless do only a1 [fail]) r1
]
) |
'check | ; invalid CHECK use, ignored
'use block! end | ; invalid USE use, ignored
'use set a1 block! rule (
insert/only tail single-rule build [
(push only a1) only rule-result (pop only a1)
]
) |
'use | ; invalid USE use, ignored
copy a1 skip (insert tail single-rule a1) |
none
]
]
(
rule-result: single-rule
pop [single-rule a1 a2 a3]
)
]
stack: copy []
push: func [block [block!]] [
foreach variable block [insert/only tail stack get/any variable]
]
pop: func [block [block!]] [
set/any block stack: skip tail stack negate length? block
clear stack
]
compile: func [
{compile an enhanced PARSE rule}
[catch]
rule-to-compile [block!]
] [
parse rule-to-compile rules
return rule-result
]
]
parseen: func [
"Parses a series according to rules."
input [series!] "Input series to parse"
rules [block! string! none!] "Rules to parse by"
/all "Parses all chars including spaces."
/case "Uses case-sensitive comparison."
/local call
] [
call: copy [parse]
if all [insert tail call 'all]
if case [insert tail call 'case]
call: reduce [to path! call :input compile rules]
do call
]