实施Anyfix注释!


16

在前缀表示法中,运算符位于参数之前,因此您可以想象该运算符next()会以递归方式调用。在后缀表示法中,运算符在参数之间移动,因此您可以简单地将其想象为解析树。在后缀表示法中,运算符位于参数之后,因此您可以将其想象为基于堆栈的。

用anyfix表示法,操作员可以在任何地方*。如果操作员出现并且没有足够的参数,则操作员将等待直到有足够的参数。对于这一挑战,您将实现一个非常基本的anyfix评估程序。(请注意,anyfix是我放弃的一种娱乐语言,您可以在此处试用或在此处查看

您将需要支持以下命令:

(Arity 1)

  • 重复

(Arity 2)

  • 加成
  • 乘法
  • 相等:返回01

您可以选择对这些命令使用任何五个非空白符号。出于演示目的,我将使用"重复项,×乘法和+加法。

对于文字,您仅需要支持非负整数,但是您的解释器必须能够包含所有整数(在您语言的(合理的)整数范围内)。

让我们来看一个示例:10+5。该存储应表现为堆栈,而不是队列。因此,首先,堆栈从开始[],而排队的操作员列表从开始[]。然后,对文字10进行求值,从而使stack成为可能[10]。接下来,对运算符+进行求值,它需要两个参数。但是,堆栈上只有一个参数,因此排队的运算符列表变为['+']。然后,对文字5进行求值,从而使stack成为可能[10, 5]。在这一点上,'+'可以对运算符进行评估,使它成为堆栈[15]和队列[]

最终的结果应该是[15]+ 10 510 + 510 5 +

让我们来看一个更困难的示例:10+"。堆栈和队列从[]和开始[]10首先被评估,这使堆栈[10]。接下来,+对进行评估,它不会更改堆栈(因为没有足够的参数),并使队列成为['+']。然后,"进行评估。这样就可以立即运行,从而形成堆栈[10, 10]+现在可以求值,以使堆栈成为[20]和队列[]。最终结果是[20]

操作顺序如何?

让我们来看看×+"10 10。堆栈和队列都以[]

  • ×:堆栈未更改,队列变为['×']
  • +:堆栈未更改,队列变为['×', '+']
  • ":堆栈未更改,队列变为['×', '+', '"']
  • 10:堆栈变为[10]。即使×应该是第一个要评估的运算符,因为它首先出现,但"可以立即运行,并且没有运算符可以运行,因此可以对其进行评估。堆栈变为[10, 10]并排队['×', '+']×现在可以求值,这使堆栈[100]和队列成为可能['+']
  • 10:堆栈变为[100, 10],可以+对其进行求值。堆栈变为[110]并排队[]

最终结果是[110]

这些演示中使用的命令与anyfix语言的命令一致。但是,由于我的解释器中的错误,最后一个示例将无法正常工作。(免责声明:您的提交将不会在anyfix解释器中使用)

挑战

选择一组5个非空白非数字字符,并根据上述规范创建一个anyfix解释器。您的程序可以输出奇异数组或包含的值;确保值栈在执行结束时仅包含单个值,并且确保运算符队列在执行结束时为空。

这是因此以字节为单位的最短代码获胜。

测试用例

对于这些测试用例,重复项为",否定为-,加法为+,乘法为×且相等为=

Input -> Output
1+2×3 -> 9
1"+"+ -> 4
2"××" -> 16
3"×+" -> 18
3"+×" -> 36
123"= -> 1 ("= always gives 1)
1+2=3 -> 1
1"=2+ -> 3
1-2-+ -> -3
-1-2+ -> 3 (hehe, the `-1` becomes `+1` at the `-` rather than making the `2` a `-1`)
+×"10 10 -> 200 (after the 10 is duplicated (duplication is delayed), 10 + 10 is performed and then 20 * 10, giving 200)

