g | x | w | all
Bytes Lang Time Link
126Swift 6240306T200328ZmacOSist
191Easyfuck240402T011531ZQuadrupl
205TypeScript's type system231211T151329Znoodle p
129C gcc231212T225939ZAShelly
090Julia 1.0231220T135050ZMarcMush
203Gema231217T012617Zmanatwor
649brainfuck231218T024239ZATaco
nan231211T085608Zlyxal
173Cabsi231217T204740ZConor O&
111Python231211T083036Zbsoelch
118PowerShell Core231211T201547ZJulian
050APL Dyalog Classic231212T044209ZTbw
099Haskell231212T230648ZLeo
029Vyxal 3231212T101215Zlyxal
294Brainflak231212T055012ZDJMcMayh
092Perl 5 a231211T190602ZXcali
143Haskell231211T204723Zcolossus
312Go231211T152145Zbigyihsu
050Pip p231211T180708ZDLosc
179flex231211T143330ZNoodle9
103JavaScript Node.js231211T094052Ztsh
114Ruby231211T150805ZG B
048Charcoal231211T144410ZNeil
nanRegex PCRE 2231211T120535Zmousetai

Swift 6, 196 188 126 bytes

{($0 as[_]).reduce(into:[_]()){s,i in
var z:Int{s.popLast()!}
i==0 ?_=z:(s+=i>3 ?[z,z]:[i>0 ?i<2 ?s.last!:i<3 ?z+z:-z+z:-i])}}

Try it on SwiftFiddle!

Takes input as an array of Int instructions.

Instruction Action
-n push n
0 pop one and discard (drop)
1 pop one and push twice (dup)
2 pop two and add
3 pop two and subtract
4 pop two and push in reverse (swap)

Notes

Easyfuck, 191 bytes

NELe%»Öß;º±uëSHYl®|ùó7ÌÕ¾m}_ÕoSGCISHYCSIÚoDCS¾s÷ëækV¾Ü¡"ÿÊÕÛBù"ÿÊÕÝB§:PLDo®©Ö¢VìïPU2>|ùòPMVTS␕Þ}yN¥␒PM)Æ¡õå¸␔j|ÁN·SS3␞t[HOPF¥ju¼yÑn␅␚PU2<ªõN·OSC␖àQ©#Ê·Ôëè·␂RII␟!SSHY÷E¸␔j¦òCSIêju¾}Ñn␊ºß>|®òSGCIVånHÁõ¼ïDCSãMW¹ÝÕ¸␝«ºû;ì␖␒8¶¹␊wØ,$et

due to lack of unicode representations for c1 control characters, they have been replaced by their superscripted abbreviations

Decompressed:

BY$[^[>;],.^]5Y.>>>3>3+>6_+}+>3---S=S>!>9}}>3-->n($/~++[!>$/~++]!)g([>])k(Jng>$>>>>)t(+^>^)j(J<)c(>^-`(j>0)k<<<t-`(j+)k<<t-`(j$<U=)k<t-`(j$<U_)kt-`(j$>!)k>t-`(jS<S>S)k>>t-`Uk>>>+^)J[Jn$0>[g>!cJn;]-`;+]>g>`X$8[.!'>`X$2]

Explanation:

BY$[^[>;],.^]

The program begins by putting into the storage cell so it can check against it when taking input, to know when input is done (␍␊ is the enter key). It then runs a loop that puts all the characters into consecutive cells until it receives a .

5Y.>>>3>3+>6_+}+>3---S=S>!>9}}>3-->

It then prints a and puts two s after the instructions "block". The first one acts as a separator, and the second will store the instruction that is currently executed. After that it sets the next 7 cells to the following characters: 01+-:$. which will be checked against with the instruction stored in the cell just before them. They correspond to the following instructions:

Character Instruction
0 Push 0
1 Increment top value
+ Pop top 2 values, push sum
- Pop top 2 values, push difference
: Pop top value, push twice
$ Swap top 2 values
. Pop top value

As per my conversation with the author in the comments, this solution should be legal.

n($/~++[!>$/~++]!)g([>])k(Jng>$>>>>)t(+^>^)j(J<)

The program then defines a bunch of helper functions. n moves the pointer to the right until it encounters a non-zero cell, g does the same but it looks for null cells, k utilizes the previous 2 to go to the keys "block" (the one with the instruction templates). t and j just contain code that is used a bunch of times and needed to be golfed down.

c(>^-`(j>0)k<<<t-`(j+)k<<t-`(j$<U=)k<t-`(j$<U_)kt-`(j$>!)k>t-`(jS<S>S)k>>t-`Uk>>>+^)

It then defines the c function which takes the stored instruction and checks it against the instructions in the keys block. The stack itself is stored after the keys block separated by a single null cell. Accessing the top of the stack is done by moving the pointer to the first cell, and then moving it to the cell before it, effectively moving it to the last cell.

J[Jn$0>[g>!cJn;]-`;+]

And that's the main loop. It takes an instruction from the instruction block setting it to 0, puts it just before the keys block, and runs the c function. It runs until the instruction block is made up of nothing but null characters.

>g>`X$8[.!'>`X$2]

