Answers:
创建两种语言的多语种的一种简单方法是将代码分为两部分,如下所示:
从而
这里唯一困难的部分是找到一组语句(第一部分),这些语句使用语言A进行工作,而不会给出语言B的错误。对此的一些建议:
一维语言通常会解析整个源代码,并且会对它们不了解的事物产生语法错误或不必要的运行时影响(因此迫使您将其他语言的代码隐藏起来),而二维语言则不同于在执行路径中解析代码,这意味着程序的其余部分将被忽略。还有更多的空间可以将执行路径在两个维度上分开。您可以将指令指针发送到一个不寻常的方向,例如向下或什至向左(环绕在程序的右手边),以使其迅速摆脱干扰。一维语言中有用的技术也可以推广到二维语言(例如,您可以使用;;
在Befunge-98中,除了只是向一个奇怪的方向发送IP外,与一维解决方案相比,这基本上只是一个严格的收益。
另外,几种二维语言的输入点不在该程序的左上方,这意味着您无需费劲就可以将它们与其他语言分开。他们会自然地从小组中分离出来。
这是一个在Python和C ++中均可使用的示例
#include <iostream> /*
""" */
int main() {
std::cout << "Hello World!\n";
}
/* """
print("Hello World!")
# */
路易斯·门多(Luis Mendo)提出了我认为迄今为止最简单的解决方案,即使用评论。
您在寻找一种具有块注释的语言,而另一种语言则在其中的常规语法在第二种注释语法中。
甚至更容易的是两种具有不同块注释样式的语言,它们可互换使用正确的语法,但是我不愿意检查。
当您使用多种语言编写多语言时,您不一定能够立即将所有语言的控制流彼此分离。因此,您将需要在一段时间内“真多语”某些语言,以允许在每种语言中运行相同的代码。在执行此操作时,要记住两个主要规则:
任何两种语言的控制流应该非常相似,或者非常不同。尝试处理大量交错的控制流是造成混乱的秘诀,并且会使您的程序难以修改。相反,应通过确保位于同一位置的所有程序出于相同的原因存在并且可以在需要的情况下愉快地并行运行,来限制必须做的工作量。同时,如果一种语言与其他语言有很大不同,则您希望其执行尽快移至一个非常不同的位置,这样就不必尝试使代码一次符合两种不同的语法模型。
寻找机会将一种语言或一组相似的语言彼此分开。从较大的小组到较小的小组。一旦在程序中的某个点拥有了一组相似的语言,就需要在某个时候将它们分开。例如,在程序开始时,您可能希望将#
用作注释标记的语言与使用其他注释标记的语言分开。稍后,也许您会发现所有语言都使用f(x)
语法进行函数调用,使用分号分隔单独的命令并具有相似的语法相似性。到那时,您可以使用更多特定于语言的内容来拆分它们,例如Ruby和Perl不会处理''
字符串中的转义序列,而Python和JavaScript会处理。
通常,程序的逻辑流应该以一棵树结尾,反复地分成相互之间更相似的语言组。这给在第一次分割之前就在开始时写多语种带来了很大的困难。随着控制流越来越多地分支,并且在任何给定点运行的语言越来越相似,您的任务将变得更加容易,因为您可以使用更高级的语法而不会导致所涉及的语言出现语法错误。
一个很好的例子是集合{JavaScript,Ruby,Perl,Python 3}; 所有这些语言都接受带括号的函数调用,并可以用分号分隔语句。它们还都支持eval
语句,有效地允许您以可移植的方式进行流控制。(Perl是这些语言中最好的一种,可以尽早从小组中分离出来,因为它对变量的语法与其他语言有所不同。)
在大多数语言中,字符串文字本身不执行任何操作,或执行易于反转的操作(例如将字符串压入堆栈)。字符串文字语法也相对不规范,尤其是对于许多语言用来处理带有嵌入式换行符的字符串的替代语法而言;例如,Python具有""" ... """
,Perl具有q( ... )
和Lua具有[[ ... ]]
。
这些有两个主要用途。一种是允许您通过在一种语言的第一部分的末尾开始一个字符串并在第二种语言的第二个开始处恢复它来插入针对不同语言的部分,这应该很容易,以避免由于多种语言而意外关闭字符串。不同语言之间的字符串定界符。另一个是许多字符串定界符在其他语言中恰好是有意义的命令(通常比注释标记更有意义),因此您可以执行类似的操作x = [[4] ]
,这对于使用列表的JSON表示法的语言来说是一种无害的赋值,但是Lua中的字符串(因此,您可以将Lua代码从其余代码中分离出来,因为它可以有效地“跳转”到下一个]]
)。
您可以使用一种语言突然终止该程序,以便它将忽略另一种语言的代码。
所以基本上可以使用这种格式
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所建议,如果该语言尚未内置“结束程序”,则可以创建一个错误(如果允许)以结束该程序。
在许多语言中,双引号字符串文字通常是无害的。但是在某些语言中,它们也可能包含代码。
在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}"
可能还有其他。
这些语法不兼容。这意味着您可以将所有这些语言的代码放在一个无害的字符串中。它只会忽略其他语言无法识别的代码,并将其解释为字符串内容。
在许多情况下,您也可以在此处轻松注释掉双引号字符,并制作更传统的多语种。
这可能是最简单的(IMO)最重要的技巧之一,特别是因为它可以使用多种语言。
例:
print=alert;print("Hello World!")
这不仅适用于Javascript,而且适用于Python,Ruby等。稍后,当我想到其他示例时,将使用更多示例。当然,欢迎发表评论建议/发表评论。
alert
来print
在Python(3只),因为JS的注释语法,//
可以很容易地加工成Python程序,而Python的#
不能加工成JS。
#
基于评论本技巧是至少一种语言的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"
#`[
...
# ]# # ### # |# ; =#
对于类似的语言或简单的多语言,有时在语言执行算术方式方面有所不同很有用。这是因为大多数(非深奥的)语言都具有中缀算术运算符,并且算术可以是引入差异的快速简便的方法。
例如:
^
在某些语言中按位异或在另一些语言中取幂/
在某些语言中是整数除法,在其他语言中是浮点除法
-1/2
是-1
在一些语言(向下取整)和0
其他一些国家(向零)-1%2
是-1
在一些语言和1
别人--x
在某些语言中(双重否定)是禁止操作,在其他语言中是预先减少1/0
在某些语言中提供无穷大,而在其他语言中提供错误1<<64
在某些语言(溢出)和36893488147419103232
其他语言中给出0x=1;["JS","Python"][--x]
,它返回运行语言的名称(介于JS和Python之间)。
几乎所有BF实现都抛弃了char,+-<>[].,
恰好对我们有利!
由于具有此功能,因此BF可能是最容易用于多语言的语言之一,只要您先编写BF部分即可。编写完BF 代码后,只需对BF结构周围的所有其他代码进行建模即可。
这是一个非常简单的示例:
.+[.+]
这几乎是递增的,并且charcode输出“永远”(取决于运行时设置)。现在,如果您想编写一段随机的代码,例如在JS中,您可以执行以下操作:
x=>"asdf".repeat(+x)[x*Math.random()*2+1|0]
注意JS是如何在BF周围成型的。
如果您真的想开始使用BF,请确保知道这最有效。从另一种语言开始尝试结合BF的难度要大得多。
[]
。
x=>
更改单元格,在这种情况下无关紧要,但只想说
这是Mama Fun Roll关于BF的观点的概括。忽略大多数字符的esolang在多义词中非常有用。同样有用的是:大量字符可以互换的esolang。一些例子:
@
错误。
exec('''...\t\n\40''')
不知道这是否有价值,但是...
perl
程序根据此答案和Perl文档,如果将以shebang行开头的任何文件传递给perl
,它将调用适当的程序来运行该文件。例如,这
#!/usr/bin/python
for i in range(6):
print i**2
如果调用,将由Python解释器执行perl filename.py
。
perl
,但它不会成为Perl程序。
perl
”?听起来像是一个很好的哲学家模因
许多编程语言都能够解析任意标识符,后跟带有表达式的一对括号:
identifier(1 + 1)
有时,由于需要将代码提供给您正在使用的另一种语言,因此所讨论的标识符的形式可能是固定的。如果标识符不对应于该语言实际具有的功能,那么乍一看似乎会造成麻烦。
但是,许多编程语言在检查函数本身是否确实存在之前都会评估函数的参数(例如Lua),因此无论如何您都可以使用这种构造。您需要做的就是在函数参数内的某个位置退出程序。
这是一个示例,一个DC / Lua多语言:
c2pq(1 + #os.exit(print(3)))
c2pq
是用于打印2并退出的dc程序;Lua将此视为函数的名称,但是可以通过在其参数中放置退出命令来防止Lua出错。这种构造的最大优点是,与赋值(c2pq =
)不同,它不会自动与变量名称以符号开头的语言不兼容;函数名称语法在各种语言中比变量名称语法更一致。