Skip to main content
link to a Pyth debugger
Source Link
user62131
user62131

I made heavy use of this Pyth debugger while working on the program; check the "Debug on?" box, and you'll see the Python that the program transpiles to. This is very helpful in knowing whether a syntax error is in the original Pyth or the output Python, and getting clues in how to fix it (e.g. if a Python statement has been placed in the middle of an expression, you know you'll need to escape some of the expression's nesting levels).

I made heavy use of this Pyth debugger while working on the program; check the "Debug on?" box, and you'll see the Python that the program transpiles to. This is very helpful in knowing whether a syntax error is in the original Pyth or the output Python, and getting clues in how to fix it (e.g. if a Python statement has been placed in the middle of an expression, you know you'll need to escape some of the expression's nesting levels).

Source Link
user62131
user62131

59. Tcl, 1324 bytes

#16 "(}23!@)(" 3//*v\D;'[af2.qc]PkPPX'#)"14";n4 #/*0|7//`"` ['][!(>77*,;68*,@;'1,@1␉0␉␉11)(22)S␉(1 P''53'S^'q #>␉ # 36!@␉` # # #`<` #<]+<[.>-]>[ #{ #z} # #=x<R+++++[D>+++++++ L+++<-][pPLEASE,2<-#2DO,2SUB#1<-#52DO,2SUB#2<-#32DOREADOUT,2PLEASEGIVEUPFACiiipsddsdoh]>+.-- -. >][4O6O@ #x%+>+=ttt Z_*. #D>xU/-<+++L #R+.----\).>]| #[#[(}2}20l0v0x1k1kMoOMoOMoOMoOMOO0l0ix0jor0h0h1d111x0eU0yx0y0moO1d0y0e0e00m1d0i0fx0g0n0n11MoOMoOMoOMoOMoOMoOMoOMoOMoOMoOMoOMoOMoOmOoMOo0moo0n0tx0t0moO0f0t0gOOM0g0f0h0j0j0i0001k10vx0v0l111111^_00) ###x<$+@+-@@@@=>+<@@@=>+<?#d>+.--.| # [ "]56p26q[puts 59][exit]" ,'\[' ];#// '(((p\';a=a;case $argv[1]+${a:u} in *1*)echo 50;;*A)echo 54;;*)echo 58;;esac;exit;';print((eval("1\x2f2")and 9 or 13)-(0and 4)^1<<(65)>>62)or"'x"or'{}{}{}{}({}<(((((()()())){}{})){}{})>)\{(<{}(( {}){})>)}{}({}())'#}#(prin 45)(bye)46(8+9+9+9+9+=!)((("'3)3)3)"|/=1/24=x'/ __DATA__=1#"'x"// #.;R"12"' ###;console.log +39 """"#// =begin // #sseeeemPaeueewuuweeeeeeeeeeCisajjap*///;.int 2298589328,898451655,12,178790,1018168591,84934449,12597/* #define p sizeof'p'-1?"38":"37" #include<stdio.h> main ( )/*/ #*/{puts(p);}/* # /* <>{// #} disp 49#// #{ }<>// $'main'// #-3o4o#$$$ #<R>"3"O. =end #// """#"#// #} #s|o51~nJ;#:p'34'\=#print (17)#>27.say#]#print(47)#]#echo 21# #sss8␛dggi2␛`|$//''25 16*///~-<~-<~-<<<~-^_^_X2229996 

is a literal tab, a literal ESC character; Stack Exchange would mangle the program otherwise. Note also that the line #*/{puts(p);}/* has a trailing space. I recommend copying the program from the "input" box of the TIO link below, if you want to work on it.

Try them online!

VIP score (Versatile Integer Printer): .006446 (to improve, next entry should be no more than 1392 bytes)

Rundown

This program prints 59 in Tcl, 58 in Ksh, 57 in Wise, 56 in dc, 55 in Brain-Flak Classic, 54 in Zsh, 53 in Shove, 52 in COW, 51 in Assembly, 50 in Bash, 49 in Octave, 48 in Deadfish~, 47 in Lily, 46 in Cubix, 45 in PicoLisp, 44 in alphuck, 43 in reticular, 42 in evil, 41 in brainfuck, 40 in Minimal-2D, 39 in CoffeeScript, 38 in C, 37 in C++, 36 in Labyrinth, 35 in INTERCAL, 34 in Rail, 33 in Incident, 32 in Whirl, 31 in Modular SNUSP, 30 in Whitespace, 29 in Trigger, 28 in Brain-Flak, 27 in Perl 6, 26 in 05AB1E, 25 in Pip, 24 in Thutu, 23 in Hexagony, 22 in Underload, 21 in Nim, 20 in Prelude, 19 in Reng, 18 in Cardinal, 17 in Julia, 16 in Pyth, 15 in Haystack, 14 in Turtlèd, 13 in Ruby, 12 in Fission, 11 in Befunge-98, 10 in Befunge-93, 9 in Perl 5, 8 in Retina, 7 in Japt, 6 in SMBF, 5 in Python 2, 4 in ><>, 3 in Minkolang, 2 in V/Vim, and 1 in Python 3.