After the main loop is completed all that is left is printing the stack which is done in this small loop at the end. Each entry is separated by a space.

TypeScript's type system, 206 205 bytes

//@ts-ignore
type F<C,S=[0,0]>=[S,C]extends[[infer A,infer B,...infer V],[infer I,...infer R]]?F<R,I extends string?[I,...S]:[...[[B],[A,A,B],[B,A],[`${A}${B}`],B extends`${A}${infer Z}`?[Z]:0][I],...V]>:S

Try it at the TS playground

This is a generic type F<C> which takes input as a tuple of items which are either unary numbers as strings of 1s, or numbers 0 to 4 for the 5 commands:

num function
0 Pop
1 Duplicate
2 Swap
3 Add
4 Subtract

This solution works identically to the one below, only it skips the step of splitting on spaces, and indexes into an array instead of a dictionary, so it ends up quite a bit shorter.

TypeScript’s type system, 324 309 251 220 bytes

//@ts-ignore
type F<C,S=[0,0]>=[S,C]extends[[infer A,infer B,...infer V],`${infer I} ${infer R}`]?F<R,I extends`1${any}`?[I,...S]:[...{p:[B],d:[A,A,B],x:[B,A],a:[`${A}${B}`],s:B extends`${A}${infer Z}`?[Z]:0}[I],...V]>:S

Try it at the TS playground

This is a generic type F<C> which takes input as a string type of space separated commands or unary numbers, space terminated. Output in unary, first element is top of stack.

Commands:

name function
a Add
s Subtract
x Swap
p Pop
d Duplicate

I was surprised by how short this was when it was 100 bytes longer than it is now, so now I'm really surprised.

Explanation:

type F<
  // C is the input string type
  C,
  // S is the stack, starts with two useless elements
  S=[0,0],
>=[S,C]extends[
    // get the top 2, A and B, and the rest V, of the stack
    [infer A,infer B,...infer V],
    // get the first word I and the rest R of C
    `${infer I} ${infer R}`
  ]
    // recurse, setting C to R, and setting S to...
    ?F<R,
      // does I start with a 1?
      I extends`1${any}`
        // if so, prepend it to S
        ?[I,...S]
        // otherwise, it's a command; index into this object
        // to replace the top 2 of the stack:
        :[...{
          // pop- just the second
          p:[B],
          // dup- first twice, then second
          d:[A,A,B],
          // swap: second, then first
          x:[B,A],
          // add: concatenate the first and second
          a:[`${A}${B}`],
          // subtract: the second with the first taken away
          s:B extends`${A}${infer Z}`?[Z]:0
        // then append V
        }[I],...V]
    >
  // if C is empty (no more commands are left), return S
  :S

C (gcc), 131 129 bytes

k[99],*s=k,t;main(p){
for(;p=getchar()-64;*s=p<0?*s*8+p+16:p<4?p=*s--,t=*s,p:p<6?*s+t:p<8?-*s:!++s);
for(;s>k;printf("%d ",*s--));}

Try it online!

Inspired by Python answer, saved 23 bytes by implementing keywords as primitives:

Primitives

These primitives are mapped to to ASCII ranges, which allow us to build the following operations with nonsense names.

OPERATION KEYWORDS:

USAGE:

$> echo "^1^2AD^1CODA^12^2AGE^3AD^9LADLEAGE^1^2^3^1LADLE^2AD^3^2^5CUE@" | ./a.out
2 5 3 3 1 3 2 1 0 11 3 

previous:

C (gcc), 244, 229, 223, 204, 161, 154 bytes

thanks to @ceilingcat for -7

k[99],*s=k,t;main(p){for(;p=getchar()-42;*s=t=p<0?!++s:p>5?8*t+p-6:p>4?*--s:p>3?
*s++:p>2?*--s-t:p>1?p=*--s,*s++=t,p:*--s+t);for(;s>k;printf("%d ",*s--));}

Try it online!

OPERATIONS:

Usage:

$> echo ' 1 2+ 1/ 12 2- 3+ 9.- 1 2 3 1. 2+ 3 2 5,*' |  /a out 
2 5 3 3 1 3 2 1 0 11 3 

How it works: k is the stack storage and s points to the top. p is the next program character from standard input.
p-42 maps the range "*+,-./01234567" into 0..14.

A '*' (0) exits the loop. Otherwise, it's a big if-else statement using ternary operators.
Any ASCII character below '*' starts a number entry by pushing a 0 onto the stack.
Characters from '0' upward are converted to octal digits and added to 8* the stack top t.
The remaining 5 characters manipulate the stack pointer and produce the value that should be on top.

Julia 1.0, 90 bytes

f()=[]
f(+,b...;c=f(b...))=try c[[+;2:end]]catch;try[c[2]+c[1];c[3:end]]catch;[+;c]end;end

Try it online!

input and output stacks are lists in reverse order.

It works by chosing clever ways to represent the commands, grouped in 3 types, detected with try/catch (shorter than multiple dispatch here)

Gema, 206 203 characters

<N>=@push{s;$1}
+=@set{s;@add{$s;@pop{s}$s}}
-=@set{t;$s}@set{s;@sub{@pop{s}$s;$t}}
d=@push{s;$s}
r=@set{t;$s}@set{n;@pop{s}$s}@set{s;$t}@push{s;$n}
s=@pop{s}
 =