规则

  • 适用标准漏洞
  • 如果您愿意,您可以带anyfix官方口译员并打高尔夫。期望失去可怕。

输入将以字符串形式给出,输出将以数组形式(单个整数)输出,而不是其中一个的字符串表示形式。您可以假设输入将仅包含空格,数字和您选择的5个字符。

* 实际上不是


2
到任何地方*™。
乔纳森·艾伦,

相等运算符的结果是什么?01
菲利克斯·帕尔姆

1
@JonathanAllan见上文;我删除了一条命令rip
HyperNeutrino

1
@RickHitchcock当然。
HyperNeutrino

1
您可能应该×+"10 10在测试用例中或其他任何包含以下示例的示例中:1)使用空格,2)延迟使用重复运算符(我完全错过了两件事)。
Arnauld

Answers:


5

的JavaScript(ES6),204个 203 200字节

返回一个整数。

e=>e.replace(/\d+|\S/g,v=>{for((1/v?s:v>','?u:b)[U='unshift'](v);!!u[0]/s[0]?s[U](u.pop()>'c'?s[0]:-S()):!!b[0]/s[1]?s[U](+eval(S(o=b.pop())+(o<'$'?'==':o)+S())):0;);},s=[],u=[],b=[],S=_=>s.shift())|s

使用的字符:

  • +:加法
  • *:乘法
  • #: 平等
  • d:重复
  • -:负数

测试用例

格式化和评论

e => e.replace(                     // given an expression e, for each value v matching
  /\d+|\S/g, v => {                 // a group of digits or any other non-whitespace char.
    for(                            //   this loop processes as many operators as possible
      (                             //   insert v at the beginning of the relevant stack:
        1 / v ? s : v > ',' ? u : b //     either value, unary operator or binary operator
      )[U = 'unshift'](v);          //     (s[], u[] or b[] respectively)
      !!u[0] / s[0] ?               //   if there's at least 1 value and 1 unary operator:
        s[U](                       //     unshift into s[]:
          u.pop() > 'c' ?           //       for the duplicate operator:
            s[0]                    //         a copy of the last value
          :                         //       else, for the negative operator:
            -S()                    //         the opposite of the last value
        ) :                         //     end of unshift()
      !!b[0] / s[1] ?               //   if there's at least 2 values and 1 binary operator:
        s[U](                       //     unshift into s[]:
          +eval(                    //       the result of the following expression:
            S(o = b.pop()) +        //         the last value, followed by the
            (o < '$' ? '==' : o) +  //         binary operator o with '#' replaced by '=='
            S()                     //         followed by the penultimate value
          )                         //       end of eval()
        ) : 0;                      //     end of unshift()
    );                              //   end of for()
  },                                // end of replace() callback
  s = [],                           // initialize the value stack s[]
  u = [],                           // initialize the unary operator stack u[]
  b = [],                           // initialize the binary operator stack b[]
  S = _ => s.shift()                // S = helper function to shift from s[]
) | s                               // return the final result

不要认为这适用于-1+-2。返回3而不是-3。
里克·希区柯克,

1
@RickHitchcock我的理解是第二个-必须立即应用-1
Arnauld

我认为第二个-将与去2,因为它涉及另算。也许@HyperNeutrino可以澄清。在某些情况下,负运算符可能是不明确的。
里克·希区柯克,

3

的JavaScript(ES6),162个 152 143 150字节

(s,N=s.replace(/(-?\d+)-|-(-)/g,'- $1 ').match(/(- ?)*?\d+|R/g))=>+eval(`R=${N[0]>'9'?N[1]:N[0]},${s.match(/[+*=]/g).map((o,i)=>'R=R'+o+'='+N[i+1])}`)

略有偏差:

