started at ; stage 2 at ; ended at
it seems about time to implement brain-flak. submissions may be written in any language.
brain-flak is a stack-based esolang created by a member of the code golf stack exchange some years ago. inspired by the minimalism of brainfuck, it is an expression-based language written only using brackets.
there are 4 types of brackets: ()
, []
, {}
and <>
. each program's brackets must be balanced.
some implementations support line comments with #
or block comments with #{...}
, but this is not a requirement for this challenge.
the language's only data type is the integer, which can be both negative and positive. these integers traditionally have arbitrary size, but you may implement them as signed 64-bit integers if you like.
there are 2 stacks, the 'left' and 'right' stack. when the program starts, the left stack is the 'current' stack. any input to the program starts out on the left stack, with the rightmost values at the top. popping an empty stack is valid and yields 0.
each program in the language executes some side effects and evaluates to an integer. the concatenation XY
of two programs X
and Y
will perform the effects of X
, then Y
, and evaluate to the sum of their results.
first I will describe the behaviour of brackets with nothing inside them, known as nilads:
()
evaluates to 1[]
evaluates to the height of the current stack{}
pops the active stack and evaluates to the value popped<>
toggles which stack is active and evaluates to zerorecall that concatenating programs sums them, so ()()()
evaluates to 3 and {}()
pops the stack and adds one to the value before returning it.
the other 4 operations, monads, take other programs as arguments:
(n)
evaluates n
, pushes it to the current stack and evaluates to the same value[n]
evaluates n
and evaluates to the result's negation{n}
evaluates n
repeatedly as long as the top of the stack is not 0 and evaluates to the sum of all results attained this way.<n>
evaluates n
but evaluates to 0
note that (...)
evaluates to the value pushed, so it can be chained such as in ((()))
to push 1 twice. {...}
evaluates to the sum of all its runs, such that e.g. ({{}})
pushes the sum of the values popped.
your implementation should accept a program and input in the form of a sequence of integers, execute the program and output the contents of the current stack at the end. you do not have to reject invalid programs.
you can download all the entries
written by Anima Libera
submitted at
0 likes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import sys *t,r,a,n,s=[],sys.argv,[[]],lambda p:sum(map(u,p)) for u in a[2:]:t+=int(u), for w in a[1]: if w in"([{<":n+=[], if w in")]}>":*n,e=n;n[-1]+=(w,e), def u(v): c,x=v;z=0 global t,r if")"==c: z=1 if x:z=s(x);t+=z, elif"]"==c:z=-s(x)if x else len(t) elif"}"==c: if x: while(not t)or t[-1]:z+=s(x) elif t:*t,z=t elif x:s(x) else:t,r=r,t return z s(n[0]) print(t) |
written by LyricLy
submitted at
3 likes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | #--------------------------------------------------------------------------------- .SUFFIXES: #--------------------------------------------------------------------------------- ifeq ($(strip $(DEVKITPRO)),) $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro") endif TOPDIR ?= $(CURDIR) include $(DEVKITPRO)/libnx/switch_rules #--------------------------------------------------------------------------------- # TARGET is the name of the output # BUILD is the directory where object files & intermediate files will be placed # SOURCES is a list of directories containing source code # DATA is a list of directories containing data files # INCLUDES is a list of directories containing header files # ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional) # # NO_ICON: if set to anything, do not use icon. # NO_NACP: if set to anything, no .nacp file is generated. # APP_TITLE is the name of the app stored in the .nacp file (Optional) # APP_AUTHOR is the author of the app stored in the .nacp file (Optional) # APP_VERSION is the version of the app stored in the .nacp file (Optional) # APP_TITLEID is the titleID of the app stored in the .nacp file (Optional) # ICON is the filename of the icon (.jpg), relative to the project folder. # If not set, it attempts to use one of the following (in this order): # - <Project name>.jpg # - icon.jpg # - <libnx folder>/default_icon.jpg # # CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder. # If not set, it attempts to use one of the following (in this order): # - <Project name>.json # - config.json # If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead # of a homebrew executable (.nro). This is intended to be used for sysmodules. # NACP building is skipped as well. #--------------------------------------------------------------------------------- TARGET := $(notdir $(CURDIR)) BUILD := build SOURCES := . DATA := data INCLUDES := include APP_TITLE := cg \#39 APP_AUTHOR := You! ICON := icon.jpg #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE CFLAGS := -g -Wall -O2 -ffunction-sections \ $(ARCH) $(DEFINES) CFLAGS += $(INCLUDE) -D__SWITCH__ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions ASFLAGS := -g $(ARCH) LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) LIBS := -lnx #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing # include and lib #--------------------------------------------------------------------------------- LIBDIRS := $(PORTLIBS) $(LIBNX) #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional # rules for different file extensions #--------------------------------------------------------------------------------- ifneq ($(BUILD),$(notdir $(CURDIR))) #--------------------------------------------------------------------------------- export OUTPUT := $(CURDIR)/$(TARGET) export TOPDIR := $(CURDIR) export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) export DEPSDIR := $(CURDIR)/$(BUILD) CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C #--------------------------------------------------------------------------------- ifeq ($(strip $(CPPFILES)),) #--------------------------------------------------------------------------------- export LD := $(CC) #--------------------------------------------------------------------------------- else #--------------------------------------------------------------------------------- export LD := $(CXX) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- export OFILES_BIN := $(addsuffix .o,$(BINFILES)) export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) export OFILES := $(OFILES_BIN) $(OFILES_SRC) export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ -I$(CURDIR)/$(BUILD) export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) ifeq ($(strip $(CONFIG_JSON)),) jsons := $(wildcard *.json) ifneq (,$(findstring $(TARGET).json,$(jsons))) export APP_JSON := $(TOPDIR)/$(TARGET).json else ifneq (,$(findstring config.json,$(jsons))) export APP_JSON := $(TOPDIR)/config.json endif endif else export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) endif ifeq ($(strip $(ICON)),) icons := $(wildcard *.jpg) ifneq (,$(findstring $(TARGET).jpg,$(icons))) export APP_ICON := $(TOPDIR)/$(TARGET).jpg else ifneq (,$(findstring icon.jpg,$(icons))) export APP_ICON := $(TOPDIR)/icon.jpg endif endif else export APP_ICON := $(TOPDIR)/$(ICON) endif ifeq ($(strip $(NO_ICON)),) export NROFLAGS += --icon=$(APP_ICON) endif ifeq ($(strip $(NO_NACP)),) export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp endif ifneq ($(APP_TITLEID),) export NACPFLAGS += --titleid=$(APP_TITLEID) endif ifneq ($(ROMFS),) export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS) endif .PHONY: $(BUILD) clean all #--------------------------------------------------------------------------------- all: $(BUILD) $(BUILD): @[ -d $@ ] || mkdir -p $@ @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- clean: @echo clean ... ifeq ($(strip $(APP_JSON)),) @rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf else @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf endif #--------------------------------------------------------------------------------- else .PHONY: all DEPENDS := $(OFILES:.o=.d) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- ifeq ($(strip $(APP_JSON)),) all : $(OUTPUT).nro ifeq ($(strip $(NO_NACP)),) $(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp else $(OUTPUT).nro : $(OUTPUT).elf endif else all : $(OUTPUT).nsp $(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm $(OUTPUT).nso : $(OUTPUT).elf endif $(OUTPUT).elf : $(OFILES) $(OFILES_SRC) : $(HFILES_BIN) #--------------------------------------------------------------------------------- # you need a rule like this for each extension you use as binary data #--------------------------------------------------------------------------------- %.bin.o %_bin.h : %.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(bin2o) -include $(DEPENDS) #--------------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------------- |
1 2 | install devkitpro packages switch-dev and devkita64, then run make. or use the included .nro if you have no switch see demonstration.mp4 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | typedef struct { enum { One, Height, Pop, Toggle, Open, Push, Negate, Drop, LoopOpen, LoopEnd, } type; size_t target; } Token; #define token(x) ((Token) {.type = (x)}) typedef struct { Token tokens[PROGRAM_SIZE]; size_t tokens_size; } Tokens; Tokens lex(char *program) { Tokens p; p.tokens_size = 0; #define push_token(x) do { p.tokens[p.tokens_size++] = (x); } while (0) size_t open_brackets[PROGRAM_SIZE]; size_t open_brackets_size = 0; for (size_t i = 0; program[i]; i++) { switch (program[i]) { case '(': case '[': case '<': push_token(token(Open)); break; #define match_last(x, a, b) if (p.tokens_size && p.tokens[p.tokens_size-1].type == Open) p.tokens[p.tokens_size-1] = token(a); else push_token(token(b)); case ')': match_last('(', One, Push); break; case ']': match_last('[', Height, Negate); break; case '>': match_last('<', Toggle, Drop); break; case '{': open_brackets[open_brackets_size++] = p.tokens_size; push_token(token(LoopOpen)); break; case '}': open_brackets_size--; if (p.tokens_size && p.tokens[p.tokens_size-1].type == LoopOpen) { p.tokens[p.tokens_size-1] = token(Pop); } else { size_t idx = open_brackets[open_brackets_size]; p.tokens[idx].target = p.tokens_size; push_token(((Token) {.type = LoopEnd, .target = idx})); } break; } } return p; } Stack execute(Stack active, char *program) { Tokens p = lex(program); Stack inactive = {0}; Stack third = {0}; stack_push(&third, 0); for (size_t i = 0; i < p.tokens_size; i++) { Token t = p.tokens[i]; switch (t.type) { case One: (*stack_peek(&third))++; break; case Height: *stack_peek(&third) += active.size; break; case Pop: *stack_peek(&third) += active.size ? stack_pop(&active) : 0; break; case Toggle: Stack tmp = active; active = inactive; inactive = tmp; break; case Open: stack_push(&third, 0); break; case Push: { int64_t x = stack_pop(&third); *stack_peek(&third) += x; stack_push(&active, x); break; } case Negate: { int64_t x = stack_pop(&third); *stack_peek(&third) -= x; break; } case Drop: stack_pop(&third); break; case LoopOpen: if (!active.size || !*stack_peek(&active)) i = t.target; break; case LoopEnd: if (active.size && *stack_peek(&active)) i = t.target; break; } } stack_destroy(&inactive); stack_destroy(&third); return active; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | #define PROGRAM_SIZE 500 #define INPUT_SIZE 10 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include <inttypes.h> #include <switch.h> #include "stack.h" #include "interpreter.h" #define error(s, kind) do { strncpy(string, (s), string_size); return SwkbdTextCheckResult_##kind; } while (0) SwkbdTextCheckResult is_balanced(char* string, size_t string_size) { char stack[500]; size_t height = 0; bool non_bracket = false; for (size_t i = 0; string[i]; i++) { char c = string[i]; switch (string[i]) { case '<': case '{': case '[': case '(': stack[height++] = c; break; #define ensure(x) if (!height) error("Unexpected close bracket.", Bad); else if (stack[--height] != (x)) error("Brackets are mismatched.", Bad); else {} case '>': ensure('<'); break; case ']': ensure('['); break; case ')': ensure('('); break; case '}': ensure('{'); break; case ' ': case '\n': break; default: non_bracket = true; } } if (height) error("Unclosed bracket.", Bad); if (non_bracket) error("Some characters are not brackets and will be ignored.", Prompt); return SwkbdTextCheckResult_OK; } void query_program(char *program) { SwkbdConfig kbd; Result rc = swkbdCreate(&kbd, 0); if (!R_SUCCEEDED(rc)) return; swkbdConfigMakePresetDefault(&kbd); swkbdConfigSetInitialText(&kbd, program); swkbdConfigSetGuideText(&kbd, "Program (sorry, it only lets me do 500 characters...)"); swkbdConfigSetTextCheckCallback(&kbd, is_balanced); char out[PROGRAM_SIZE+1] = {0}; rc = swkbdShow(&kbd, out, sizeof out); if (R_SUCCEEDED(rc)) { strcpy(program, out); } swkbdClose(&kbd); } void query_input(int64_t *n) { SwkbdConfig kbd; Result rc = swkbdCreate(&kbd, 0); if (!R_SUCCEEDED(rc)) return; swkbdConfigMakePresetDefault(&kbd); char initial[INPUT_SIZE+1]; snprintf(initial, sizeof initial, "%" PRId64, *n); swkbdConfigSetInitialText(&kbd, initial); swkbdConfigSetType(&kbd, SwkbdType_NumPad); swkbdConfigSetHeaderText(&kbd, "Enter an input value."); swkbdConfigSetStringLenMax(&kbd, INPUT_SIZE); swkbdConfigSetTextDrawType(&kbd, SwkbdTextDrawType_Line); char out[INPUT_SIZE+1]; rc = swkbdShow(&kbd, out, sizeof out); if (R_SUCCEEDED(rc) && *out) { *n = atoll(out); } swkbdClose(&kbd); } typedef enum { Input, Program, Execute, } Selected; typedef struct { Stack input; Stack output; size_t selected_input; Selected selected; char program[PROGRAM_SIZE+1]; } InputState; void clear(void) { printf("\033[2J"); } void cyan(void) { printf("\033[36;1m"); } void green(void) { printf("\033[32;1m"); } void reset(void) { printf("\033[0m"); } void print_state(InputState *state) { clear(); printf("Move to select\nA to edit value\nY to push input\nX to pop input\n+ to exit\n\nInputs: "); for (size_t i = 0; i < state->input.size; i++) { if (state->selected == Input && i == state->selected_input) cyan(); printf("%" PRId64 " ", state->input.values[i]); reset(); } if (state->selected == Program) cyan(); printf("\nProgram:\n%s\n\n", state->program); reset(); if (state->selected == Execute) cyan(); printf("Execute\n"); reset(); green(); for (size_t i = 0; i < state->output.size; i++) { printf("%" PRId64 " ", state->output.values[i]); } reset(); consoleUpdate(NULL); } void correct_selected(InputState *state) { consoleUpdate(NULL); Selected min = state->input.size ? Input : Program; Selected max = Execute; if (state->selected < min) state->selected = min; if (state->selected > max) state->selected = max; } int main(void) { consoleInit(NULL); padConfigureInput(1, HidNpadStyleSet_NpadStandard); PadState pad; padInitializeDefault(&pad); InputState state = {.selected = Program}; print_state(&state); while (appletMainLoop()) { padUpdate(&pad); u64 down = padGetButtonsDown(&pad); if (down & HidNpadButton_Plus) break; if (down & HidNpadButton_A) { switch (state.selected) { case Input: query_input(&state.input.values[state.selected_input]); break; case Program: query_program(state.program); break; case Execute: stack_destroy(&state.output); state.output = execute(stack_clone(&state.input), state.program); break; } } if (down & HidNpadButton_Y) stack_push(&state.input, 0); if (down & HidNpadButton_X && state.input.size) stack_pop(&state.input); if (down & HidNpadButton_AnyUp) { state.selected--; correct_selected(&state); } if (down & HidNpadButton_AnyDown) { state.selected++; correct_selected(&state); } if (state.selected == Input) { if (down & HidNpadButton_AnyLeft && state.selected_input) state.selected_input--; if (down & HidNpadButton_AnyRight) state.selected_input++; if (state.selected_input >= state.input.size) state.selected_input = state.input.size-1; } if (down) print_state(&state); } stack_destroy(&state.input); stack_destroy(&state.output); consoleExit(NULL); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #include <stdint.h> #include <malloc.h> #include <string.h> typedef struct { int64_t *values; size_t size; size_t capacity; } Stack; int64_t *stack_push(Stack *s, int64_t val) { if (s->size == s->capacity) { s->capacity = s->capacity ? s->capacity * 2 : 64; s->values = realloc(s->values, s->capacity * sizeof (int64_t)); } int64_t *p = &s->values[s->size++]; *p = val; return p; } int64_t *stack_peek(Stack *s) { return &s->values[s->size-1]; } int64_t stack_pop(Stack *s) { return s->values[--s->size]; } Stack stack_clone(Stack *s) { Stack c = *s; c.values = malloc(c.capacity * sizeof (int64_t)); memcpy(c.values, s->values, c.size * sizeof (int64_t)); return c; } void stack_destroy(Stack *s) { free(s->values); } |
written by kimapr
submitted at
2 likes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 | /* * BrainFlak (https://esolangs.org/wiki/Brain-Flak) interpreter in Rust. * Values are signed 64-bit integers or larger. * No syntax errors. Any valid opening bracket can be closed with any valid * closing bracket, but any combination not specified below causes undefined * behavior when evaluated. To improve user experience, this implementation * treats those the same way as {]. Any unclosed brackets, along with their * contents, or extraneous closing brackets are discarded. * * Custom operations: * * {], {...] - Evaluates to 0. The inner expression, if any, is not * evaluated. Can be used for comments, as long as opening brackets inside * are balanced with an equal amount of closing brackets. * * <) - Read a byte from standard input. Evaluates to -1 on EOF, -2 on error, * and a positive integer (the byte) if successful. * * <...) - If the inner expression evaluates to a non-negative value, * truncate it to the size of a byte and write it to the standard output. * Negative values cause undefined behavior, except -1 and -2 which close the * standard output and input, respectively (does not actually work properly * in this implementation as Rust doesn't have built-in constructs to do * this). Evaluates to 0 on success, 1 on failure. */ /* * Copyright (C)2023 Anonymous * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ mod brainflak { #[derive(Copy, Clone, PartialEq, Eq)] enum BracketType { Round, Square, Curly, Angle, } #[derive(Copy, Clone)] enum BracketSide { Opening, Closing, } #[derive(Copy, Clone)] struct Bracket { btype: BracketType, side: BracketSide, } use BracketSide::*; use BracketType::*; struct Func { btype: BracketType, monad: bool, addr: usize, } impl TryFrom<u8> for Bracket { type Error = (); fn try_from(c: u8) -> Result<Self, ()> { match c { b'(' => Ok(Self { btype: Round, side: Opening, }), b'[' => Ok(Self { btype: Square, side: Opening, }), b'{' => Ok(Self { btype: Curly, side: Opening, }), b'<' => Ok(Self { btype: Angle, side: Opening, }), b')' => Ok(Self { btype: Round, side: Closing, }), b']' => Ok(Self { btype: Square, side: Closing, }), b'}' => Ok(Self { btype: Curly, side: Closing, }), b'>' => Ok(Self { btype: Angle, side: Closing, }), _ => Err(()), } } } pub struct Program { code: Box<[u8]>, } mod ops { pub const NOP: u8 = 0; pub const ONE: u8 = 1; pub const HEIGHT: u8 = 2; pub const POP: u8 = 3; pub const SWAP: u8 = 4; pub const NEW: u8 = 5; pub const PUSH: u8 = 6; pub const NEGATE: u8 = 7; pub const DROP: u8 = 8; pub const SAVE: u8 = 9; pub const ZRET: u8 = 10; pub const READ: u8 = 11; pub const WRITE: u8 = 12; } use ops::*; use std::io; use std::io::ErrorKind; use std::io::{Read, Write}; use std::mem; impl Program { fn backtrack(code: &mut Vec<u8>, f: &Func) { code.truncate(f.addr); } pub fn run(&self, input: Vec<i64>, stdin: impl Read, stdout: impl Write) -> Vec<i64> { let mut active = input; let mut passive: Vec<i64> = Vec::new(); let mut data: Vec<i64> = Vec::new(); let mut rets: Vec<u32> = Vec::new(); let mut exec: u32 = 0; let mut stdin = Some(stdin); let mut stdout = Some(stdout); let clen = self.code.len() as u32; while exec < clen { let c = self.code[exec as usize]; match c { SAVE | ZRET => match c { SAVE => { rets.push(exec + 5); data.push(0); exec = u32::from_le_bytes( self.code[((exec + 1) as usize)..((exec + 5) as usize)] .try_into() .unwrap(), ); } ZRET => { if active.last().map(|v| *v).unwrap_or(0) != 0 { exec = *rets.last().unwrap(); } else { let v = data.pop().unwrap(); data.last_mut().map(|pc| *pc += v); rets.pop().unwrap(); exec += 1; }; } _ => unreachable!(), }, NEW => { data.push(0); exec += 1; } NOP | ONE | HEIGHT | POP | SWAP | READ => { let v = match c { NOP => 0, ONE => 1, HEIGHT => active.len() as i64, POP => active.pop().unwrap_or(0), SWAP => { mem::swap(&mut active, &mut passive); 0 } READ => { let mut buffer = [0; 1]; match stdin.as_mut() { Some(stdin) => match stdin.read_exact(&mut buffer) { Ok(_) => buffer[0] as i64, Err(e) => match e.kind() { ErrorKind::UnexpectedEof => -1, _ => -2, }, }, None => -2, } } _ => unreachable!(), }; data.last_mut().map(|pc| *pc += v); exec += 1; } PUSH | NEGATE | DROP | WRITE => { let mut v = data.pop().unwrap(); match c { PUSH => active.push(v), NEGATE => v = -v, DROP => v = 0, WRITE => { v = match v { v if v >= 0 => match stdout.as_mut() { Some(stdout) => match stdout.write_all(&[v as u8]) { Ok(_) => 0, Err(_) => 1, }, None => 1, }, -1 => stdin.take().map_or(1, |_| 0), -2 => stdout.take().map_or(1, |_| 0), _ => 1, } } _ => unreachable!(), } data.last_mut().map(|pv| *pv += v); exec += 1; } _ => panic!(), } } active } pub fn new(file: impl Read) -> io::Result<Self> { let mut funcs: Vec<Func> = Vec::new(); let mut code: Vec<u8> = Vec::new(); for b in file.bytes().filter_map(|c| match c { Ok(c) => Bracket::try_from(c).ok().map(|c| Ok(c)), Err(e) => Some(Err(e)), }) { let b = b?; match b.side { Opening => { funcs.last_mut().map(|f| { if f.monad { return; } f.monad = true; if f.btype == Curly { code.extend([0; 4]); } }); funcs.push(Func { btype: b.btype, monad: false, addr: code.len(), }); code.push(0); } Closing => 'm: { let f = if let Some(f) = funcs.pop() { f } else { break 'm; }; 'e: { match f.monad { false => { code[f.addr] = match (f.btype, b.btype) { (Round, Round) => ONE, (Square, Square) => HEIGHT, (Curly, Curly) => POP, (Angle, Angle) => SWAP, (Angle, Round) => READ, _ => break 'e Err(()), } } true => { if let (Curly, Curly) = (f.btype, b.btype) { code[f.addr] = SAVE; let addr = &(code.len() as u32).to_le_bytes(); code[(f.addr + 1)..(f.addr + 5)].copy_from_slice(addr); code.push(ZRET); } else { code[f.addr] = NEW; code.push(match (f.btype, b.btype) { (Round, Round) => PUSH, (Square, Square) => NEGATE, (Angle, Angle) => DROP, (Angle, Round) => WRITE, _ => break 'e Err(()), }); } } } Ok(()) } .err() .map(|_| Self::backtrack(&mut code, &f)); } } if code.len() > (u32::MAX as usize) { panic!("Program too large"); } } funcs.first().map(|f| Self::backtrack(&mut code, &f)); code.shrink_to_fit(); Ok(Self { code: code.into_boxed_slice(), }) } } } pub use brainflak::*; use std::env; use std::fs::File; use std::io; use std::str::FromStr; fn main() { let mut args = env::args(); args.next(); let pfile = File::open(args.next().expect("invalid argument")).expect("failed to open file"); let mut inputs = Vec::new(); for p in args { inputs.push(i64::from_str(&p).expect("invalid argument")); } let program = Program::new(pfile).expect("fail"); for i in program.run(inputs, io::stdin(), io::stdout()) { println!("{}", i); } } |
written by GNU Radio Shows
submitted at
4 likes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | bf p i = reverse (run 0 p [] [0] (reverse i) []) run 0 ('(':')':p) r (n:t) m a = run 0 p r ((n+1):t) m a run 0 ('[':']':p) r (n:t) m a = run 0 p r ((n+length m):t) m a run 0 ('{':'}':p) r (n:t) (x:m) a = run 0 p r ((n+x):t) m a run 0 ('{':'}':p) r t m a = run 0 p r t m a run 0 ('<':'>':p) r t m a = run 0 p r t a m run 0 ('(':p) r t m a = run 0 p r (0:t) m a run 0 ('[':p) r t m a = run 0 p r (0:t) m a run o ('{':p) r t m a = run (o+1) p (p:r) (0:t) m a run 0 ('<':p) r t m a = run 0 p r (0:t) m a run 0 (')':p) r (x:n:t) m a = run 0 p r ((n+x):t) (x:m) a run 0 (']':p) r (x:n:t) m a = run 0 p r ((n-x):t) m a run 0 ('>':p) r (_:t) m a = run 0 p r t m a run 0 ('}':p) (_:r) (x:n:t) (0:m) a = run 0 p r ((n+x):t) (0:m) a run 0 ('}':_) (p:r) t m a = run 0 p (p:r) t m a run 1 ('}':p) r t m a = run 0 ('}':p) r t m a run o ('}':p) (_:r) (_:t) m a = run (o-1) p r t m a run o (_:p) r t m a = run o p r t m a run _ [] _ _ m _ = m |
written by ultlang
submitted at
1 like
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | function entry(Source, Input){ InputStack = Input // This is the "left stack", also known as the "stack not on the Right". Input goes here. kcatStupnI = []; // This is the "right stack", also known as the "stack on the Right". The evil twin of the input stack. Active = 1.0; // Left stack Active: 1 is at the Left of the decimal point. FormattedSource = Source.replace(/(\[\]|\(\)|{\}|\<>)/g, nilad => ({"()":"○","[]":"⎕","{}":"⍬","<>":"♢"}[nilad])); // APL symbols look good and Brain-Flak was simpler to implement this way to me. console.log(FormattedSource); // Bask in the glory of APL symbols. function run(Snippet) { let Pointer = 0 let EValue = []; // Short for "evaluated value". while (Pointer * Pointer != Math.pow(Snippet.length,2)) { // Are we done with the snippet? switch (Snippet[Pointer]) { case "○": EValue.push(1); break// case "⎕": EValue.push((Active==1.0?InputStack:kcatStupnI).length); break// case "⍬": popped = (Active==1.0?InputStack:kcatStupnI).pop(); EValue.push(typeof popped == "undefined" ? 0 : popped); // According to the specification, // Brain-Flak should return 0 if the active stack is empty. break// case "♢": Active = (Active == 1.0 ? 0.1 : 1.0) // Toggles which stack is active. EValue.push(0); break// case "(": { let NestingLevel = 1 let EnclosedSnippet = "" while (NestingLevel != 0) { Pointer = Pointer + (Pointer?Pointer / Pointer:1) EnclosedSnippet += Snippet[Pointer] if (Snippet[Pointer] == "(") {NestingLevel += 1} else if (Snippet[Pointer] == ")") {NestingLevel -= 1} } EnclosedSnippet = EnclosedSnippet.substring(0, EnclosedSnippet.length - 1); result = run(EnclosedSnippet); EValue.push(result); (Active==1.0?InputStack:kcatStupnI).push(result); } ;break// case "<": { let NestingLevel = 1 let EnclosedSnippet = "" while (NestingLevel != 0) { Pointer = Pointer + (Pointer?Pointer / Pointer:1) EnclosedSnippet += Snippet[Pointer] if (Snippet[Pointer] == "<") {NestingLevel += 1} else if (Snippet[Pointer] == ">") {NestingLevel -= 1} } EnclosedSnippet = EnclosedSnippet.substring(0, EnclosedSnippet.length - 1); run(EnclosedSnippet) EValue.push(0) } ;break// case "{": { let NestingLevel = 1 let EnclosedSnippet = "" while (NestingLevel != 0) { Pointer = Pointer + (Pointer?Pointer / Pointer:1) EnclosedSnippet += Snippet[Pointer] if (Snippet[Pointer] == "{") {NestingLevel += 1} else if (Snippet[Pointer] == "}") {NestingLevel -= 1} } EnclosedSnippet = EnclosedSnippet.substring(0, EnclosedSnippet.length - 1); let EValueInCurlyBraces = [] while ((Active==1.0?InputStack:kcatStupnI)[(Active==1.0?InputStack:kcatStupnI).length-1] != 0 || (Active==1.0?InputStack:kcatStupnI).length == 0) { EValueInCurlyBraces.push(run(EnclosedSnippet)) } EValue.push( EValueInCurlyBraces.reduce((x, y) => x+y, 0)) } ;break// case "[": { let NestingLevel = 1 let EnclosedSnippet = "" while (NestingLevel != 0) { Pointer = Pointer + (Pointer?Pointer / Pointer:1) EnclosedSnippet += Snippet[Pointer] if (Snippet[Pointer] == "[") {NestingLevel += 1} else if (Snippet[Pointer] == "]") {NestingLevel -= 1} } EnclosedSnippet = EnclosedSnippet.substring(0, EnclosedSnippet.length - 1); EValue.push(0 - run(EnclosedSnippet)) } ;break// } Pointer = Pointer + (Pointer?Pointer / Pointer:1) // There is probably no better way to increment a variable. } let evalue_final_FINAL_jpg = EValue.reduce((x, y) => x+y, 0) return evalue_final_FINAL_jpg; } run(FormattedSource) console.log(Active==1.0?InputStack:kcatStupnI) // Shows the active stack. return (Active==1.0?InputStack:kcatStupnI) } /* // Example program from the Esolangs wiki. // This program computes [number on the stack not on the Right] steps of the Fibonacci sequence. entry("<>((()))<>{({}[()])<>({}<>)<>(({})<>({}<>))<>}<>{}{}", [50]); */ |
1 2 3 4 5 6 7 8 | (((( ]]]] <<<< }}}}} (( ]] ]]<< <<}} (( ]] ]]<< <<}}}} (((( ]]]] <<<< }}}}} ))))[[ [[>>>>> {{{{ )) [[ [[>> {{ )) ))[[ [[>>>> {{ )))) [[[[ >>>>>{{{{sing |
written by olus2000
submitted at
1 like
1 | // Code by SoundOfSpouting#6980 (UID: 151149148639330304) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | ! // Code by SoundOfSpouting#6980 (UID: 151149148639330304) ! See http://factorcode.org/license.txt for BSD license. USING: help.markup help.syntax kernel strings urls ; IN: brain-flak HELP: unclosed-brain-flak-expression { $values { "program" object } } { $description "Throws an " { $link unclosed-brain-flak-expression } " error." } { $error-description "Thrown during brain-flak compilation if an opened subexpression doesn't have a closing bracket." } ; HELP: mismatched-brain-flak-brackets { $values { "program" object } { "character" object } } { $description "Throws an " { $link mismatched-brain-flak-brackets } " error." } { $error-description "Thrown if a bracket is closed with a bracket that doesn't match." } ; HELP: leftover-program-after-compilation { $values { "program" object } { "leftover" object } } { $description "Throws an " { $link leftover-program-after-compilation } " error." } { $error-description "Thrown if excessive closing brackets are encountered during compilation." } ; HELP: b-f" { $syntax "b-f\"({}[]){<>()}\"" } { $description "Syntax for a brain-flak program. It will take a sequence, run the program with the sequence as the initial active stack, and replace the sequence with the final active stack. Syntax and semantics of brain-flak are explained in" { $link "brain-flak" } . } { $errors "Throws an error when the parsed string is not a correct brain-flak program" } { $examples { $example "USING: brain-flak prettyprint ;" "{ 2 1 3 7 } b-f\"({{}})\" ." "{ 13 }" } { $example "USING: brain-flak prettyprint ;" "{ 1 2 } b-f\"(({}({}))[({}[{}])])\" ." "{ 2 1 }" } } { $see-also compile-brain-flak } ; HELP: compile-brain-flak { $values { "string" string } { "quote" { $quotation ( seq -- seq ) } } } { $description "Compiles a brain-flak program in" { $snippet "string" } "into a quotation that can be run on a sequence of numbers and will return a sequence of numbers. Syntax and semantics of brain-flak are explained in" { $link "brain-flak" } "." } { $errors "Throws an error when the string is not a correct brain-flak program" } { $examples { $example "USING: brain-flak kernel prettyprint ;" "\"({{}})\" compile-brain-flak" "{ 2 1 3 7 } swap call( seq -- seq ) ." "{ 13 }" } { $example "USING: brain-flak kernel prettyprint ;" "\"(({}({}))[({}[{}])])\" compile-brain-flak" "{ 1 2 } swap call( seq -- seq ) ." "{ 2 1 }" } } { $see-also \ b-f" } ; ARTICLE: "brain-flak" "Introduction to brain-flak" { { $url URL"https://esolangs.org/wiki/Brain-Flak" "Brain-flak" } " is a stack-based esoteric language designed by Programming Puzzles and Code-Golf user " { $url URL"https://codegolf.stackexchange.com/users/31716/djmcmayhem" "DjMcMayhem" } } . The name is a cross between "\"brainfuck\"" , which was a big inspiration for the language, and "\"flak-overstow\"" , since the language is confusing and stack-based. { $heading "Overview" } Brain-flak is an expression-based language written only using brackets, which must be balanced. Any other character will be ignored. Its only data type is a signed integer, which in this implementation has unbounded size. { $nl } There are two stacks, one of which is considered the { $strong "active" } stack at each point of the execution. Programs start with the active stack initialised with the input data and inactive stack empty, and return the active stack when finished. Popping from an empty stack yields 0. { $nl } Each expression in brain-flak executes some side-effects on the stacks and evaluates to a number. Concatenation of expressions performs their side-effects from left to right and evaluates to a sum of their evaluations. { $heading "Functions" } There are two types of functions in brain-flak: nilads, that are brackets without any contents, and monads, which are non-empty bracketed subexpressions. { $nl } Nilads: { $list { { $snippet "()" } " evaluates to 1" } { { $snippet "[]" } " evaluates to the height of the active stack" } { { $snippet "{}" } " pops the active stack and evaluates to the popped value" } { { $snippet "<>" } " swaps active and inactive stack and evaluates to 0" } } Recall that concatenating expressions sums their values, so { $snippet "()()()" } will evaluate to 3, and { $snippet "{}()" } will pop from the active stack and evaluate to one more than the popped value. { $nl } Monads: { $list { { $snippet "(X)" } " evaluates " { $snippet "X" } ", pushes the result on the stack and evaluates to the same value" } { { $snippet "[X]" } " evaluates " { $snippet "X" } " and evaluates to its negation" } { { $snippet "{X}" } " evaluates " { $snippet "X" } " in a loop as long as top of the active stack is not 0 and evaluates to the sum of all results" } { { $snippet "<X>" } " evaluates " { $snippet "X" } ", discards the result and evaluates to zero" } } For example program { $snippet "([(()()())])" } will push numbers 3 and -3 to the stack, and program { $snippet "({{}})" } will replace values on the stack until a zero with their sum. { $examples "Examples of brain-flak programs can be seen on its " { $url URL"https://github.com/DJMcMayhem/Brain-Flak/wiki/Stack-Operations" "github wiki" } "." } { $heading "Vocabulary" } The { $vocab-link "brain-flak" } vocabulary provides a brain-flak to Factor compiler in two words: { $subsections compile-brain-flak POSTPONE: b-f" } These offer a way to compile brain-flak strings into quotations and embed them directly in code. Programs compiled this way will take a sequence for their initial active stack and return a sequence of the same type representing the "final" active stack. ; ABOUT: "brain-flak" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | ! // Code by SoundOfSpouting#6980 (UID: 151149148639330304) ! See http://factorcode.org/license.txt for BSD license. USING: accessors brain-flak combinators.short-circuit kernel strings tools.test ; IN: brain-flak.tests { { } } [ { } "" compile-brain-flak call ] unit-test { { } } [ { } b-f"" ] unit-test { { } } [ { } "X" compile-brain-flak call ] unit-test { { } } [ { } b-f"X" ] unit-test { { } } [ { } "()" compile-brain-flak call ] unit-test { { } } [ { } b-f"()" ] unit-test { { } } [ { } "[]" compile-brain-flak call ] unit-test { { } } [ { } b-f"[]" ] unit-test { { } } [ { } "{}" compile-brain-flak call ] unit-test { { } } [ { } b-f"{}" ] unit-test { { } } [ { } "<>" compile-brain-flak call ] unit-test { { } } [ { } b-f"<>" ] unit-test { { 1 } } [ { } "(())" compile-brain-flak call ] unit-test { { 1 } } [ { } b-f"(())" ] unit-test { { 1 } } [ { } "((X))" compile-brain-flak call ] unit-test { { 1 } } [ { } b-f"((X))" ] unit-test { { 1 } } [ { } "(X()X)" compile-brain-flak call ] unit-test { { 1 } } [ { } b-f"(X()X)" ] unit-test { { 2 } } [ { } "(()())" compile-brain-flak call ] unit-test { { 2 } } [ { } b-f"(()())" ] unit-test { { 2 2 } } [ { } "((()()))" compile-brain-flak call ] unit-test { { 2 2 } } [ { } b-f"((()()))" ] unit-test { { 0 } } [ { } "([])" compile-brain-flak call ] unit-test { { 0 } } [ { } b-f"([])" ] unit-test { { 1 2 3 3 } } [ { 1 2 3 } "([])" compile-brain-flak call ] unit-test { { 1 2 3 3 } } [ { 1 2 3 } b-f"([])" ] unit-test { { 1 2 2 3 } } [ { 1 2 } "([])([])" compile-brain-flak call ] unit-test { { 1 2 2 3 } } [ { 1 2 } b-f"([])([])" ] unit-test { { 0 } } [ { } "({})" compile-brain-flak call ] unit-test { { 0 } } [ { } b-f"({})" ] unit-test { { 1 2 } } [ { 1 2 } "({})" compile-brain-flak call ] unit-test { { 1 2 } } [ { 1 2 } b-f"({})" ] unit-test { { 1 } } [ { 1 2 } "{}" compile-brain-flak call ] unit-test { { 1 } } [ { 1 2 } b-f"{}" ] unit-test { { 0 } } [ { 1 2 } "(<>)" compile-brain-flak call ] unit-test { { 0 } } [ { 1 2 } b-f"(<>)" ] unit-test { { 1 2 0 } } [ { 1 2 } "(<><>)" compile-brain-flak call ] unit-test { { 1 2 0 } } [ { 1 2 } b-f"(<><>)" ] unit-test { { 0 } } [ { } "([[]])" compile-brain-flak call ] unit-test { { 0 } } [ { } b-f"([[]])" ] unit-test { { 1 2 -2 } } [ { 1 2 } "([[]])" compile-brain-flak call ] unit-test { { 1 2 -2 } } [ { 1 2 } b-f"([[]])" ] unit-test { { 0 } } [ { } "([()]())" compile-brain-flak call ] unit-test { { 0 } } [ { } b-f"([()]())" ] unit-test { { 0 } } [ { } "({<>})" compile-brain-flak call ] unit-test { { 0 } } [ { } b-f"({<>})" ] unit-test { { 4 3 2 1 0 6 } } [ { 4 } "({(({})[()])})" compile-brain-flak call ] unit-test { { 4 3 2 1 0 6 } } [ { 4 } b-f"({(({})[()])})" ] unit-test { { 0 } } [ { } "(<()()()>)" compile-brain-flak call ] unit-test { { 0 } } [ { } b-f"(<()()()>)" ] unit-test { { 1 0 } } [ { 1 2 } "(<<>({}())>)" compile-brain-flak call ] unit-test { { 1 0 } } [ { 1 2 } b-f"(<<>({}())>)" ] unit-test [ "{" compile-brain-flak call ] [ { [ unclosed-brain-flak-expression? ] [ program>> "{" = ] } 1&& ] must-fail-with [ "{>" compile-brain-flak call ] [ { [ mismatched-brain-flak-brackets? ] [ program>> "{>" = ] } 1&& ] must-fail-with [ "{}>" compile-brain-flak call ] [ { [ leftover-program-after-compilation? ] [ program>> "{}>" = ] [ leftover>> >string ">" = ] } 1&& ] must-fail-with |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | ! // Code by SoundOfSpouting#6980 (UID: 151149148639330304) ! See http://factorcode.org/license.txt for BSD license. USING: accessors assocs combinators combinators.short-circuit kernel math sequences sets splitting strings.parser vectors ; IN: brain-flak << ALIAS: ' CHAR: >> ERROR: unclosed-brain-flak-expression program ; ERROR: mismatched-brain-flak-brackets program ; ERROR: leftover-program-after-compilation program leftover ; <PRIVATE : matches ( a b -- ? ) { { ' ( ' ) } { ' [ ' ] } { ' { ' } } { ' < ' > } { ' ) ' ( } { ' ] ' [ } { ' } ' { } { ' > ' < } } at = ; : glue ( a stack2 stack1 b -- a+b stack2 stack1 ) roll + -rot ; : (()) ( ret stack2 stack1 -- ret stack2 stack1 ) 1 glue ; : ([]) ( ret stack2 stack1 -- ret stack2 stack1 ) dup length glue ; : ({}) ( ret stack2 stack1 -- ret stack2 stack1 ) dup [ pop glue ] unless-empty ; : (<>) ( ret stack2 stack1 -- ret stack2 stack1 ) swap ; : ()) ( ret stack2 stack1 quot -- ret stack2 stack1 ) 0 -roll call rot [ suffix! ] keep glue ; inline : (]) ( ret stack2 stack1 quot -- ret stack2 stack1 ) 0 -roll call rot neg glue ; inline : (}) ( ret stack2 stack1 quot -- ret stack2 stack1 ) 0 -roll [ dup { [ empty? ] [ last 0 = ] } 1|| ] swap until rot glue ; inline : (>) ( ret stack2 stack1 quot -- ret stack2 stack1 ) 0 -roll call rot drop ; inline : compile-bf-subexpr ( vec string-like -- vec string-like ) [ { { [ dup empty? ] [ f ] } { [ dup first ")]}>" in? ] [ f ] } { [ "()" ?head-slice ] [ [ \ (()) suffix! ] dip t ] } { [ "[]" ?head-slice ] [ [ \ ([]) suffix! ] dip t ] } { [ "{}" ?head-slice ] [ [ \ ({}) suffix! ] dip t ] } { [ "<>" ?head-slice ] [ [ \ (<>) suffix! ] dip t ] } [ 0 <vector> swap [ rest-slice ] [ first ] bi [ compile-bf-subexpr [ [ ] clone-like suffix! ] dip [ dup empty? [ dup seq>> unclosed-brain-flak-expression ] [ rest-slice ] if ] [ ?first ] bi ] dip over matches [ over seq>> mismatched-brain-flak-brackets ] unless { { ' ) [ [ \ ()) suffix! ] dip ] } { ' ] [ [ \ (]) suffix! ] dip ] } { ' } [ [ \ (}) suffix! ] dip ] } { ' > [ [ \ (>) suffix! ] dip ] } } case t ] } cond ] loop ; PRIVATE> : compile-brain-flak ( string -- quote ) [ "()[]{}<>" in? ] filter dup V{ dup V{ } clone-like 0 0 <vector> rot } clone swap compile-bf-subexpr [ overd leftover-program-after-compilation ] unless-empty { 2nip swap clone-like } append! [ ] clone-like nip ; SYNTAX: b-f" parse-string compile-brain-flak append! ; |
1 | A Brain-flak to Factor compiler |
1 2 3 4 | brain-flak languages parsing syntax |
written by razetime
submitted at
1 like
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | # Brain-flak interpreter in Python # soon to be added: proper debugging capability # Flakhead society approved def read_until_matching(s, start): stack_height = 0 for idx, char in enumerate(s[start + 1 :]): match char: case "{": stack_height += 1 case "}": stack_height -= 1 if stack_height == -1: return idx + start + 1 return False class Interpreter: left = [] right = [] main = [] active = left index = 0 current_value = 0 running = False def reset(self): self.left = [] self.right = [] self.main = [] self.active = self.left self.index = 0 self.current_value = 0 self.running = False def __init__(self, source): self.source = source def step(self): if not self.running: return False is_nilad = True match self.source[self.index : self.index + 2]: case "()": self.current_value += 1 case "[]": self.current_value += len(self.active) case "{}": if self.active: self.current_value += self.active.pop() case "<>": self.active = self.right if self.active == self.left else self.left case _: is_nilad = False if is_nilad: self.index += 2 else: match self.source[self.index]: case "(": self.main.append(("(", self.current_value, self.index)) self.current_value = 0 case "[": self.main.append(("[", self.current_value, self.index)) self.current_value = 0 case "{": self.main.append(("{", 0, self.index)) new_index = read_until_matching(self.source, self.index) if not self.active or self.active[-1] == 0: self.main.pop() self.index = new_index case "<": self.main.append(("<", self.current_value, self.index)) self.current_value = 0 case ")": _, inc, _ = self.main.pop() self.active.append(self.current_value) self.current_value += inc case "]": _, inc, _ = self.main.pop() self.current_value *= -1 self.current_value += inc case "}": _, inc, idx = self.main.pop() self.index = idx - 1 self.current_value += inc case ">": _, inc, _ = self.main.pop() self.current_value = inc self.index += 1 if self.index >= len(self.source): self.running = False return True def run(self, input): self.reset() self.left = input self.active = self.left self.running = True while self.running: self.step() return self.active for code, input in [ ("(([]){[{}]{}([])}{})", [5, 69, 700, 8214]), # sum stack ("({}{})", [0x12, 123]), # add two numbers ("(())", []), # 1 ("<>((()))<>{({}[()])<>({}<>)<>(({})<>({}<>))<>}<>{}{}", [9]), # Fibonacci # ('(()()()()()()())(())(()()()()()()())(()()()()()()()())(()()())(()()()())(()())(()()())(()()()())(()()()()()()()())(()()())(()()()())(())(()()()()())(()()()()()())(()())(()()()()()()())(())(()()()()()()())(()()()()()()()())(()()()()())(())(()())(()()()()()())(()()())(())(())(()()()()())(()()()()()()())(()()()()()()()())(()()()()()())(())(()())(()()())(())(())(())(())(())(())(())(())(())(()())(())(()())(())(()())(())(()())(())(()())(()())(()()()()()()())(()()()()()()()())(()())(()()()()()()())(()()()()()()()())(()())(()()()()()()())(()()()()()()()())(()())(()()())(()()()())(()())(()())(())(()())(()())(()())(()()()())(()())(()()())(()()()())(()())(()()()()()()())(())(()()()()()()())(()()()()()()()())(())(()())(()()())(())(()()()()()()())(()()()()()()()())(())(()())(()())(()()()())(()())(()()()()()()())(())(()()()()()()())(()()()()()()()())(())(()())(()()())(())(()()()()()()())(()()()()()()()())(())(())(())(())(()())(())(()())(())(()())(()())(()())(()()()()()()())(()()()()()()()())(()()()()()()())(()()()()()()()())(()())(()()()()()()())(()()()()()()()())(())(()())(()())(()()()())(()())(()()()()()()())(())(()()()()()()())(()()()()()()()())(())(()())(()()())(())(()()()()()()())(()()()()()()()())(())(()())(())(()())(()())(()()()())(()())(()()()()()()())(())(()()()()()()())(()()()()()()()())(())(()())(()()())(())(()()()()()()())(()()()()()()()())(())(())(())(())(()())(())(()())(())(()())(()())(()()()()()()())(()()()()()()()())(())(()())(()())(()()()()()()())(()()()()()()()())(()())(()()()()()()())(()()()()()()()())(())(()())(()())(()()()())(()())(()()()()()()())(())(()()()()()()())(()()()()()()()())(())(()())(()()())(())(()()()()()()())(()()()()()()()())(())(()())(())(()())(()())(()()()())(()())(()()()()()()())(())(()()()()()()())(()()()()()()()())(())(()())(()()())(())(()()()()()()())(()()()()()()()())(())(())(())(())(()())(())(()())(())(()())(())(()())(())(()())(()())(()())(()()()()()()())(()()()()()()()())(()()()()()()())(()()()()()()()())(()())(()()()()()()())(()()()()()()()())(()())(()()()())(()())(()()()()()()())(())(()()())(()()()()()()())(()()()()()()()())(())(()()()()()()())(()()()()()()()())(())(()())(())(()())(()())(()()()())(()())(()()()()()()()())(()()()()()()()())(()()()()()()()())(()()()()()()()())(()()()()()()()())(()()()()()()()())(()()()()()()()())(()()()()()()())(()()()()()()()())(())(()()()()())(()()()()()())(()()())(())(()()()()()()())(()()()()()()()())(()()())(()()()()()()())(())(()()()()()()())(()()()()()()()())(()()())(()()()())(()())(()()())(()()()())(()()()()()()()())(()()())(()()()())(()()()())(()())(()()()())(()())(()()()()()()())(())(()()()()()()())(()()()()()()()())(()()()()())(())(()())(()()()()()())(()()())(())(()()()()()()())(()()()()()()()())(()()())(()()()())(()())(()()())(()()()())(()()()())(()())(()()()()()()()())(()()()()()()())(()()()()()()()())(()()()()()()())(())(()()()()()()())(()()()()()()()())(())(()())(()()())(())(())(())(()()()()()()())(()()()()()()()())(()()()()())(())(()())(()()()()()())(()())(())(()())(()())(()())(()()()())(()())(()()()()()()()())(()()()()()()())(()()()()()()()())(()()())(()()()())(()()()())(()())(()()()()()()()())(()()()()()()())(()()()()()()()())(()()()()()()())(()()())(()()()())(())(()()()()()()())(()()()()()()()())(()()())(()()()())(()())(()()()()()()()()){({}<>)<>}<>([]){({}[()]<(([{}]()<((((((((()()()()()){}){}){})<>))()))>)<>){({}()<({}())>){({}()<({}(((()()())){}{}){}())>){({}()<({}()())>){({}()<({}(((()()()){}()){}){}())>){({}()<({}()())>){({}()<({}(((()()()()())){}{}){})>){(<{}({}()())>)}}}}}}}{}([]<({}<{({}<>)<>}<>>)>){({}[()]<({}<>)<>>)}{}{({}()<((({}[()])()))>)}{}<>>)}{}{<>({}<>)}', []) ]: print(Interpreter(code).run(input)) |
written by Olivia
submitted at
5 likes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-- ## --} import Text.Megaparsec (parse, errorBundlePretty, between, choice, many, sepBy, Parsec, eof) {-- ## ## --} {-- --} ; import Control.Lens ((<&>), uncons, uses, (%=), (.=), _1) {-- ## ## ### --} {-- ###### --} ; import Text.Megaparsec.Char (char, newline, space1) {-- ##### ### ### --} {-- #### ## ##### --} ; import Text.Megaparsec.Char.Lexer (decimal, signed) {-- ## #### ## #### --} {-- ### ## ### ### --} ; import Control.Monad.State (execState) {-- ## ## ## --} {-- ## ## ## ## ## ## --} ; import Data.Maybe (listToMaybe) {-- ## ## --} {--## ## ## ## ## ####### ##### --} ; import Control.Monad.Fix (fix) {-- ### ## --} {--## ## ## ## ## ## #### ### ### --} ; import Data.Text (pack, Text) {-- ##### --} {-- ## ## ## ## ## ## ## ## ## --} ; import Data.Tuple (swap) {-- #### ##--} {-- ### ## ## ## ## ## ##### ## ## --} ; import Data.Void (Void) {-- ## --} {-- #### ##### ## ## ## ## ### ## ## --} ; import Data.Bool (bool) {-- # --} {-- ###### ## ## ### ## ## ### --} ; data T = P | B | C | A {-- --} {-- ###### ## ## ## ## ## #### --} ; data F = F T [F] {----} main = getContents >>= ((\case {-- ###### ### ### ## ## ## ### --} {--} Left e -> putStrLn $ errorBundlePretty {-- #### ## ## ## ###### --} {-- --} e; Right (f, i) -> (putStrLn . unwords {-- ### ## ###### ### ## #### --} {-- --} . (show <$>) . reverse . fst) (execState {-- ##### ## ## ## # ## ### --} {-- --} (fix (\x -> foldl (\a f -> a >>= (\n -> ( {-- ### ## ## ## --} {-- --} n +) <$> (\(F t p) -> if null p then case {-- ###### ### ## ## --} {-- ## --} t of P -> return 1 ; B -> uses _1 length {-- #### ## ## ## ## ## --} {-- ## ## --} C -> uses _1 uncons >>= maybe (return 0) {-- ## ## ### ## ### ## --} {-- ##### ## ## --} (\(h, t) -> _1 .= t >> return h); A -> {-- ##### # ## ## #### ## ###### --} {-- ######### ## ###### --} id %= swap >> return 0 else case t of{-- ### ## ## ## ## ## ## ###--} {-- ## ######## ### --} P -> x p >>= (\n -> _1 %= (n :) >> return {-- ###### ## ## ### ## #--} {-- ## ## ## --} n); B -> negate <$> x p; C -> fix (\l f -> {-- ### ## ## ## ### --} {-- ### ## ## ## ###### --} uses _1 ((0 `elem`) . listToMaybe) >>= bool {-- ## ## ## ## ### --} {-- ###### ### ### ## ## ### --} (x f >>= (\n -> (n +) <$> l f)) (return 0)) {-- ## ## ## --} {-- ## ########## #### ## ## #### --} p; A -> x p >> return 0) f)) (return 0)) f) {-- ##### --} {-- ## ## ## ### ## ### #### --} (reverse i, []))) . parse ((,) <$> many (fix {-- --} {-- ## ### ## ## ####### ### ### --} (\t -> choice $ zipWith3 between (char <$> {-- --} {-- ## ## #### ### # ## ## ## --} "([{<") (char <$> ")]}>") ((many t <&>) . {-- --} {-- ## ###### ### ## ## ## --} F <$> [P, B, C, A]))) <* newline <*> signed {-- --} {-- ######## --} (pure ()) decimal `sepBy` space1 <* eof :: {-- --} {-- ### ## --} Parsec Void Text ([F], [Int])) "") . pack {---} |
written by luatic
submitted at
0 likes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ; Brain-Flak implementation in Chicken Scheme for Code Guessing Round 39 ; Supports line comments using `#`, ignores invalid characters ; Compilation & invocation: `csc cg39.scm && ./cg39 FILE [ARGS ...]` (import (chicken process-context)) (define (parse port) (define (paren closing) (read-char port) (let ((sub (parse port))) (assert (eqv? (read-char port) closing)) (cons (cons closing sub) (parse port)))) (let ((c (peek-char port))) (case c ((#\) #\] #\} #\> #!eof) '()) ((#\() (paren #\))) ((#\[) (paren #\])) ((#\{) (paren #\})) ((#\<) (paren #\>)) (else (if (eqv? (read-char port) #\#) (do () ((memv (read-char port) '(#\newline #!eof))))) (parse port))))) (define (exec exp active) (let ((inactive '())) (define (pop) (if (null? active) 0 (let ((top (car active))) (set! active (cdr active)) top))) (define (push x) (set! active (cons x active))) (define (toggle) (let ((a active)) (set! active inactive) (set! inactive a))) (define (ctx-eval exp) (if (null? exp) 0 (let ((sub (cdr exp)) (nilad (null? (cdr exp)))) (if (list? (car exp)) (apply + (map ctx-eval exp)) (case (car exp) ((#\)) (if nilad 1 (let ((k (ctx-eval sub))) (push k) k))) ((#\]) (if nilad (length active) (- (ctx-eval sub)))) ((#\}) (if nilad (pop) (do ((sum 0)) ((or (null? active) (= (car active) 0)) sum) (set! sum (+ sum (ctx-eval sub)))))) ((#\>) (begin (if nilad (toggle) (ctx-eval sub)) 0))))))) (ctx-eval exp)) (for-each (lambda (x) (display x) (newline)) active)) (let ((args (command-line-arguments))) (call-with-input-file (car args) (lambda (port) (let ((exp (parse port))) (assert (eof-object? (read-char port))) (exec exp (map string->number (reverse (cdr args)))))))) |
written by soup girl
submitted at
1 like
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | function toggle(s, t, c) return c(0, t, s) end function one(s, t, c) return c(1, s, t) end function height(s, t, c) return c(#s, s, t) end function void(n) return function (s, t, c) return n(s, t, function (x, y, z) return c(0, y, z) end) end end function neg(n) return function (s, t, c) return n(s, t, function (x, y, z) return c(-x, y, z) end) end end function pop(s, t, c) local u = {} for i = 2, #s do u[i-1] = s[i] end return c(s[1], u, t) end function loop(n) return function (s, t, c) if #s == 0 or s[1] == 0 then return c(0, s, t) else return concat(n, loop(n))(s, t, c) end end end function concat(m, n) return function (s, t, c) return m(s, t, function (x, y, z) return n(y, z, function (p, q, r) return c(x+p, q, r) end) end) end end function push(n) return function (s, t, c) return n(s, t, function (x, y, z) local u = {x} for i = 1, #y do u[i+1] = y[i] end return c(x, u, z) end) end end function parse(f, s, c) local nilads = { ['()']=one, ['[]']=height, ['{}']=pop, ['<>']=toggle } local monads = { ['(']=push, ['[']=neg, ['{']=loop, ['<']=void } local nilad = nilads[string.sub(s, 1, 2)] local monad = monads[string.sub(s, 1, 1)] if nilad then return parse(concat(f, nilad), string.sub(s, 3), c) elseif monad then return parse(void(one), string.sub(s, 2), function (g, s) return parse(concat(f, monad(g)), string.sub(s, 2), c) end) else return c(f, s) end end function brainflak(s, n) s = string.gsub(s, "[^%[%](){}<>]", "") s, t = parse(void(one), s, function (f, s) return f, s end) return s(n, {}, function (x, y, z) return y end) end |
written by taswelll
submitted at
3 likes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | with builtins; rec { parse = with (import (fetchTarball { url = "https://github.com/kanwren/nix-parsec/archive/v0.2.0.tar.gz"; sha256 = "1v1krqzvpmb39s42m5gg2p7phhp4spd0vkb4wlhfkgbhi20dk5w7"; })).parsec; let { spaces = void (many (choice [ (string " ") (string "\n") (skipThen (string "#") (skipWhile (c: c != "\n"))) ])); symbol = s: thenSkip (string s) spaces; br = open: close: lift2 (b: c: {inherit b c;}) (symbol open) (thenSkip expr (symbol close)); expr = many (choice [ (br "(" ")") (br "[" "]") (br "{" "}") (br "<" ">") ]); body = runParser (between spaces eof expr); }; eval = s1: s2: let init = l: genList (x: elemAt l x) (length l - 1); last = l: elemAt l (length l - 1); return = s1: s2: ret: { inherit s1 s2 ret; }; toRet = f: v: v//{ ret = f v.ret; }; eval1 = s1: s2: expr: (if length expr.c == 0 then { ${"("} = return s1 s2 1; ${"["} = return s1 s2 (length s1); ${"<"} = return s2 s1 0; ${"{"} = if s1 == [] then return s1 s2 0 else return (init s1) s2 (last s1); } else { ${"("} = (v: v//{ s1=v.s1++[v.ret]; }) (eval s1 s2 expr.c); ${"["} = (toRet (x: -x)) (eval s1 s2 expr.c); ${"<"} = (toRet (x: 0 )) (eval s1 s2 expr.c); ${"{"} = let loop = {s1, s2, ret}@v: if s1 == [] || last s1 == 0 then v else (toRet (x: x+ret)) (loop (eval s1 s2 expr.c)); in loop (return s1 s2 0); }).${expr.b}; in foldl' ({s1, s2, ret}: next: (toRet (x: x+ret)) (eval1 s1 s2 next)) (return s1 s2 0); run = stack: code: with parse code; if type == "success" then eval stack [] value else throw (toJSON value); } |
written by Palaiologos
submitted at
1 like
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | -*-mode:text;coding:utf-8-*- $ uname -m x86_64 $ ./cg39 "((()()())(()()()()){{}})" 7 どのように機能するのでしょうか? Handle input with: import sys import os p=sys.argv[1] k=lambda x:"(("+o(x//3)+")){}{}"+(x%3)*"()"if x>3 else"()"*x m=lambda x:"("+o(x//2)+"){}"+(x%2)*"()"if x>6 else"()"*x o=lambda x:min(k(x),m(x),key=len) i=sys.stdin.read() i=i[:-1] if i[-1]=='\n' else i r=''.join(["("+o(ord(c))+")"for c in i])+p os.system("./cg39 '%s'"%r) |
the term "sus" indicating suspicion or uncertainty gained popularity thanks to a certain game even though it was in use prior to the games launch further terminology and internet memes that surged in popularity and were influenced by among us are "sussy" and "sussy baka" terms evolved from "sus" the ironic meme "when the imposter is sus" generally paired with a manipulated image of jerma985 and the humorous intentional misspelling of "among us" as "amogus" are other terms associated with the game moreover the "among us everywhere" meme which involves spotting objects reminiscent of the games crewmate character in unexpected places also gained traction in september 2022 "sus" was included in the merriam-webster dictionary
post a comment