\Z=@f{}
f:=@cmps{${s;};;;;$s @pop{s}@f{}}

As I like dc, borrowed its commands: d dup, r swap, s drop.
The stack is dumped top to bottom.

Sample run:

bash-5.2$ echo '1 2 + d 3 4 - 5 r 6 7 8 s s 9' | gema '<N>=@push{s;$1};+=@set{s;@add{$s;@pop{s}$s}};-=@set{t;$s}@set{s;@sub{@pop{s}$s;$t}};d=@push{s;$s};r=@set{t;$s}@set{n;@pop{s}$s}@set{s;$t}@push{s;$n};s=@pop{s}; =;\Z=@f{};f:=@cmps{${s;};;;;$s @pop{s}@f{}}'
9 6 -1 5 3

Try it online! / Try all test cases online!

brainfuck, 684 649 bytes

,[<<--[>+<++++++]>-[->-<]>[[<]+[>]<-]<<<<<<<<<<<<<<<<[[->]<<<<<<<<<<<<<<<<]>[->+<]>[->+<]>[->+<]>[->+<]>[->+<]>[->+<]>[->+<]>[->+<]>>[-]<[->+<]>[<+[,<<++++[>++++++++<-]>[->-<]>[---------------->[-<++++++++++>]<[->+<]<+>]<[->+<]>]>>>>>>>>>[>]+[<]<<<<<<<-[->>>>>>>>[>]<+[<]<<<<<<<]>->->->->-<<<<<]>[->>>>>>>>[>]<<[->>+<<]>[-<+>]>[-<+>]<[<]<-<-<-<-<-<]>[->>>>>>>[>]<[-]<[<]<-<-<-<-<]>[->>>>>>[>]<[-<->]<[<]<-<-<-<]>[->>>>>[>]<[->+>+<<]>>[-<<+>>]<<<[<]<-<-<]>[->>>>[>]<[-<+>]<[<]<-<]>,]>>[[<++++++++++>[-<-[<+<<]<[+[->+<]<+<<]>>>>>]<[-]-[>+<-----]>---[-<<+>>]<<-<<<<<[<]+[>]>>>>[-<<<<<[<]>+[>]>>>>]<[->>>+<<<]>>>]<<<<<<<[<]>[.[-]>]++++++++++.[-]>>>>>>>]

Try it online!

All numbers have to be followed by a space. Uses +-,./ for add, sub, dup, drop, and swap respectively.

Prints stack from bottom to top separated by newlines.

I confess this is a touch over-engineered, and could be shorter if I used less human-readable I/O.

With Comments