(s,
 N=s.replace(/(-?\d+)-|-(-)/g,'- $1 ').      //change postfix negatives to prefix,
                                             //and change "--" to "- - "
     match(/(- ?)*?\d+|R/g)                  //grab numbers and duplicates
)=>+eval(`R=${N[0] > '9' ?  N[1] : N[0]},    //handle a delayed duplicate
          ${s.match(/[+*=]/g).               //grab the operators
              map((o,i)=>'R=R'+o+'='+N[i+1]) //create a comma-separated list of assignments
           }
         `)

说明

*用于乘法和R重复。其他运算符与问题中的相同。

N 成为数字数组(包括重复项)。

replace处理这样的负号来的情况的数量。例如,它会改变1-- 1-1-- -1

在中evals.match创建二进制运算符数组。请注意,此元素总是比少一个N

该函数的结果是eval数字和运算符的映射。

这是eval每个测试用例的内容:

0+2*3        R=0,R=R+=2,R=R*=3        = 6 
1+2*3        R=1,R=R+=2,R=R*=3        = 9 
1R+R+        R=1,R=R+=R,R=R+=R        = 4 
2R**R        R=2,R=R*=R,R=R*=R        = 16 
3R*+R        R=3,R=R*=R,R=R+=R        = 18 
3R+*R        R=3,R=R+=R,R=R*=R        = 36 
123R=        R=123,R=R==R             = 1 
1+2=3        R=1,R=R+=2,R=R==3        = 1 
1R=2+        R=1,R=R==R,R=R+=2        = 3 
1-2-+        R=- 1,R=R+=- 2           = -3 
-1-2+        R=1,R=R+=2               = 3 
*+R10 10     R=10,R=R*=10,R=R+=10     = 110 
+*R10 10     R=10,R=R+=10,R=R*=10     = 200 
-1+--2       R=-1,R=R+=- -2           = 1 
-1+-2        R=-1,R=R+=-2             = -3 

JavaScript表达式中的逗号运算符返回其最后一个表达式的结果,因此,map自动返回可用的表达式。

+标志是前需要eval改变true,以1false0

同时使用R变量重复运算符可以大大简化map的子表达式。

测试用例:


2
我认为replace作品不符合预期。这回报3-1+--2,我认为1是正确的(在1改变符号三次有对于第二个参数之前+可用,导致-1 + 2)。
菲利克斯·帕尔姆

很好,@ FelixPalmen。现在已修复。
里克·希区柯克,

2

JavaScript,321311字节

_="f=a=>(a.replace(/\\d+|./g,mq!~(b='+*=\"- '.indexOf(a))|b>2j3j4j5&&o+aw1/y?(y*=-1wcz:1/y?oywcz:hz,rql.map(z=>m(lki,1)[0],i)),hq1/s[1]?sk0,2,+eval(`y${a=='='?a+a:a}s[1]`)):cz,cqlki,0,a),s=[],l=[],e='splice'),s)z(a,i)ys[0]w)^r``:q=z=>os.unshift(k[e](j?b-";for(i of"jkoqwyz")with(_.split(i))_=join(pop());eval(_)

在线尝试!

除了*乘法之外,这五个字符与问题中的字符相同。
该脚本使用RegPack压缩。原始脚本_在评估后存储在变量中。


不要认为这适用于-1+-2。返回3而不是-3。
里克·希区柯克,

@RickHitchcock。您为什么认为它应该返回-3而不是3

我可能会误解否定运算符。通常-1 + -2-3,但是应该将其解析为--1 + 2吗?
里克·希区柯克,

1
@RickHitchcock。我很确定结果是3。在2进入栈之前,第二个-就已经被评估了,因此我们1 2 +的确是3。嗯,也许您也必须编辑答案。

你也许是对的。您和Arnauld会得到相同的答案,而我已要求OP进行澄清。如果可以的话,请再次投票给您。
里克·希区柯克,

1

Haskell,251个字节

