创建多语种的技巧


48

是可在2种或多个不同的编程语言来运行程序。

您有什么通用技巧来制作多语言文字,或为特定任务选择易于编写多语言文字的语言?

请发布可在大多数情况下应用的提示。也就是说,它们不应仅在两种特定语言的多语言环境中工作。(如果您的技巧太具体,则可以简单地发布多语种问题的答案。)但是,您可以引入一种语言的功能,从而可以轻松地使用多种语言,也可以轻松地将其添加到任何现有的多语系中。

请为每个答案发布一个提示。如果特定于语言的提示也适用于另一种语言,请随时建议编辑。

Answers:


25

利用注释符号

创建两种语言的多语种的一种简单方法是将代码分为两部分,如下所示:

  1. 第一部分以语言A进行实际工作,以语言B无害(无错误),并以语言A注释符号结尾,该符号将语言A的第二部分隐藏起来。
  2. 第二部分使用语言B进行实际工作。

从而

  • 语言A看到第一部分,即工作,然后是注释。
  • 语言B看到没有用的第一部分,然后是第二部分,完成了任务。

这里唯一困难的部分是找到一组语句(第一部分),这些语句使用语言A进行工作,而不会给出语言B的错误。对此的一些建议:

  • 大多数基于堆栈的语言仅允许在程序末尾显示堆栈的顶部(有时甚至是默认值,例如05AB1E)。
  • 一些语言会忽略未定义的语句(例如Golfscript)。

这里可以找到使用这些准则的简单示例。语言A和B分别是MATL05AB1E


24

使用二维语言

一维语言通常会解析整个源代码,并且会对它们不了解的事物产生语法错误或不必要的运行时影响(因此迫使您将其他语言的代码隐藏起来),而二维语言则不同于在执行路径中解析代码,这意味着程序的其余部分将被忽略。还有更多的空间可以将执行路径在两个维度上分开。您可以将指令指针发送到一个不寻常的方向,例如向下或什至向左(环绕在程序的右手边),以使其迅速摆脱干扰。一维语言中有用的技术也可以推广到二维语言(例如,您可以使用;; 在Befunge-98中,除了只是向一个奇怪的方向发送IP外,与一维解决方案相比,这基本上只是一个严格的收益。

另外,几种二维语言的输入点不在该程序的左上方,这意味着您无需费劲就可以将它们与其他语言分开。他们会自然地从小组中分离出来。


20

知道你的是非

每种语言看到“真”和“假”的方式略有不同。如果它们具有相似的语法,则可以通过添加一种决定,以使语言使用不同的方式来利用此语法。

Trick或Treat线程的一个示例使用'',一个空字符串。在Lua中,这评估为真实,但在Python中为伪造,因此以下内容:

print(''and'trick'or'treat')

..将以每种语言打印不同的字符串。

要做的就是找到这样的值。例如,您可以使用'0',其结果false在PHP中可用,但true在Python中为。


17

至少使用一种语言的块引用

这是一个在Python和C ++中均可使用的示例

#include <iostream> /*
""" */
int main() {
    std::cout << "Hello World!\n";
}

/* """
print("Hello World!")
# */

路易斯·门多Luis Mendo)提出了我认为迄今为止最简单的解决方案,即使用评论。

您在寻找一种具有块注释的语言,而另一种语言则在其中的常规语法在第二种注释语法中。

甚至更容易的是两种具有不同块注释样式的语言,它们可互换使用正确的语法,但是我不愿意检查。

Python 3.5C ++中进行检查


2
该行的第一行不应使用分号。

真正。好点
dexgecko

15

分而治之