READ AN INSTRUCTION
IF ITS A NUMBER THEN GRAB ALL OF IT UNTIL THE SPACE
OTHERWISE ITS A REGULAR INSTRUCTION
ITS ACTUALLY EASIER TO CHECK IF ITS A REGULAR INSTRUCTION THAN A NUMBER BECAUSE THERE ARE MORE NUMBERS THAN INSTRUCTIONS
SO WE CHECK THAT FIRST
>>>>>>>>>>>>>>>>>>>>>>>>>>>> THIS LINE MAKES DEBUGGING EASIER BUT ISNT NEEDED
,[
    <<--[>+<++++++]>-
    SUBTRACT 42 FROM INP
    [->-<]
    COLLAPSE IT LEFT
    >[
     CLEAR THE ONE AT NEGATIVE SIXTEEN
     THIS IS A GUARD VALUE
     <<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>
    [<]+[>]<-]
    SUM UP THE FIRST NINE NUMBERS AS THESE ARE THE DIGITS
    WE IGNORE 0 AS ITS NOT USEFUL
    <<<<<<<<<<<<<<<<
    IF THE GUARD IS TRIPPED THEN WE DISCARD THE WHOLE STACK
    [[->]<<<<<<<<<<<<<<<<]>
    [->+<]>[->+<]>[->+<]>[->+<]>[->+<]>[->+<]>[->+<]>[->+<]>
    >[-]<[->+<]> I PUT IT IN THE ZERO ANYWAY FOR SANITY
    IF THIS IS TRUTHY THEN ITS A NUMBER THAT WE NEED TO PUSH
    IN SUCH CASE WE NEED TO KEEP GRABBING DIGITS UNTIL WE SEE A 32 SPACE
    [
        <+[
            ,
            32
            <<++++[>++++++++<-]>
            SUBTRACT FROM INP
            [->-<]
            >
            [
                IF ITS STILL TRUTHY THEN ITS A NUMBER (PROBABLY)
                SUBTRACT 16 THAN MULTIPLY BY TEN ONTO THIS
                ----------------
                >[-<++++++++++>]
                AND COPY BACK
                <[->+<]
                <+> SET THE NOT FLAG
            ]
            COPY THE NOTFLAG UNTO HERE TO CHECK IF WE NEED TO LOOP
            <[->+<]>
        ]
        GO SIX RIGHT AND PUSH A NEW VALUE TO THE STACK
        >>>>>>>>>[>]+[<]<<<<<<<-
        [->>>>>>>>[>]<+[<]<<<<<<<]
        >->->->->-
        <<<<<
    ]
    > IF THIS IS POSITIVE THAN ITS A SWAP INSTEAD
    [
        WE USE SCRATCH SPACE NEXT TO THE NUMBERS TO MAKE SWAPPING THEM POSSIBLE
        -
        >>>>>>>>[>]<<
        COPY THIS NUMBER TWO ACROSS
        [->>+<<]
        >[-<+>] COPY THE NEXT NUMBER INTO THIS PLACE
        >[-<+>] AND THIS ONE TOO
        <[<]<-<-<-<-<-< AND GO HOME
    ]
    > IF THIS IS POSITIVE THAN ITS A DROP
    [
        -
        >>>>>>>[>]< GO TO THE TOP OF THE STACK
        [-] CLEAR IT
        <[<]<-<-<-<-< AND GO HOME
    ]
    > IF THIS IS POSITIVE THAN ITS A SUB
    [
        -
        >>>>>>[>]< GO TO THE TOP OF THE STACK
        [-<->] SUB IT FROM THE LAST
        <[<]<-<-<-< AND GO HOME
    ]
    > IF THIS IS POSITIVE THAN ITS A DUP
    [
        -
        >>>>>[>]< GO TO THE TOP OF THE STACK
        [->+>+<<] COPY IT ACROSS THE NEXT TWO
        >>[-<<+>>] COPY THE ONE BACK TWO
        <<<[<]<-<-< AND GO HOME
    ]
    > FINALLY IF THIS IS POSITIVE THAN ITS ADD
    [
        -
        >>>>[>]< GO TO THE TOP OF THE STACK
        [-<+>] ADD IT UNTO THE LAST
        <[<]<-< AND GO HOME
    ]
    >,
]
ONCE WERE DONE WE NEED TO PRINT ALL VALUES ON THE STACK
>>
[
    GET ALL THE DIGITS
    [
        <++++++++++>
        [-<-[<+<<]<[+[->+<]<+<<]>>>>>] DIVMOD
        <[-] UNNEEDED VALUE
        SET TO 48 AND ADD TO THE MOD VALUE
        -[>+<-----]>---
        [-<<+>>]
        <<
        PUSH THIS VALUE TO THE NUMBERSTACK
        -<<<<<[<]+[>]>>>>
        [-<<<<<[<]>+[>]>>>>]
        <[->>>+<<<] MOVE THE NEW VALUE BACK
        >>>
    ]
    PRINT THEM ALL OUT
    <<<<<<<[<]>[.[-]>]
    PRINT A NEWLINE AS WELL ++++++++++.[-]
    >>>>>>> NEXT NUMBER
]

Trivial Eval/Exec Answers in Stack Languages

For languages where the command set required is already a thing, and evaluating a string is the shortest solution.

Don't add answers in stack languages that aren't purely "exec".

Vyxal W, 1 byte

Ė

Try it Online!

Uses the command set +-:$_ and [0-9]+ for pushing numbers.

05AB1E, 3 bytes

.V)

Try it online.

Uses the command set +-Ds\ for add; subtract; duplicate; swap; drop respectively. .V executes the (implicit) input as 05AB1E code; and ) wraps the entire stack into a list (which is output implicitly at the end).

sclin, 1 bytes

#

Try it on scline! Uses dup, pop, swap, +, -.

dc, 2 characters

?f

Where ? reads a line from stdin and executed it as dc code and f dumps the stack.

In the simple stack language use d for dup, r for swap and ss for drop.

Try it online!

RProgN, 1 byte

C

Try it online!

Requires space between commands, []\ are Drop, Dup, and Swap respectively.

Cabsi, 173 bytes

1PUSH NULL
2GETW
3JNL 8
4DUP
5YEET
6ORD
7GOTO $1
8JNL 64
9PRINT
10GOTO 8
33POP
34GOTO 2
36SWAP
37GOTO 2
43ADD
44GOTO 2
45SUB
46GOTO 2
57YOINK
58MAKEI
59GOTO 2
62DUP
63GOTO 2

Try it here! Implements dup (>) add (+) sub (-) drop (!) and swap ($). Prints stack top-to-bottom. Expects instructions to be separated by spaces/newlines.

Technically, only the first character of non-numeric instructions are parsed, so the "literate" input 10 2 - 3 + >dup 2 + $swap >dup 0 $swap - $swap !drop works just as well as the minified 10 2 - 3 + > 2 + $ > 0 $ - $ !.

Explanation

As Cabsi is a stack language, the code can implement a stack-based language using its own stack. Thankfully, since the target language is not very complex, there is not a lot of overhead we need.

