用于在 Gforth 中创建新字典条目的语法糖 + 其他操作
Syntactic sugar for making new dictionary entries + other operations in Gforth
我是Forth新手,正在尝试开发一些(伪有用的)玩具来学习语言。我想压缩以下操作:
[ifundef] vehicles 2variable vehicles [then]
[ifundef] cars< 2variable cars< [then]
vehicles 2@ s" cars " s+ vehicles 2!
cars< 2@ s" vehicles" s+ cars< 2!
通过以下(更紧凑)指令
-> vehicles cars
或者,换句话说:
- "->"解析后面两个名字
- 为名字创建一个字典条目"vehicle"为类似结构的 2 变量,如果它不存在,将为其分配一个字符串
- 为第二个名字创建另一个条目 "cars<"(注意 <),如果它不存在,还有一个 2variable
- 然后将字符串 "cars" 添加(而不是替换)到变量 vehicle
- 并将字符串 "vehicles" 添加到变量 cars<
我使用字符串操作和评估进行了破解以获取此行为...
: space+ ( str -- ) s" " s+ ;
\ use like: cars add alfa-romeo (first is a 2variable name, second a parsed name)
: add ( a "name" -- ) dup >r 2@ parse-name space+ s+ r> 2! ;
create _x 256 chars allot align
: _x@ ( -- ) _x count ;
: _x! ( -- ) _x place ;
create _y 256 chars allot align
: _y@ ( -- ) _y count ;
: _y! ( -- ) _y place ;
: init_x ( str -- ) 2dup s" [ifundef] " 2swap s+ s" 2variable " s+ 2swap s+ s" [then]" s+ evaluate ;
: init_y ( str -- ) 2dup s" [ifundef] " 2swap s+ s" < 2variable " s+ 2swap s" <" s+ s+ s" [then]" s+ evaluate ;
: make-dictionary-entries ( -- ) _x@ init_x _y@ init_y ;
: add-strings-to-entries ( -- ) _x@ s" add " s+ _y@ s+ evaluate
_y@ s" < add " s+ _x@ s+ evaluate ;
: -> parse-name _x! parse-name _y!
make-dictionary-entries
add-strings-to-entries ;
\ CUSTOM TESTING to improve readability of the examples
: test( POSTPONE assert( ; immediate
: true! 0= throw ;
: false! throw ;
: same-string! str= true! ;
-> vehicles cars
test( vehicles 2@ s" cars " same-string! )
test( cars< 2@ s" vehicles " same-string! )
-> vehicles trucks
-> vehicles dreams
test( vehicles 2@ s" cars trucks dreams " same-string! )
test( trucks< 2@ s" vehicles " same-string! )
-> cars ferrari
-> cars lamborghini
-> dreams lamborghini
test( cars 2@ s" ferrari lamborghini " same-string! )
test( lamborghini< 2@ s" cars dreams " same-string! )
我认为存在另一种更直接、更优雅的方式,但这是我目前能做的最好的方式。有什么建议吗?
一些建议
- 从纯后缀解决方案开始自顶向下分解。
- 找到某种理想 概念 顶级后缀解决方案的实现。
- 实施您的 Forth 系统中缺少的单词和/或级别。
注意:这不是一般规则,而是问题中代码中的一些弱点。
下面是一个常见的规则。
在管道部分,应仅使用后缀语法。前缀语法(解析词)可能仅作为糖出现在顶层。 IE。任何解析词都应该有一个后缀变体。
给定问题的一般后缀解决方案是:S" content" S" name" update-var
解决方案
\ reference implementations of some underlying words for testing purpose only
: s, ( d-txt -- ) here swap dup allot move ;
: s+ ( d-txt1 d-txt2 -- d-txt3 ) here >r 2swap s, s, r> here over - 0 c, ;
: s+! ( d-txt addr -- ) dup >r 2@ 2swap s+ r> 2! ; \ '+!' naming convention
: gs+ ( d-txt1 -- d-txt2 ) s" " s+ ; \ add gap string ('space+' is too long)
\ some Forth-systems have these words as factors:
: created ( d-txt-name -- ) s" create " 2swap s+ evaluate ;
: obey ( i*x d-txt-name wid -- j*x true | i*x d-txt-name false )
>r 2dup r> search-wordlist if nip nip execute true exit then false
;
\ the solution itself
wordlist constant v \ for special auto-created variables
: make-var ( d-txt-name -- addr )
get-current >r v set-current
created here 0 , 0 ,
r> set-current
;
: obtain-var ( d-txt-name -- addr )
v obey if exit then make-var
;
: update-var ( d-txt-content d-txt-name -- )
obtain-var s+!
;
: -> \ "vehicles" "cars"
parse-name parse-name
2over gs+ 2over s" <" s+ update-var
gs+ 2swap update-var
;
d-
前缀在堆栈符号中表示两个单元值,d-txt-
前缀表示字符串(单元对)。
s,
( d-txt -- ) 将给定的字符串按原样存储到数据 space 中(另请参阅 ,
and c,
); NB: in Gforth it stores in counted string format (see 3.1.3.4 Counted strings)。
created
是create
(in a proper system the last should be defined via the first); regarding etymology see also the standard words included
(postfix form) and include
的后缀变体(前缀形式,解析词)。
此外,最好为这些自动创建的变量使用单独的词表,以避免可能出现的名称冲突问题(例如,如果您需要 -> here str
怎么办)。在 revision 8.
中查看没有单独单词列表的变体
要编写测试用例,也可以使用众所周知的 ttester.fs 库(在 Gforth 中,它位于 ./test/ 目录中)。在这个库中 ->
词是为它自己的目的而定义的,所以同义词可以用来克服不需要的阴影。
我是Forth新手,正在尝试开发一些(伪有用的)玩具来学习语言。我想压缩以下操作:
[ifundef] vehicles 2variable vehicles [then]
[ifundef] cars< 2variable cars< [then]
vehicles 2@ s" cars " s+ vehicles 2!
cars< 2@ s" vehicles" s+ cars< 2!
通过以下(更紧凑)指令
-> vehicles cars
或者,换句话说:
- "->"解析后面两个名字
- 为名字创建一个字典条目"vehicle"为类似结构的 2 变量,如果它不存在,将为其分配一个字符串
- 为第二个名字创建另一个条目 "cars<"(注意 <),如果它不存在,还有一个 2variable
- 然后将字符串 "cars" 添加(而不是替换)到变量 vehicle
- 并将字符串 "vehicles" 添加到变量 cars<
我使用字符串操作和评估进行了破解以获取此行为...
: space+ ( str -- ) s" " s+ ;
\ use like: cars add alfa-romeo (first is a 2variable name, second a parsed name)
: add ( a "name" -- ) dup >r 2@ parse-name space+ s+ r> 2! ;
create _x 256 chars allot align
: _x@ ( -- ) _x count ;
: _x! ( -- ) _x place ;
create _y 256 chars allot align
: _y@ ( -- ) _y count ;
: _y! ( -- ) _y place ;
: init_x ( str -- ) 2dup s" [ifundef] " 2swap s+ s" 2variable " s+ 2swap s+ s" [then]" s+ evaluate ;
: init_y ( str -- ) 2dup s" [ifundef] " 2swap s+ s" < 2variable " s+ 2swap s" <" s+ s+ s" [then]" s+ evaluate ;
: make-dictionary-entries ( -- ) _x@ init_x _y@ init_y ;
: add-strings-to-entries ( -- ) _x@ s" add " s+ _y@ s+ evaluate
_y@ s" < add " s+ _x@ s+ evaluate ;
: -> parse-name _x! parse-name _y!
make-dictionary-entries
add-strings-to-entries ;
\ CUSTOM TESTING to improve readability of the examples
: test( POSTPONE assert( ; immediate
: true! 0= throw ;
: false! throw ;
: same-string! str= true! ;
-> vehicles cars
test( vehicles 2@ s" cars " same-string! )
test( cars< 2@ s" vehicles " same-string! )
-> vehicles trucks
-> vehicles dreams
test( vehicles 2@ s" cars trucks dreams " same-string! )
test( trucks< 2@ s" vehicles " same-string! )
-> cars ferrari
-> cars lamborghini
-> dreams lamborghini
test( cars 2@ s" ferrari lamborghini " same-string! )
test( lamborghini< 2@ s" cars dreams " same-string! )
我认为存在另一种更直接、更优雅的方式,但这是我目前能做的最好的方式。有什么建议吗?
一些建议
- 从纯后缀解决方案开始自顶向下分解。
- 找到某种理想 概念 顶级后缀解决方案的实现。
- 实施您的 Forth 系统中缺少的单词和/或级别。
注意:这不是一般规则,而是问题中代码中的一些弱点。
下面是一个常见的规则。 在管道部分,应仅使用后缀语法。前缀语法(解析词)可能仅作为糖出现在顶层。 IE。任何解析词都应该有一个后缀变体。
给定问题的一般后缀解决方案是:S" content" S" name" update-var
解决方案
\ reference implementations of some underlying words for testing purpose only
: s, ( d-txt -- ) here swap dup allot move ;
: s+ ( d-txt1 d-txt2 -- d-txt3 ) here >r 2swap s, s, r> here over - 0 c, ;
: s+! ( d-txt addr -- ) dup >r 2@ 2swap s+ r> 2! ; \ '+!' naming convention
: gs+ ( d-txt1 -- d-txt2 ) s" " s+ ; \ add gap string ('space+' is too long)
\ some Forth-systems have these words as factors:
: created ( d-txt-name -- ) s" create " 2swap s+ evaluate ;
: obey ( i*x d-txt-name wid -- j*x true | i*x d-txt-name false )
>r 2dup r> search-wordlist if nip nip execute true exit then false
;
\ the solution itself
wordlist constant v \ for special auto-created variables
: make-var ( d-txt-name -- addr )
get-current >r v set-current
created here 0 , 0 ,
r> set-current
;
: obtain-var ( d-txt-name -- addr )
v obey if exit then make-var
;
: update-var ( d-txt-content d-txt-name -- )
obtain-var s+!
;
: -> \ "vehicles" "cars"
parse-name parse-name
2over gs+ 2over s" <" s+ update-var
gs+ 2swap update-var
;
d-
前缀在堆栈符号中表示两个单元值,d-txt-
前缀表示字符串(单元对)。
s,
( d-txt -- ) 将给定的字符串按原样存储到数据 space 中(另请参阅 ,
and c,
); NB: in Gforth it stores in counted string format (see 3.1.3.4 Counted strings)。
created
是create
(in a proper system the last should be defined via the first); regarding etymology see also the standard words included
(postfix form) and include
的后缀变体(前缀形式,解析词)。
此外,最好为这些自动创建的变量使用单独的词表,以避免可能出现的名称冲突问题(例如,如果您需要 -> here str
怎么办)。在 revision 8.
要编写测试用例,也可以使用众所周知的 ttester.fs 库(在 Gforth 中,它位于 ./test/ 目录中)。在这个库中 ->
词是为它自己的目的而定义的,所以同义词可以用来克服不需要的阴影。