(#([],[]))
(x:r)#(o,n)|x>'9'=r#h(o++[x],n)|[(a,t)]<-lex$x:r=t#h(o,read a:n)
_#(o,n:_)=n
h=e.e
e(o:s,n:m:r)|o>'N'=e(s,g[o]n m:r)
e(o:s,n:r)|o=='D'=e(s,n:n:r)|o=='N'=e(s,-n:r)
e(o:s,n)|(p,m)<-e(s,n)=(o:p,m)
e t=t
g"a"=(+)
g"m"=(*)
g"q"=(((0^).abs).).(-)

在线尝试!使用以下字符:a用于加法,m用于乘法,q用于相等,D用于重复和N用于求反。(我想e用于相等性,但是遇到了lex解析2e3为数字的问题。)用法示例:(#([],[])) "2a3 4m"yields 20


1

6502机器代码(C64),697字节

00 C0 A2 00 86 29 86 26 86 27 86 28 86 4B 86 4C 86 CC 20 E4 FF F0 FB C9 0D F0
10 C9 20 30 F3 A6 27 9D B7 C2 20 D2 FF E6 27 D0 E7 C6 CC A9 20 20 1C EA A9 0D
20 D2 FF 20 95 C0 20 09 C1 20 95 C0 A6 26 E4 27 F0 4E BD B7 C2 E6 26 C9 20 F0
E8 C9 2D D0 09 A6 4C A9 01 9D B7 C3 D0 32 C9 22 D0 09 A6 4C A9 02 9D B7 C3 D0
25 C9 2B D0 09 A6 4C A9 81 9D B7 C3 D0 18 C9 2A D0 09 A6 4C A9 82 9D B7 C3 D0
0B C9 3D D0 0D A6 4C A9 83 9D B7 C3 E6 28 E6 4C D0 A3 4C 8A C2 A6 29 F0 6F A4
28 F0 6B CA F0 4B C6 28 A6 4B E6 4B BD B7 C3 F0 F5 30 14 AA CA D0 0B 20 7B C2
20 E1 C1 20 4D C2 D0 D9 20 5C C2 D0 D4 29 0F AA CA D0 0B 20 6D C2 20 08 C2 20
4D C2 D0 C3 CA D0 0B 20 6D C2 20 16 C2 20 4D C2 D0 B5 20 6D C2 20 F4 C1 20 4D
C2 D0 AA A4 4B B9 B7 C3 F0 02 10 AC C8 C4 4C F0 0F B9 B7 C3 F0 F6 30 F4 AA A9
00 99 B7 C3 F0 A6 60 A0 00 A6 26 E4 27 F0 15 BD B7 C2 C9 30 30 0E C9 3A 10 0A
E6 26 99 37 C4 C8 C0 05 D0 E5 C0 00 F0 08 A9 00 99 37 C4 20 39 C2 60 A2 FF E8
BD 37 C4 D0 FA A0 06 88 CA 30 0A BD 37 C4 29 0F 99 37 C4 10 F2 A9 00 99 37 C4
88 10 F8 A9 00 8D 3D C4 8D 3E C4 A2 10 A0 7B 18 B9 BD C3 90 02 09 10 4A 99 BD
C3 C8 10 F2 6E 3E C4 6E 3D C4 CA D0 01 60 A0 04 B9 38 C4 C9 08 30 05 E9 03 99
38 C4 88 10 F1 30 D2 A2 06 A9 00 9D 36 C4 CA D0 FA A2 10 A0 04 B9 38 C4 C9 05
30 05 69 02 99 38 C4 88 10 F1 A0 04 0E 3D C4 2E 3E C4 B9 38 C4 2A C9 10 29 0F
99 38 C4 88 10 F2 CA D0 D6 C0 05 F0 06 C8 B9 37 C4 F0 F6 09 30 9D 37 C4 E8 C8
C0 06 F0 05 B9 37 C4 90 F0 A9 00 9D 37 C4 60 A9 FF 45 FC 85 9F A9 FF 45 FB 85
9E E6 9E D0 02 E6 9F 60 A2 00 86 9F A5 FB C5 FD D0 07 A5 FC C5 FE D0 01 E8 86
9E 60 A5 FB 18 65 FD 85 9E A5 FC 65 FE 85 9F 60 A9 00 85 9E 85 9F A2 10 46 FC
66 FB 90 0D A5 FD 18 65 9E 85 9E A5 FE 65 9F 85 9F 06 FD 26 FE CA 10 E6 60 20
33 C1 A6 29 AD 3D C4 9D 3F C4 AD 3E C4 9D 3F C5 E6 29 60 A6 29 A5 9E 9D 3F C4
A5 9F 9D 3F C5 E6 29 60 A6 29 BD 3E C4 9D 3F C4 BD 3E C5 9D 3F C5 E6 29 60 C6
29 A6 29 BD 3F C4 85 FD BD 3F C5 85 FE C6 29 A6 29 BD 3F C4 85 FB BD 3F C5 85
FC 60 A6 29 BD 3E C5 10 13 20 7B C2 20 E1 C1 20 4D C2 A9 2D 20 D2 FF A6 29 BD
3E C5 8D 3E C4 BD 3E C4 8D 3D C4 20 8B C1 A9 37 A0 C4 4C 1E AB

在线演示

用法 sys49152,然后输入anyfix表达式,然后按回车键。

  • 几乎没有错误检查,因此期望在无效表达式上产生有趣的输出。
  • *所建议的乘法符号是,所有其他符号。
  • 输入的最大长度为256个字符,排队的操作员不能超过127个。
  • 输入例程处理控制字符,因此请不要键入错误;)
  • 整数是16位带符号的,溢出将默默回绕。
  • 字节数有点大,因为此CPU甚至都不知道乘法,并且C64 OS / ROM没有给您任何整数算术运算或从十进制字符串转换为十进制字符串。

这是可读的ca65样式的汇编程序源代码


1

VB.NET(.NET 4.5)615个 576字节

-39字节感谢Felix Palmen通过更改\r\n\n

需要Imports System.Collections.Generic(包含在字节数中)

Dim s=New Stack(Of Long),q=New List(Of String),i=Nothing,t=0,c=0
Function A(n)
For Each c In n
If Long.TryParse(c,t)Then
i=i &"0"+t
Else
If c<>" "Then q.Add(c)
If i<>A Then s.Push(i)
i=A
End If
If i=A Then E
Next
If i<>A Then s.Push(i)
E
A=s
End Function
Sub E()
c=s.Count
If c=0Then Exit Sub
For Each op In q
If op="-"Or op="d"Or c>1Then
Select Case op
Case"*"
s.Push(s.Pop*s.Pop)
Case"+"
s.Push(s.Pop+s.Pop)
Case"="
s.Push(-(s.Pop=s.Pop))
Case"-"
s.Push(-s.Pop)
Case"d"
s.Push(s.Peek)
End Select
q.Remove(op)
E
Exit Sub
End If
Next
End Sub

入口点是Function A,它将字符串作为输入并返回Stack(Of Long)

符号:

  • 加法- +
  • 乘法- *
  • 平等 - =
  • 否定- -
  • 复制- d

概述:

函数A接受输入并将其标记化。它使用a Long?来计算多位数整数的总计Nothing表示我们当前未读取整数。

子程序 E获取整数堆栈和运算符队列,并评估anyfix表示法。它递归地调用自身,直到没有剩余动作为止。

我一次声明了全局参数,以节省声明和参数传递时的字节数。

A通过为匹配变量分配值来设置from的返回值A

VB True相当于-1,因此操作必须取反结果才能获得正确的值。

在线尝试!



顺便说一句,有了Imports,我得到的字节数仅为576-您能算错吗?
Felix Palmen

我用@FelixPalmen \r\n代替\n,所以这就是差异所在。
Brian J

@FelixPalmen添加了TIO,感谢您提醒我!:)(哦,我还没有意识到您已经完成了这篇文章)
Brian J
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.