1 PUSH NULL     REM Stack work delimiter
REM ReadLoop:
2 GETW          REM Read word from STDIN
3 JNL 8         REM If end of input, jump to PrintLoop
4 DUP           REM Duplicate token read
5 YEET          REM And place it on the secondary stack
6 ORD           REM Get Ord(Token[0])
7 GOTO $1       REM Goto the line specified by that ordinal
REM PrintLoop:
8 JNL 64        REM If work delimiter reached, end program
9 PRINT         REM Print top of stack 
10 GOTO 8       REM Jump to PrintLoop
REM If "!" (ord 33):
33 POP          REM Pop top of stack
34 GOTO 2       REM Jump to ReadLoop
REM If "$" (ord 36):
36 SWAP         REM Swap top two on stack
37 GOTO 2       REM Jump to ReadLoop
REM If "+" (ord 43):
43 ADD          REM Add top two on stack
44 GOTO 2       REM Jump to ReadLoop
REM If "-" (ord 45):
45 SUB          REM Subtract top two on stack
46 GOTO 2       REM Jump to ReadLoop
REM If "0" through "9" (ords 48 through 57)
57 YOINK        REM Pull the full representation from the secondary stack
58 MAKEI        REM Cast to integer
59 GOTO 2       REM Jump to ReadLoop
REM If ">" (ord 62)
62 DUP          REM Duplicate top on stack
63 GOTO 2       REM Jump to ReadLoop

Python, 111 bytes

-11 bytes, thanks to emanresu A, uses bytes 0x00-0x03 as commands

def g(s):
 S=[]
 exec(s.translate('S+=[0]; S[-1]+=1; *_,a,b=S;S[-2:]=[b,a-b,a]; S[-1:]=[];'.split()))
 return S

Attempt This Online!


Python, 122 bytes

-8 bytes, thanks to psmears

def f(s):
 S=[]
 for c in s:exec('S+=[0] S[-1]+=1 *_,a,b=S;S[-2:]=[b,a-b,a] S[-1:]=[]'.split()['#*$.'.index(c)])
 return S

Attempt This Online!


Python, 127 bytes (no eval)

taking emanresu A's suggestion to its extreme

def f(s):
 S=[]
 for c in s:
  if"#"==c:S+=[0]
  if"*"==c:S[-1]+=1
  if"$"==c:*S,a,b=S;S+=[b,a-b,a]
  if"."==c:*S,_=S
 return S

Attempt This Online!

It is possible to go down to 3 operations, by creating a new operation ' that pushes 1 and replacing # with ''$.$$.. and * with '$$.$.$$...$$.... But then the pushed integer is no longer clearly determinable from the push integer instruction


Python, 193 bytes

def f(s):
 S=[]
 for c in s:
  if"/"<c<":":S[-1]=10*S[-1]+int(c)
  if"#"==c:S+=[0]
  if"$"==c:*S,a,b=S;S+=[a+b,a-b]
  if":"==c:S+=[S[-1]]
  if","==c:S[-2:]=S[:-3:-1]
  if"."==c:*S,_=S
 return S

Attempt This Online!

Operations:

According to the comments on the sandbox version it is allowed to split operations into smaller suboperations

Atomics:

simulating operations from requirements:

PowerShell Core, 118 bytes

switch -r($args){\D{$a,$b,$s=$s}s{$s=$b,$a+$s}[-+]{$s=,("$b$_$a"|iex)+$s}u{$s=$a,$a,$b+$s}r{$s=,$b+$s}\d{$s=,$_+$s}}$s

Try it online!

Takes an array in parameter containing the instructions, returns an array top to bottom.

Explanation for the previous version, but the idea is still more or less the same:

switch -r($args){                       # for each of the instruction switch as regular expressions:
s{$a,$b,$s=$s;$s=$b,$a+$s}              # s for Swap
u{$b,$s=$s;$s=$b,$b+$s}                 # u for dUp
r{$b,$s=$s}                             # r for dRop
[+-]{$a,$b,$s=$s;$s=,("$b$_$a"|iex)+$s} # + or - for subtract and sum
\d{$s=,$_+$s}                           # to push a number
}                                       # end of the foreach
$s                                      # return the stack

APL (Dyalog Classic), 50 bytes

T←{(⍺⍺2↑⍵),2↓⍵}
p←+/T
m←¯1∘⊥T
x←⊃,⊢
s←⌽T
d←1∘↓
⎕←⎕

Try it online!

Note that the spaces are necessary.

Polish notation is used, i.e. read right-to-left (opposite of the examples in the question), as APL itself is right-to-left. The stack is stored and displayed top-to-bottom (opposite of the examples in the question). E.g. using Polish notation 1 dup 2 + becomes p 2,x 1,⍬ and outputs 3 1

My first time using dops (user-defined operators) in APL. Doesn't seem too useful for golfing, unless you are defining multiple similar functions. T is a dop defined as {(⍺⍺2↑⍵),2↓⍵}. This is a monadic operator that takes a monadic function on the left, and applies it to the first two elements of the array on the right, then catenates with the rest of the array (you can even use this to define new stack operations).

Would love to know how this can be improved upon.

EDIT: There was a bug in my minus function that would negate the whole stack. None of the test cases noticed it though. Fixed now but had to add one byte.

Haskell, 99 bytes

foldl(!)[]
s!c|c<0= -c:s|1<2=[j(+),j(-),\(n:x)->n:n:x,\(a:b:x)->b:a:x,tail]!!c$s
j o(a:b:x)=b`o`a:x

Try it online!

Takes a list of integers as input, where:

Prints the stack as a list with the top element first.