当您使用多种语言编写多语言时,您不一定能够立即将所有语言的控制流彼此分离。因此,您将需要在一段时间内“真多语”某些语言,以允许在每种语言中运行相同的代码。在执行此操作时,要记住两个主要规则:

  • 任何两种语言的控制流应该非常相似,或者非常不同。尝试处理大量交错的控制流是造成混乱的秘诀,并且会使您的程序难以修改。相反,应通过确保位于同一位置的所有程序出于相同的原因存在并且可以在需要的情况下愉快地并行运行,来限制必须做的工作量。同时,如果一种语言与其他语言有很大不同,则您希望其执行尽快移至一个非常不同的位置,这样就不必尝试使代码一次符合两种不同的语法模型。

  • 寻找机会将一种语言或一组相似的语言彼此分开。从较大的小组到较小的小组。一旦在程序中的某个点拥有了一组相似的语言,就需要在某个时候将它们分开。例如,在程序开始时,您可能希望将#用作注释标记的语言与使用其他注释标记的语言分开。稍后,也许您会发现所有语言都使用f(x)语法进行函数调用,使用分号分隔单独的命令并具有相似的语法相似性。到那时,您可以使用更多特定于语言的内容来拆分它们,例如Ruby和Perl不会处理''字符串中的转义序列,而Python和JavaScript会处理。

通常,程序的逻辑流应该以一棵树结尾,反复地分成相互之间更相似的语言组。这给在第一次分割之前就在开始时写多语种带来了很大的困难。随着控制流越来越多地分支,并且在任何给定点运行的语言越来越相似,您的任务将变得更加容易,因为您可以使用更高级的语法而不会导致所涉及的语言出现语法错误。

一个很好的例子是集合{JavaScript,Ruby,Perl,Python 3}; 所有这些语言都接受带括号的函数调用,并可以用分号分隔语句。它们还都支持eval语句,有效地允许您以可移植的方式进行流控制。(Perl是这些语言中最好的一种,可以尽早从小组中分离出来,因为它对变量的语法与其他语言有所不同。)


13

在字符串文字中隐藏代码

在大多数语言中,字符串文字本身不执行任何操作,或执行易于反转的操作(例如将字符串压入堆栈)。字符串文字语法也相对不规范,尤其是对于许多语言用来处理带有嵌入式换行符的字符串的替代语法而言;例如,Python具有""" ... """,Perl具有q( ... )和Lua具有[[ ... ]]

这些有两个主要用途。一种是允许您通过在一种语言的第一部分的末尾开始一个字符串并在第二种语言的第二个开始处恢复它来插入针对不同语言的部分,这应该很容易,以避免由于多种语言而意外关闭字符串。不同语言之间的字符串定界符。另一个是许多字符串定界符在其他语言中恰好是有意义的命令(通常比注释标记更有意义),因此您可以执行类似的操作x = [[4] ],这对于使用列表的JSON表示法的语言来说是一种无害的赋值,但是Lua中的字符串(因此,您可以将Lua代码从其余代码中分离出来,因为它可以有效地“跳转”到下一个]])。


13

结束程序

您可以使用一种语言突然终止该程序,以便它将忽略另一种语言的代码。

所以基本上可以使用这种格式

code_in_language1 end_program_in_language1 code_for_language2 end_program_in_language2 ...

end_program_in_languageN结束程序的命令在哪里。

例如,在我的答卷中,您将为感恩节带来什么?,我以Dip结束程序,然后为另一种语言V编写了代码,以便Dip解释器将其忽略。

"turkey"e#"corn"??"gravy"p&Ssalad
"turkey"e#"corn"??"gravy"                 
                         p&            # print stack and exit program (Dip) 
                           Ssalad      # Now that the program ended in Dip,
                                       # I can write V code that would otherwise
                                       # have caused errors in Dip

但是,并非所有语言都具有可以像这样结束程序的命令。但是,如果这种语言具有此功能,则应明智地使用它。

如@LuisMendo所建议,如果该语言尚未内置“结束程序”,则可以创建一个错误(如果允许)以结束该程序。


2
即使该语言没有函数或语句来结束程序,通常也会发生错误
Luis Mendo

1
@LuisMendo:同意,尽管请注意,许多多语种问题特别禁止通过崩溃退出,因为这样做太容易了。不过,如果他们不这样做,最好利用它。

1
您可能应该提到第二部分的代码在第一语言上在语法上仍然应该正确,否则大多数实用语言都会抛出错误。
MilkyWay90

13

字符串文字中的变量或代码

在许多语言中,双引号字符串文字通常是无害的。但是在某些语言中,它们也可能包含代码。

在Bash中,您可以使用`...`(它不会结束程序):

"`echo Hello world! >/proc/$$/fd/1`"

