用于在 Gforth 中创建新字典条目+其他操作的语法糖

问题描述 投票:0回答:1

我是一名 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

或者,换句话说:

  • “->”解析以下两个名称
  • 对于名字,为 2 变量结构创建一个字典条目“vehicle”,如果它尚不存在,则会为其分配一个字符串
  • 为第二个名称创建另一个条目“汽车”<" (note the <), if it doesn't already exists, also a 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 gforth
1个回答
4
投票

一些建议

  1. 从纯后缀解决方案开始自顶向下分解。
  2. 找到某种理想概念性顶级后缀解决方案的实现。
  3. 实现 Forth 系统中缺少的单词和/或级别。

注意:这不是一般规则,而是问题中代码的一些弱点。

以下是一个常见规则。 在管道部分,只能使用后缀语法。前缀语法(解析单词)只能作为顶层的糖出现。 IE。任何解析词都应该有后缀变体。

给定问题的通用后缀解决方案是:

s" content" s" name" update-var

解决方案

\ reference implementations of some underlying words for testing purpose only
: s, ( sd.data -- ) here swap dup allot move ;
: s+ ( sd1 sd2 -- sd3 ) here >r 2swap s, s, r> here over - 0 c, ;
: s+! ( sd addr -- ) dup >r 2@ 2swap s+ r> 2! ; \ '+!' naming convention 
: gs+ ( sd1 -- sd2 ) s"  " s+ ; \ add gap string ('space+' is too long)
\ some Forth-systems have these words as factors:
: created ( sd.name -- ) s" create " 2swap s+ evaluate ;
: obey ( i*x sd.name wid -- j*x true | i*x sd.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 ( sd.name -- addr )
  get-current >r v set-current
  created here 0 , 0 ,
  r> set-current
;
: obtain-var ( sd.name -- addr )
  v obey if exit then  make-var
;
: update-var ( sd.content sd.name -- )
  obtain-var s+!
;
: -> \ "vehicles" "cars"
  parse-name parse-name
  2over gs+ 2over s" <" s+ update-var
  gs+ 2swap update-var
;

数据类型符号

sd
代表代表字符串的
( c-addr u )
单元对。

s,
( sd -- ) 将给定字符串按原样存储到数据空间中(另请参见
,
c,
);注意:在 Gforth 中,同名单词以计数字符串格式存储字符串(请参阅 3.1.3.4 计数字符串)。

created
create
的后缀变体(在设计良好的系统中,后者应通过前者定义);对于词源,另请参阅标准词
included
(后缀形式)和
include
(前缀形式,解析词)。

最好为这些自动创建的变量使用单独的单词列表,以避免可能出现的名称冲突问题(例如,如果您需要

-> here str
怎么办)。请参阅修订版 8中没有单独单词列表的变体。

为了编写测试用例,还可以使用著名的 tester.fs 库(在 Gforth 中,它位于

test/
目录中)。在这个库中,
->
这个词是为了它自己的目的而定义的,所以同义词可以用来克服不需要的阴影。

© www.soinside.com 2019 - 2024. All rights reserved.