Verification

Most of the languages are tested by the test driver shown above.

  • Reng can be tested to output 19 here.

  • Modular SNUSP can be tested to output 31 here.

  • Incident was tested to output 33 on my own computer, locally, using the official interpreter.

  • Deadfish~ can be tested to output 48 on my own computer, locally, using this interpreter. Note that Deadfish~ takes the polyglot to be fed on stdin, but and prints a number of >> prompts to standard output, which are an unavoidable consequence of running any Deadfish~ program.

Explanation

Tcl

Tcl is a language designed for embedding scripts into larger programs. This means that there are a lot of different dialects of Tcl with different commands; however, this particular program restrains itself to "portable" Tcl, running no commands other than ones with a common meaning on every platform. (The interpreter I used for testing is tclsh, which seems to interprets unknown commands as shell commands, although it isn't documented to do so.)

In this particular program, we mostly care about its bizarre parsing rules:

  • If a token starts with #, it's a comment that lasts to a newline (thus #…\n is a comment, but x#…\n isn't;
  • Most tokens are whitespace-delimited;
  • If a token starts with { or ", it instead ends at the matching " or };
  • […] substitutes the result of a command into a token (like $(…) in bash), even if it's "…"-quoted (but not if it's {…}-quoted).

The program is thus almost very simple; all we have to do is create a "…" string literal that most languages will ignore, and drop some Tcl code in square brackets into the middle of it. In this case, that's [puts 59;exit]. However, there are some problems with this method, each of which caused a clash with a different language. As such, they'll be discussed below.

dc

Polyglotting Tcl and dc is fairly difficult, because both of them complain upon seeing an invalid command, and very few commands are valid in both. We can't start a Tcl string literal with { or " because dc will complain about both. As such, we have to start with dc code.

One possibility is to just write the dc commands outright. We can actually almost pull this off directly:

c56pq="[puts 59;exit]"; 

This is a valid command in the shells and in most of the scripting languages, meaning that it's almost a very simple problem to our solution. However, it isn't valid Perl (variable names in Perl start with punctuation marks, normally $), and I couldn't find a way to make it valid Perl without breaking a lot more. So that was something of a dead end.

The other alternative is to hide code from dc using square brackets to quote it, along these lines:

[ "[puts 59;exit]" ,']56pq[' ];#// 

That approach seems more promising, and doesn't conflict with any of the scripting languages. (Note the space after the second "; that's for Tcl, which requires whitespace between tokens.) The shells complain, but it's a warning rather than an error (they keep executing), so we can live with this for now.

Brain-Flak Classic

There are no changes to the Brain-Flak Classic code in this polyglot. However, it's mostly relevant because of what it prevents us from doing: it doesn't let us nest square brackets, […[…]…], without producing unwanted output.