在Tcl中,您可以使用[...]

"[puts {hello world!};exit]"

在PHP中,您可以使用${...}(这会在Bash中产生一个错误,因此它必须出现在Bash代码之后):

"${die(print(Hello.chr(32).world.chr(33)))}";

在Ruby中,您可以使用#{...}

"#{puts 'Hello world!';exit}"

可能还有其他。

这些语法不兼容。这意味着您可以将所有这些语言的代码放在一个无害的字符串中。它只会忽略其他语言无法识别的代码,并将其解释为字符串内容。

在许多情况下,您也可以在此处轻松注释掉双引号字符,并制作更传统的多语种。


12

可变别名

这可能是最简单的(IMO)最重要的技巧之一,特别是因为它可以使用多种语言。

例:

print=alert;print("Hello World!")

这不仅适用于Javascript,而且适用于Python,Ruby等。稍后,当我想到其他示例时,将使用更多示例。当然,欢迎发表评论建议/发表评论。


5
需要注意的是在做例如JS / Python的时候,它通常是更短的别名alertprint在Python(3只),因为JS的注释语法,//可以很容易地加工成Python程序,而Python的#不能加工成JS。
ETHproductions 2016年

11

#基于评论

本技巧是至少一种语言Exploit注释符号Blockquotes的子集

当使用多种语言(尤其是生产就绪型语言而不是esolangs)创建多语种时,查看用#在块或单行注释中的语言会很有用。

  • 有很多以块注释语法开头的语言#,并且。之后的字符有很多变化#
  • 这些语言中的大多数还允许将一个#作为行注释,这意味着可能以一种语言开头的注释只是另一种语言中的普通注释,因此很容易放入。

以下是#在块注释中使用的语言的快速摘要列表(并非详尽无遗):

Language            Start       End      Single-line #?     Notes
------------------------------------------------------------------------------------------
Agena               #/          /#             ✓
AutoIt              #cs         #ce
Brat                #*          *#             ✓
C                   #if 0       #endif                      Not actually a comment
CoffeeScript        ###         ###            ✓            Needs to be on separate line
Common Lisp         #|          |#
Julia               #=          =#             ✓
Lily                #[          ]#             ✓
Objeck              #~          ~#             ✓
Perl 6              #`{         }#             ✓            Any bracketing chars will do
Picolisp            #{          }#             ✓
Scheme              #|          |#

有关更多示例,请参见Rosetta Code

这是一个简单快捷的示例,作为演示:

#|
###
#`[

print("Julia")
#=

|#
(format t "Common Lisp")
#|

###
alert("CoffeeScript")
###

]#
say "Perl 6"
#`[

...

# ]# # ### # |# ; =#

西风#- ... -#
DLosc '16

11

算术运算符差异

对于类似的语言或简单的多语言,有时在语言执行算术方式方面有所不同很有用。这是因为大多数(非深奥的)语言都具有中缀算术运算符,并且算术可以是引入差异的快速简便的方法。

例如:

  • ^ 在某些语言中按位异或在另一些语言中取幂
  • / 在某些语言中是整数除法,在其他语言中是浮点除法
    • 对于整数除法语言,-1/2-1在一些语言(向下取整)和0其他一些国家(向零)
  • -1%2-1在一些语言和1别人
  • --x 在某些语言中(双重否定)是禁止操作,在其他语言中是预先减少
  • 1/0 在某些语言中提供无穷大,而在其他语言中提供错误
  • 1<<64在某些语言(溢出)和36893488147419103232其他语言中给出0

3
一个简单的示例将是x=1;["JS","Python"][--x],它返回运行语言的名称(介于JS和Python之间)。
ETHproductions 2016年

10

使用Brainfuck

几乎所有BF实现都抛弃了char,+-<>[].,恰好对我们有利!

由于具有此功能,因此BF可能是最容易用于多语言的语言之一,只要您先编写BF部分即可。编写完BF 代码后,只需对BF结构周围的所有其他代码进行建模即可。

这是一个非常简单的示例:

.+[.+]

这几乎是递增的,并且charcode输出“永远”(取决于运行时设置)。现在,如果您想编写一段随机的代码,例如在JS中,您可以执行以下操作:

