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

时间:2018-01-27 12:02:00

标签: forth gforth

我是一个新手,试图开发一些(伪有用的)玩具来学习这门语言。我想强制执行以下操作:

[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

或者换句话说:

  • &#34; - &GT;&#34;解析以下两个名称
  • 为名字创建一个字典条目&#34; vehicle&#34;对于2变量之类的结构,如果它不存在,则会为其分配一个字符串
  • 为第二个名称创建另一个条目&#34; cars&lt;&#34; (注意&lt;),如果它不存在,也是2变量
  • 然后添加(而不是替换)字符串&#34; cars&#34;变辆车
  • 并添加字符串&#34; vehicles&#34;改变汽车&lt;

我使用字符串操作和评估来实现这种行为......

: 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! )

我认为存在另一种更直接,更优雅的方式,但这是我现在能做的最好的方法。有什么建议吗?

1 个答案:

答案 0 :(得分:3)

一些建议

  1. 从纯后缀解决方案开始自上而下分解。
  2. 找到顶级后缀解决方案的某种理想 概念实现。
  3. 实施您的Forth系统缺席的单词和级别。
  4. 注意:这不是一般规则,而是问题代码中的一些弱点。

    以下是一条常见规则。 在管道部分中,应该仅使用后缀语法。前缀语法(解析单词)可以仅作为顶级的糖发生。即任何解析词都应该有一个后缀变种。

    针对给定问题的一般后缀解决方案是: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 - )将给定字符串按原样存储到数据空间中(另请参阅,c,);注意:在Gforth中,它以计数字符串格式存储(参见3.1.3.4 Counted strings)。

    createdcreate的后缀变体(在适当的系统中,最后一个应该通过第一个定义);关于词源,请参阅标准词included(后缀形式)和include(前缀形式,解析词)。

    最好为这些自动创建的变量使用单独的词表,以避免冲突名称上可能出现的问题(例如,如果需要-> here str)。请参阅revision 8中没有单独的词表的变体。

    要编写测试用例,还可以使用众所周知的ttester.fs库(在Gforth中,它位于./test/目录中)。在此库->中,单词是为了自己的目的而定义的,因此可以使用同义词来克服不需要的阴影。