This works by building a list of functions and using the command integer to index into this list. Negative commands are managed separately.

The definitions of dup, swap, and pop are fairly straightforward, but rather than defining two separate functions for sum and subtract I've defined a single function j that takes an operator as an extra argument and applies this operator to the first two elements of the stack. Passing (+) and (-) to j then does the trick.

Vyxal 3, 29 bytes

⸠+⸠-⸠:⸠$⸠_W₈×£?Ṃ(nnK[⌊|O¥iĖ]W

Try it Online! (link is to literate version)

Wow, the SBCS really doesn't do the beauty of literate mode justice:

(. add) (. sub) (. dup) (. swap) (. pop) wrap neg-1 * set-reg
'for (input split-spaces)
  n n
  (is-num?) ? floor : ord get-reg index call
close-all wrap

Command set is:

i -> add
j -> subtract
k -> duplicate
l -> swap
m -> pop
[0-9]+ -> number

Explained

⸠+⸠-⸠:⸠$⸠_W₈×£?Ṃ(nnK[⌊|O¥iĖ]W­⁡​‎‎⁡⁠⁡‏⁠‎⁡⁠⁢‏⁠‎⁡⁠⁣‏⁠‎⁡⁠⁤‏⁠‎⁡⁠⁢⁡‏⁠‎⁡⁠⁢⁢‏⁠‎⁡⁠⁢⁣‏⁠‎⁡⁠⁢⁤‏⁠‎⁡⁠⁣⁡‏⁠‎⁡⁠⁣⁢‏⁠‎⁡⁠⁣⁣‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁡‏⁠‎⁡⁠⁢‏‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁣‏⁠‎⁡⁠⁤‏‏​⁡⁠⁡‌⁤​‎‎⁡⁠⁢⁡‏⁠‎⁡⁠⁢⁢‏‏​⁡⁠⁡‌⁢⁡​‎‎⁡⁠⁢⁣‏⁠‎⁡⁠⁢⁤‏‏​⁡⁠⁡‌⁢⁢​‎‎⁡⁠⁣⁡‏⁠‎⁡⁠⁣⁢‏‏​⁡⁠⁡‌⁢⁣​‎‏​⁢⁠⁡‌⁢⁤​‎‎⁡⁠⁣⁤‏⁠‎⁡⁠⁤⁡‏‏​⁡⁠⁡‌⁣⁡​‎‎⁡⁠⁤⁢‏‏​⁡⁠⁡‌⁣⁢​‎‎⁡⁠⁤⁣‏⁠‎⁡⁠⁤⁤‏‏​⁡⁠⁡‌⁣⁣​‎‎⁡⁠⁢⁡⁡‏⁠‏​⁡⁠⁡‌⁣⁤​‎‎⁡⁠⁢⁡⁢‏⁠‎⁡⁠⁢⁡⁣‏‏​⁡⁠⁡‌⁤⁡​‎‎⁡⁠⁢⁡⁤‏‏​⁡⁠⁡‌⁤⁢​‎‎⁡⁠⁢⁢⁡‏⁠‎⁡⁠⁢⁢⁢‏⁠‏​⁡⁠⁡‌⁤⁣​‎‎⁡⁠⁢⁢⁣‏‏​⁡⁠⁡‌⁤⁤​‎‎⁡⁠⁢⁢⁤‏‏​⁡⁠⁡‌⁢⁡⁡​‎‎⁡⁠⁢⁣⁡‏⁠‎⁡⁠⁢⁣⁢‏‏​⁡⁠⁡‌⁢⁡⁢​‎‎⁡⁠⁢⁣⁣‏‏​⁡⁠⁡‌⁢⁡⁣​‎‏​⁢⁠⁡‌⁢⁡⁤​‎‎⁡⁠⁢⁣⁤‏⁠‎⁡⁠⁢⁤⁡‏‏​⁡⁠⁡‌­
⸠+⸠-⸠:⸠$⸠_W                    # ‎⁡Push a list of:
⸠+                             # ‎⁢  lambda x, y: x + y
  ⸠-                           # ‎⁣  lambda x, y: x - y
    ⸠:                         # ‎⁤  lambda (stack): stack.push(stack[-1])
      ⸠$                       # ‎⁢⁡  lambda (stack): stack[-2], stack[-1] = stack[-1], stack[-2]
        ⸠_                     # ‎⁢⁢  lambda (stack): stack.pop()
# ‎⁢⁣Technically, all these lambdas are monadic (take one argument) so far.
           ₈×                  # ‎⁢⁤Multiply each lambda by -1 to make them operate on the stack
             £                 # ‎⁣⁡And put the stack lambda list in the register
              ?Ṃ               # ‎⁣⁢Split the input on spaces,
                (              # ‎⁣⁣and to each command `n` in that,
                 nn            # ‎⁣⁤  Push two copies of `n`
                   K           # ‎⁤⁡  and test whether the second copy is numeric
                    [⌊         # ‎⁤⁢  if so, simply evaluate and leave on the stack
                      |        # ‎⁤⁣  otherwise:
                       O       # ‎⁤⁤    get the unicode code-point of `n`
                        ¥i     # ‎⁢⁡⁡    index into the register
                          Ė    # ‎⁢⁡⁢    and call the pushed lambda.
# ‎⁢⁡⁣That's the reason the command set was chosen - the ord value mod 5 corresponds to the lambda. Any set of 5 characters could have been chosen, but `i` was the closest to `d`, which I knew to be `100`.
                           ]W  # ‎⁢⁡⁤Close all structures, and wrap the stack when finished.
💎

Created with the help of Luminespire.

Brain-flak, 294 bytes

{(()[]<(({}()))({[()](<{}>)}(){}){{}<>({}{})((<>))}{}(({}()))({[()](<{}>)}(){}){
{}<>([{}]{})((<>))}{}(({}()))({[()](<{}>)}(){}){{}<>(({}))((<>))}{}(({}()))({[()
](<{}>)}(){}){{}<>(({}({}))[({}[{}])])((<>))}{}(({}()))({[()](<{}>)}(){}){{}<>{}
((<>))}{}>[[]]){{}({}[()()()()()]<>)(((<>)))}{}{}{}}<>

Try it Online!

What better way to "Implement a simple stack language" than by using "a simple stack language"! And also a nice excuse to show off a new online interpreter for brain-flak that I have been working on.

Conveniently, a lot of the behavior described in the challenge is built-in to how brain-flak works. For example, Your program/function must output/return the stack after all instructions are performed sequentially is just describing the fundamental operation of brain-flak. And also, we could take each of the listed operations and transliterate it to brain-flak:

# Sum
({}{})

# Subtract
([{}]{})

# Duplicate
(({}))

# Swap
(({}({}))[({}[{}])])

# Pop
{}

Unfortunately, transliteration does not a valid answer make. So we need to do a bit of parsing to figure out which operation to call.

Without clarification from OP (and seeing as many answers have assumed positive input integers), this answer assumes that "push an arbitrary integer" means "an arbitrary positive integer". Here is the input format:

Technically, negative numbers other than 5 listed also work to push a number. 0 does not work.

("TOS" means "Top of Stack")

Commented/readable version:

# While primary stack is not empty...
{
    # Keep track of the stack height +1 at this point...
    (()[]<

        # Increment TOS
        (({}()))

        # TOS != 0
        ({[()](<{}>)}(){})

        # If TOS != 0...
        {
            # OPCode -1: Sum
            # Pop two numbers and push their sum to the alternate stack
            {}
            <>
            ({}{})

            # Go back to main stack and replace TOS with 2 zeros
            ((<>))
        }{}

        # Increment TOS
        (({}()))

        # TOS != 0
        ({[()](<{}>)}(){})

        # If TOS != 0...
        {
            # OPCode -2: subtract
            # Pop two numbers and push their difference to the alternate stack. Second number - first number.
            {}
            <>
            ([{}]{})

            # Go back to main stack and replace TOS with 2 zeros
            ((<>))
        }{}

        # Increment TOS
        (({}()))

        # TOS != 0
        ({[()](<{}>)}(){})

        # If TOS != 0...
        {
            # OPCode -3: duplicate
            # to the alternate stack
            {}
            <>
            (({}))

            # Go back to main stack and replace TOS with 2 zeros
            ((<>))
        }{}

        # Increment TOS
        (({}()))

        # TOS != 0
        ({[()](<{}>)}(){})

        # If TOS != 0...
        {
            # OPCode -4: swap
            # on the alternate stack
            {}
            <>
            (({}({}))[({}[{}])])

            # Go back to main stack and replace TOS with 2 zeros
            ((<>))
        }{}

        # Increment TOS
        (({}()))

        # TOS != 0
        ({[()](<{}>)}(){})

        # If TOS != 0...
        {
            # OPCode -5: pop
            # from the alternate stack
            {}
            <>
            {}

            # Go back to main stack and replace TOS with 2 zeros
            ((<>))
        }{}


    # And see whether any extra values were added to the stack during that last bit
    # Essentially this means: "Push a 1 if none of the opcodes in that snippet matched, otherwise 0"
    # Additionally, if one of the opcodes matched, there will be an extra value on this stack. Remember that, it's important.
    >[[]])

    # If none of the opcodes matched...
    {
        # Pop a useless '1'
        {}

        # Push TOS - 5 onto alternate stack
        # This is the original positive integer that needs to be pushed
        ({}[()()()()()]<>)

        # Push THREE zeroes onto main stack
        (((<>)))
    }

    # Pop three values off the stack
    {}{}{}

}

# Switch to main stack
<>

I'm certain this could be golfed further.

Perl 5 -a, 101 92 bytes

map{/\W$/?eval"\$a[-2]$&=pop\@a":/x/?pop@a:push@a,/d/?$a[-1]:/s/?(pop@a,pop@a):$_}@F;say"@a"

Try it online!

Operations:

Operators and numbers must be separated from each other by at least one space. No error checking was specified, so this code does not do any.

Haskell, 143 bytes

([]#).words
(a:b:s)#(c:r)|c=="s"=(b:a:s)#r|c=="+"=(a+b:s)#r|c=="-"=(b-a:s)#r
(a:s)#(c:r)|c=="d"=(a:a:s)#r|c=="x"=s#r
s#(n:r)=(read n:s)#r
s#_=s

Try it online!

Operations

All commands are separated by spaces, and this code does no error checking.

Go, 321 320 312 bytes

import(."strings";."fmt")
func f(c string)(o[]int){for _,e:=range Fields(c){n,a,b,A:=0,0,0,len(o)-1
B:=A-1
if A>-1{a=o[A]}
if A>0{b=o[B]}
switch e{case"D":o=o[:A]
case"d":o=append(o,a)
case"s":o=append(o[:B],a,b)
case"+":o=append(o[:B],b+a)
case"-":o=append(o[:B],b-a)
default:Sscan(e,&n);o=append(o,n)}}
return}

Attempt This Online!

Very straight-forward split-on-spaces then switch-on-token.

-1 by aliasing indexes and elements. -8 by using the following instruction names:

Pip -p, 50 bytes

V"lPU:".{@a?a(a."POl+:POl 0l@>:2 @l lPK1"^sa)}MJgl

Attempt This Online!

Takes commands as separate command-line arguments. Outputs the final stack as a list, top first. The commands are as follows:

42  push nonzero number
i   push 0
0+  +
0-  -
01  drop
02  dup
03  swap

Explanation

As usual for language interpreters in Pip, this is a translate-and-eval solution. Since l is preinitialized to the empty list, we'll use that to store the stack. The overall logic of the program is:

V"lPU:".{...}MJgl
               g   ; List of command-line args
             MJ    ; Map this function to each and join into a single string:
        {...}      ;   Translation code (see below)
 "lPU:".           ;   Prepend lPU: to each translated command
V                  ; Evaluate
                l  ; Print the final value of l (formatted nicely by -p flag)

Inside the translation function:

@a?a(a."POl+:POl 0l@>:2 @l lPK1"^sa)
@a                                    ; First character of command
  ?                                   ; Is it truthy (nonzero)?
   a                                  ; If so, return unchanged (this is a push command)
    (                             a)  ; Otherwise, treat the command as an index into...
     a."                       "      ;   Prepend the command to this string
                                ^s    ;   and split on spaces

which boils down to the following translation table:

42  lPU:42          ; Push 42 onto l
i   lPU:i           ; Push i (preinitialized to 0) onto l
0+  lPU:0+POl+:POl  ; Pop number, add 0, pop another number, add, push result
0-  lPU:0-POl+:POl  ; Pop number, subtract from 0, pop another number, add, push result
01  lPU:0l@>:2      ; Push 0, then remove first two elements of l
02  lPU:@l          ; Push first element of l
03  lPU:lPK1        ; Remove element at index 1, then push it

flex, 179 bytes

%{
s[9];i;t;
%}
%%
a s[--i-1]+=s[i];
s s[--i-1]-=s[i];
d s[i++]=s[i-1];
x s[i-2]^=s[i-1]^(s[i-1]=s[i-2]);
p --i;
[0-9]+ s[i++]=atoi(yytext);
\n for(t=i;t--;)printf("%d ",s[t]);
%%

Try it online!

Uses:

JavaScript (Node.js), 103 bytes

-2bytes by l4m2

p=>p.split` `.reduce(([a=[],b=[],...S],i)=>[{A:a+b,S:b-a,X:[b,a],P:b}[i]??[1/i?+i:a,a,b],S].flat(2),[])

Attempt This Online!

Operators:

One space between each tokens.

Output is the array where first value is stack top, and last value is stack bottom.

Ruby, 114 bytes

f=->s,*r{s[/.+? ?/]?f[$',*r+(s>?/?[s.to_i]:(q=r.pop;s>?.?[q,q]:s>?-?[]:(w=r.pop;s>?,?[q-w]:s>?+?[q,w]:[q+w])))]:r}

Try it online!

Usage

Charcoal, 48 bytes

WS≡§ι¹+⊞υ⁺⊟υ⊟υ-⊞υ⁻⊟υ⊟υr≔⊟υιu⊞υ↨υ⁰wFE²⊟υ⊞υκ⊞υIιIυ

Try it online! Link is to verbose version of code. Takes a list of newline-terminated words as input (could save two bytes by requiring symbols). Explanation:

WS≡§ι¹

For each input string, switch on its second character.

+⊞υ⁺⊟υ⊟υ
-⊞υ⁻⊟υ⊟υ
r≔⊟υι
u⊞υ↨υ⁰
wFE²⊟υ⊞υκ

Handle +, -, drop, dup and swap respectively.

⊞υIι

Anything else is assumed to be a number to be pushed to the stack.

Iυ

Output the final stack.

Regex (PCRE 2), 104 bytes (60 + 46)

Search:

((1+) (1+) a)|((1+) \5(1+) -)|((1+) :)|((1+) (1+) s)|(1+ ~ ?)

Replacement:

${1:+$2$3:${4:+$6:${7:+$8 $8:${9:+$11 $10:}}}}

Input and output in unary.

Each regex substitution resolves one operation, so you need to repeatedly use the regex to replace until the result doesn't change to get a final output.

Try it online!

No language seems to support the PCRE 2 replacement syntax to allow writing an easy wrapper