x=>"asdf".repeat(+x)[x*Math.random()*2+1|0]

注意JS是如何在BF周围成型的。

如果您真的想开始使用BF,请确保知道这最有效。从另一种语言开始尝试结合BF的难度要大得多。


6
对于较大的多语言,集成BF所节省的字节并没有多大帮助,我将最后编写BF 并将其他代码包装成尽可能多的代码[]
Sp3000 '16

6
这不仅适用于头脑操,而且适用于大量类似脑操的语言和许多其他图灵tarpit。
0'

2
第一次x=>更改单元格,在这种情况下无关紧要,但只想说
RomanGräf16年

7

使用大多数字符无关紧要的语言

这是Mama Fun Roll关于BF的观点的概括。忽略大多数字符的esolang在多义词中非常有用。同样有用的是:大量字符可以互换的esolang。一些例子:

  • 空格会忽略所有非空格,制表符或换行符。
  • Brain-Flak基本上忽略了所有内容()[]{}<>。(@当解释器尝试将其解析为调试标志的开始时,有时会导致错误。)
  • oO CODE忽略除字母以外的所有内容。此外,所有小写字母都可以互换,所有大写字母也可以互换。
  • Wierd仅区分空白字符和非空白字符。
  • Wordy中,一些标点符号字符将被忽略,并且所有字母都可以互换。
  • 这两个括弧括号地狱忽略除括号一切。

我修复了该@错误。
小麦巫师

尝试将空白与Python结合使用
艾德尼尔(Enedil)

@enedil您不需要使用Python的选项卡。您可以使用exec('''...\t\n\40''')
MilkyWay90

5

注意嵌套块注释

有时,多种语言将对块注释使用相同的语法,这经常会破坏使用两种语言创建多语种的交易。但是,偶尔会有一种语言允许嵌套的块注释,这些注释可能被滥用来创建单独的代码路径。

例如,考虑以下多语言:

#[#[]#print("Lily")#]#echo"Nim"

Nim和Lily都使用#[]#来开始和结束块注释,但是只有Nim允许嵌套块注释。

Lily将第二个#[视为单个块注释的一部分,将第一个]#视为终止块注释。(#以下Lily的打印语句是隐藏Nim代码的行注释。)

Nim也可以将其#[]#视为嵌套(尽管为空)块注释和print("Lily")#外部块注释。


4

不知道这是否有价值,但是...

使用shebang行将所有内容转换为有效perl程序

根据此答案和Perl文档,如果将以shebang行开头的任何文件传递给perl,它将调用适当的程序来运行该文件。例如,这

#!/usr/bin/python

for i in range(6):
    print i**2

如果调用,将由Python解释器执行perl filename.py


3
虽然可以使用调用程序perl,但它不会成为Perl程序。
圣保罗Ebermann

2
@PaŭloEbermann我意识到这是临界点,所以我以“不确定是否有价值”开始回答。:)但是,定义真正的Perl的是什么(如果不是)“在文档中编写并由参考实现返回的内容perl”?听起来像是一个很好的哲学家模因
费德里科·

1
(另请参阅此meta答案。)
Federico Poloni

4

调用不存在的函数,然后在评估其参数时退出

许多编程语言都能够解析任意标识符,后跟带有表达式的一对括号:

identifier(1 + 1)

有时,由于需要将代码提供给您正在使用的另一种语言,因此所讨论的标识符的形式可能是固定的。如果标识符不对应于该语言实际具有的功能,那么乍一看似乎会造成麻烦。

但是,许多编程语言在检查函数本身是否确实存在之前都会评估函数的参数(例如Lua),因此无论如何您都可以使用这种构造。您需要做的就是在函数参数内的某个位置退出程序。

这是一个示例,一个DC / Lua多语言:

c2pq(1 + #os.exit(print(3)))

c2pq是用于打印2并退出的dc程序;Lua将此视为函数的名称,但是可以通过在其参数中放置退出命令来防止Lua出错。这种构造的最大优点是,与赋值(c2pq =)不同,它不会自动与变量名称以符号开头的语言不兼容;函数名称语法在各种语言中比变量名称语法更一致。

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.