As such, our dc/Tcl polyglot is going to have to work without nesting brackets, meaning that our double-quoted string literal is going to have to contain an ] before the first [ (as it's inside square brackets itself). Perhaps surprisingly, Tcl is just fine with this; it treats [ specially, but ] isn't special except to match a [. Of course, that means we're going to have to somehow add an extra [ to the program in a way Tcl couldn't see, so that brackets stayed matched after we added an extra closing ] for Tcl (to replace the ] it couldn't see). I tried a ton of approaches for this, most of which ended up breaking some language or another (at one point I even managed to break Nim, of all things).

Eventually, I realised that you could make use of Tcl's weird comment syntax to hide a [ from Tcl but not anything else, so I added an extra couple of lines to the program for that purpose (as Tcl comments end at newlines). It was complex, though (placement is very hard, as Tcl panics upon seeing """", leaving only a small window where it could be placed, but you can fit it in just before the """" line by using single quotes to hide the whole thing from Python). Eventually, I came across the (apparently undocumented?) fact that \[ also hides the opening square bracket from Tcl, which made things much easier.

Pyth

Adding double quotes to the program is inevitably going to cause trouble with Pyth, which hides much of the program inside them (although less of the program than you might expect). The basic issue here is that Pyth, despite being a golfing language, has a distinction between expressions and statements (which is inherited from the fact that it compiles to Python); place a statement inside an expression and the program won't compile. #, which is all over the place in this program (and many copies of which actually run in Pyth) is a statement, typically meaning "loop until an exception occurs" (it's overloaded and can also mean other things, but that's the most common meaning). It uses prefix syntax and single-character commands, so apparently innocent things like our puts can end up opening a lot of nesting levels, which all have to be closed before the next #-that's-parsed is seen. However, until the next statement that's parsed, we can happily expose fairly large chunks of the program to the Pyth parser; most things are expressions, after all.

The first change we need to make to our Tcl code, which is necessarily exposed to Pyth with this way of doing things, is to remove the semicolon (which I haven't been able to figure out the exact parsing rules of, but it's statement-like and normally crashes the parser if it appears in the wrong place). We can do that via using two substitutions rather than one, [puts 59][exit] rather than [puts 59;exit].

The second change we need to make the polyglot work again in Pyth is to end the expression before the next statement occurs. As a prefix language, most of the time we can escape one nesting level via adding a literal (such as a number, or a string); that's how prefix languages work. It turns out that there are plenty of Pyth literals in the parsed area, so many of the levels close themselves naturally.

However, Pyth also has some variable-arity commands, which will consume arbitrarily many literals, and thus need to be closed explicitly. The command to do this is ), which is unfortunately one of the hardest characters to fit into the polyglot (especially as ( is a variable-arity command in its own right). Still, I perservered with this approach, adding ")3)3)" (i.e. dropping out of the Pyth string literal, cleaning up our expression, and going back into the literal), and Pyth started working. Of course, that broke a lot of other languages, and I'll be discussing those later.

05AB1E

There are two languages which hide most of the code in strings. One of them was Pyth, but the other is 05AB1E.

Luckily, 05AB1E is much better-behaved than Pyth, and will happily tolerate almost any character in parsed code. The character that causes the problems is the q in the dc code, which prints the top of the stack and exits the program, meaning it never reaches the 26 at the end of the program.

Well, this seems more like an opportunity than a problem, given that 05AB1E's accidental new behaviour is very close to the behaviour we'd actually want. A quick change of 56pq to 56p26q and we have a clean dc/05AB1E parallel-code (i.e. all commands executed in both) polyglot that halts the parser for the rest of the code, and dc and 05AB1E naturally end up in the same place (but for different reasons). This also means that the 05AB1E code at the end of the polyglot could safely be removed, simplifying it a bit. (This may open up new opportunities for anything that cares about the end of the program.)

Underload

I added a lot of closing parentheses to the program to keep Pyth happy. Obviously, Underload likes its parentheses matched. This was a trivial fix; just add some opening parentheses just before the double quote before the Pyth code, and Pyth won't be able to see them but Underload will.

Prelude

Of course, all this addition of parentheses is something that can easily course major problems with Prelude. This is what determined where I added the Pyth/Underload code: just before the Thutu, at the end of the longest line of the program (just after the Prelude runs). Because it's on such a long line, the new parentheses don't vertically align with anything; and the )(…) acts as a Prelude comment (for exactly the same reason that ][…] acts as a comment in brainfuck/SMBF).

bash/zsh/ksh

The Pyth/Underload addition adds a double quote to the program, in a section of the code which uses double quotes to hide code from the shells. This is easier to fix than it seems; just add '3 just after the opening double quote (the extra 3 is to close the nesting level that the ' opens in Pyth), and ' near the end of the Thutu code, meaning that we can actually end the parse in these languages a line earlier than we previously were. Some proportion of the "'x" on the line afterwards can likely now be golfed off (perhaps even the whole thing!), but I don't really want to mess about more with this now that it's working.

Incident

I needed to detokenise three tokens to balance the code. Coffeescript's 39 became +39 to break up 3, a space was dropped into the Brain-Flak to break up ({}, and a trailing space was added to the C (specifically, #*/{puts(p);}/* ) to break up the token consisting of /* and a newline.

Future prospects

The end of the code is now much more open than it previously was. I don't know which languages care about that, but if you can think of one, now is a good opportunity.

Tcl shouldn't cause problems past the first non-# line, as all previous lines are commented out, and the parser exits before parsing any more.

Double quotes are now more usable than they previously were, because both Pyth and 05AB1E have had changes to make them more tolerant of double quotes in the code. (The ((("'3)3)3) can easily be expanded if needed to close more levels of Pyth code, without negatively affecting anything else.) This probably increases the scope for adding more #-comment languages that don't have usable block comments.