fix .gitignore, Makefile and README.md for 2014/endoh
Unpack src.zip.
This commit is contained in:
1 parent
a7163eafa2
commit
e18e03bff5
20 files changed
+1616
-96
No files matched your search
@@ -1,3 +1,5 @@
|
|||||||
main
|
main
|
||||||
main.c
|
main.c
|
||||||
prog
|
prog
|
||||||
|
treacle
|
||||||
|
treacle.c
|
||||||
+212
-77
@@ -1,161 +1,262 @@
|
|||||||
#!/usr/bin/env make
|
#!/usr/bin/env make
|
||||||
#
|
#
|
||||||
# 2014 makefile
|
# IOCCC 2014 winning entry - endoh1
|
||||||
|
|
||||||
|
################################################################################
|
||||||
#
|
#
|
||||||
# This work by Landon Curt Noll, Simon Cooper, and Leonid A. Broukhis
|
# Regarding individual entries:
|
||||||
# is licensed under:
|
#
|
||||||
|
# IOCCC winning entry code may not work on your system. Even with standards,
|
||||||
|
# conditions and build environments change, especially when it comes to more
|
||||||
|
# extreme code such you might find in an IOCCC winner. Moreover, what was
|
||||||
|
# allowed and liked in one IOCCC contest may no longer be liked/allowed in
|
||||||
|
# later IOCCC years.
|
||||||
|
#
|
||||||
|
# Corrections on winning author and fixing typos in remarks are VERY WELCOME.
|
||||||
|
#
|
||||||
|
# GitHub pull requests are welcome:
|
||||||
|
#
|
||||||
|
# If you have a patch that might make running an entry work in modern Unix-like
|
||||||
|
# environments, please create a GitHub pull request for the IOCCC judges to
|
||||||
|
# consider.
|
||||||
|
#
|
||||||
|
# Suggestions and corrections regarding Makefiles, winning author information,
|
||||||
|
# fixing typos in remarks, and code patches are welcome via opening a GitHub
|
||||||
|
# issue or better yet, by creating a GitHub pull request for the IOCCC judges
|
||||||
|
# to consider. To form a GitHub issue or GitHub pull, please visit:
|
||||||
|
#
|
||||||
|
# https://github.com/ioccc-src/winner
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# This work by Landon Curt Noll and Leonid A. Broukhis is licensed under:
|
||||||
#
|
#
|
||||||
# Creative Commons Attribution-ShareAlike 3.0 Unported License.
|
# Creative Commons Attribution-ShareAlike 3.0 Unported License.
|
||||||
#
|
#
|
||||||
# See: http://creativecommons.org/licenses/by-sa/3.0/
|
# See: http://creativecommons.org/licenses/by-sa/3.0/
|
||||||
|
|
||||||
|
|
||||||
################
|
#############################
|
||||||
# tool locations
|
# shell used by this Makefile
|
||||||
################
|
#############################
|
||||||
#
|
#
|
||||||
SHELL= bash
|
SHELL= bash
|
||||||
CP= cp
|
|
||||||
CPP= cpp
|
#######################
|
||||||
GUNZIP= gunzip
|
# common tool locations
|
||||||
LD= ld
|
#######################
|
||||||
MAKE= make
|
#
|
||||||
RM= rm
|
include ../../var.mk
|
||||||
SED= sed
|
|
||||||
TAR= tar
|
|
||||||
TRUE= true
|
|
||||||
|
|
||||||
# Set X11_LIBDIR to the directory where the X11 library resides
|
# Set X11_LIBDIR to the directory where the X11 library resides
|
||||||
#
|
#
|
||||||
X11_LIBDIR= /usr/X11R6/lib
|
#X11_LIBDIR= /usr/X11R6/lib
|
||||||
|
#X11_LIBDIR= /usr/X11/lib
|
||||||
|
X11_LIBDIR= /opt/X11/lib
|
||||||
|
|
||||||
# Set X11_INCLUDEDIR to the directory where the X11 include files reside
|
# Set X11_INCLUDEDIR to the directory where the X11 include files reside
|
||||||
#
|
#
|
||||||
X11_INCDIR= /usr/X11R6/include
|
#X11_INCDIR= /usr/X11R6/include
|
||||||
|
#X11_INCDIR= /usr/X11/include
|
||||||
|
X11_INCDIR= /opt/X11/include
|
||||||
|
|
||||||
# Compiler warnings
|
# Common C compiler warnings to silence
|
||||||
#
|
#
|
||||||
#CWARN=
|
#CSILENCE=
|
||||||
CWARN= -Wall
|
CSILENCE= -Wno-empty-body
|
||||||
#CWARN= -Wall -pedantic
|
|
||||||
|
|
||||||
# compiler standard
|
# Common C compiler warning flags
|
||||||
|
#
|
||||||
|
#CWARN= ${CSILENCE}
|
||||||
|
#CWARN= -Wall ${CSILENCE}
|
||||||
|
#CWARN= -Wall -Wextra ${CSILENCE}
|
||||||
|
CWARN= -Wall -Wextra -pedantic ${CSILENCE}
|
||||||
|
|
||||||
|
# Compiler standard
|
||||||
#
|
#
|
||||||
#CSTD=
|
#CSTD=
|
||||||
#CSTD= -ansi
|
#CSTD= -ansi
|
||||||
CSTD= -std=c11
|
CSTD= -std=gnu11
|
||||||
|
|
||||||
# compiler bit architecture
|
# Compiler bit architecture
|
||||||
#
|
#
|
||||||
# Some entries require 32-bitness:
|
# Some entries require 32-bitness:
|
||||||
# ARCH= -m32
|
# ARCH= -m32
|
||||||
#
|
#
|
||||||
# Some entries require 64-bitess:
|
# Some entries require 64-bitness:
|
||||||
# ARCH= -m64
|
# ARCH= -m64
|
||||||
#
|
#
|
||||||
# By default we assume nothing:
|
# By default we assume nothing:
|
||||||
#
|
#
|
||||||
ARCH=
|
ARCH=
|
||||||
|
|
||||||
# optimization
|
# Defines that are needed to compile
|
||||||
|
#
|
||||||
|
CDEFINE=
|
||||||
|
#CDEFINE= -DIOCCC
|
||||||
|
|
||||||
|
# Include files that are needed to compile
|
||||||
|
#
|
||||||
|
CINCLUDE=
|
||||||
|
#CINCLUDE= -include stdlib.h
|
||||||
|
#CINCLUDE= -include stdio.h
|
||||||
|
#CINCLUDE= -include stdlib.h -include stdio.h
|
||||||
|
#CINCLUDE= -I ${X11_INCDIR} -I ${X11_INCDIR}/X11
|
||||||
|
#CINCLUDE= `${SDL2_CONFIG} --cflags`
|
||||||
|
|
||||||
|
# Optimization
|
||||||
#
|
#
|
||||||
# Most compiles will safely use -O2. Some can use only -O1 or -O.
|
# Most compiles will safely use -O2. Some can use only -O1 or -O.
|
||||||
# A few compilers have broken optimizers or this entry make break
|
# A few compilers have broken optimizers or this entry make break
|
||||||
# under those buggy optimizers and thus you may not want anything.
|
# under those buggy optimizers and thus you may not want anything.
|
||||||
|
# Reasonable compilers will allow for -O3.
|
||||||
#
|
#
|
||||||
#OPT=
|
#OPT=
|
||||||
#OPT= -O
|
#OPT= -O
|
||||||
#OPT= -O1
|
#OPT= -O1
|
||||||
OPT= -O2
|
#OPT= -O2
|
||||||
#OPT= -O3
|
OPT= -O3
|
||||||
|
|
||||||
|
# Default flags for ANSI C compilation
|
||||||
|
#
|
||||||
|
CFLAGS= ${CSTD} ${CWARN} ${ARCH} ${CDEFINE} ${CINCLUDE} ${OPT}
|
||||||
|
|
||||||
# Libraries needed to build
|
# Libraries needed to build
|
||||||
#
|
#
|
||||||
LIBS=
|
LIBS=
|
||||||
|
#LIBS= -lm
|
||||||
|
#LIBS= -L ${X11_LIBDIR} -lX11
|
||||||
|
#LIBS= `${SDL2_CONFIG} --libs`
|
||||||
|
|
||||||
# default flags for ANSI C compilation
|
# C compiler to use
|
||||||
#
|
|
||||||
CFLAGS= ${CWARN} ${CSTD} ${ARCH} ${OPT} -Wno-empty-body -funsigned-char
|
|
||||||
|
|
||||||
# ANSI compiler
|
|
||||||
#
|
|
||||||
# Set CC to the name of your ANSI compiler.
|
|
||||||
#
|
|
||||||
# Some entries seem to need gcc. If you have gcc, set
|
|
||||||
# both CC and MAY_NEED_GCC to gcc.
|
|
||||||
#
|
|
||||||
# If you do not have gcc, set CC to the name of your ANSI compiler, and
|
|
||||||
# set MAY_NEED_GCC to either ${CC} (and hope for the best) or to just :
|
|
||||||
# to disable such programs.
|
|
||||||
#
|
#
|
||||||
CC= cc
|
CC= cc
|
||||||
#CC=clang
|
#CC=clang
|
||||||
MAY_NEED_GCC= gcc
|
#CC=gcc
|
||||||
|
|
||||||
|
# Compiler add-ons or replacements for clang only
|
||||||
|
#
|
||||||
|
ifeq ($(CC),clang)
|
||||||
|
#
|
||||||
|
CSILENCE+= -Wno-comma -Wno-missing-variable-declarations \
|
||||||
|
-Wno-poison-system-directories -Wno-shadow
|
||||||
|
#
|
||||||
|
CWARN+= -Weverything
|
||||||
|
#
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Specific add-ons or replacements for gcc only
|
||||||
|
#
|
||||||
|
ifeq ($(CC),gcc)
|
||||||
|
#
|
||||||
|
#CSILENCE+=
|
||||||
|
#
|
||||||
|
#CWARN+=
|
||||||
|
#
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
##############################
|
##############################
|
||||||
# Special flags for this entry
|
# Special flags for this entry
|
||||||
##############################
|
##############################
|
||||||
#
|
#
|
||||||
ENTRY= prog main
|
ENTRY= endoh1
|
||||||
DATA=
|
PROG= prog
|
||||||
|
#
|
||||||
|
OBJ= ${PROG}.o
|
||||||
|
DATA= Rakefile alpha.rb assemble.rb ast-def.rb gen-prog.rb gen-table.rb link.rb \
|
||||||
|
machine.rb main.c parse.rb prog-tmpl.c read_me.md register.rb \
|
||||||
|
serialize.rb src.rb tool.rb vm.c
|
||||||
|
TARGET= ${PROG} main treacle
|
||||||
|
#
|
||||||
ALT_OBJ=
|
ALT_OBJ=
|
||||||
ALT_ENTRY=
|
ALT_TARGET=
|
||||||
|
|
||||||
|
|
||||||
#################
|
#################
|
||||||
# build the entry
|
# build the entry
|
||||||
#################
|
#################
|
||||||
#
|
#
|
||||||
all: ${ENTRY} ${DATA}
|
all: data ${TARGET}
|
||||||
@${TRUE}
|
@${TRUE}
|
||||||
|
|
||||||
|
.PHONY: all alt data everything clean clobber install \
|
||||||
|
love haste waste maker easter_egg sandwich \
|
||||||
|
supernova deep_magic magic charon pluto
|
||||||
|
|
||||||
|
${PROG}: ${PROG}.c
|
||||||
|
${CC} ${CFLAGS} $< -o $@ ${LIBS}
|
||||||
|
|
||||||
main: main.c
|
main: main.c
|
||||||
${CC} ${CFLAGS} $< -o $@ ${LIBS}
|
${CC} ${CFLAGS} $< -o $@ ${LIBS}
|
||||||
|
|
||||||
main.c: prog
|
main.c: prog
|
||||||
./prog > $@
|
${RM} -f $@
|
||||||
|
./${PROG} > $@
|
||||||
prog: prog.c
|
|
||||||
${CC} ${CFLAGS} $< -o $@ ${LIBS}
|
|
||||||
|
|
||||||
# alternative executable
|
# alternative executable
|
||||||
#
|
#
|
||||||
alt: ${ALT_ENTRY}
|
alt: data ${ALT_TARGET}
|
||||||
@${TRUE}
|
@${TRUE}
|
||||||
|
|
||||||
|
treacle.c: ${PROG}
|
||||||
|
${RM} -f $@
|
||||||
|
./${PROG} < ${PROG}.c > $@
|
||||||
|
|
||||||
|
treacle: treacle.c
|
||||||
|
${CC} ${CFLAGS} $< -o $@ ${LIBS}
|
||||||
|
|
||||||
# data files
|
# data files
|
||||||
#
|
#
|
||||||
data: ${DATA}
|
data: ${DATA}
|
||||||
@${TRUE}
|
@${TRUE}
|
||||||
|
|
||||||
|
# both all and alt
|
||||||
|
#
|
||||||
|
everything: all alt
|
||||||
|
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# utility rules
|
# utility rules
|
||||||
###############
|
###############
|
||||||
#
|
#
|
||||||
everything: all alt
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
${RM} -f ${ENTRY}.o ${ALT_OBJ} main.o
|
${RM} -f ${OBJ} ${ALT_OBJ}
|
||||||
|
${RM} -f main.o
|
||||||
|
@-if [ -f indent.c ]; then \
|
||||||
|
echo ${RM} -f indent.c; \
|
||||||
|
${RM} -f indent.c; \
|
||||||
|
fi
|
||||||
|
|
||||||
clobber: clean
|
clobber: clean
|
||||||
${RM} -f ${ENTRY} ${ALT_ENTRY} main.c main
|
${RM} -f ${TARGET} ${ALT_TARGET}
|
||||||
|
@-if [ -e sandwich ]; then \
|
||||||
nuke: clobber
|
${RM} -f sandwich; \
|
||||||
@${TRUE}
|
echo 'ate sandwich'; \
|
||||||
|
fi
|
||||||
dist_clean: nuke
|
|
||||||
@${TRUE}
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
@echo "Surely we are joking Dr. Science!"
|
@echo "Dr. Spock says that is not logical!"
|
||||||
@${TRUE}
|
@${TRUE}
|
||||||
|
|
||||||
# backwards compatibility
|
# you may be able to misunderstand the source by reading indent.c
|
||||||
#
|
#
|
||||||
build: all
|
indent.c: ${PROG}.c
|
||||||
@${TRUE}
|
@if which "${GINDENT}" >/dev/null 2>&1; then \
|
||||||
|
echo ${RM} -f $@; \
|
||||||
|
${RM} -f $@; \
|
||||||
|
echo "${GINDENT} < $< > $@"; \
|
||||||
|
${GINDENT} < $< > $@; \
|
||||||
|
elif which "${INDENT}" >/dev/null 2>&1; then \
|
||||||
|
echo ${RM} -f $@; \
|
||||||
|
${RM} -f $@; \
|
||||||
|
echo "${INDENT} < $< > $@"; \
|
||||||
|
${INDENT} < $< > $@; \
|
||||||
|
else \
|
||||||
|
echo "no intent tool found, ident $< yourself, sorry"; \
|
||||||
|
echo "exit 1"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
##################
|
##################
|
||||||
@@ -174,35 +275,69 @@ waste:
|
|||||||
@echo 'haste'
|
@echo 'haste'
|
||||||
@${TRUE}
|
@${TRUE}
|
||||||
|
|
||||||
|
maker:
|
||||||
|
@echo 'Participate in a maker faire'
|
||||||
|
@${TRUE}
|
||||||
|
|
||||||
easter_egg:
|
easter_egg:
|
||||||
@echo you expected to sometimes mis-understand this $${RANDOM} magic
|
@echo "you expected to often misunderstand this $${RANDOM} magic"
|
||||||
@echo chongo '<was here>' "/\\oo/\\"
|
@echo "chongo '<was here>' /\\oo/\\"
|
||||||
@echo Readers shall not be disallowed from failong to be unable to not partly misunderstand this partocular final echo.
|
@echo "Eggy"
|
||||||
|
|
||||||
|
sandwich: easter_egg
|
||||||
|
@if [ `id -u` -eq 0 ]; then \
|
||||||
|
echo 'Okay.'; \
|
||||||
|
echo "$${RANDOM}`date +%s`$${RANDOM}" > $@; \
|
||||||
|
else \
|
||||||
|
echo 'What? Make it yourself.'; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
|
||||||
# Understand the history of the Homebrew Computer Club
|
# Understand the history of the Homebrew Computer Club
|
||||||
# as well as the West Coast Computer Faire and
|
# as well as the West Coast Computer Faire and
|
||||||
# you might be confused different. :-)
|
# you might be confused different. :-)
|
||||||
#
|
#
|
||||||
supernova: nuke
|
supernova: sandwich
|
||||||
@-if [ -r .code_anal ]; then \
|
@-if [ -r .code_anal ]; then \
|
||||||
${RM} -f .code_anal_v4; \
|
${RM} -f .code_anal_v6; \
|
||||||
else \
|
else \
|
||||||
echo "We are not expected to understand that"; \
|
echo "planet deniers, like some members of the IAU, are so cute when they try to defend their logic"; \
|
||||||
fi
|
fi
|
||||||
|
@echo "A $@ helps ${MAKE} the elements that help form planets"
|
||||||
@${TRUE}
|
@${TRUE}
|
||||||
|
|
||||||
deep_magic:
|
deep_magic: supernova
|
||||||
@-if [ -r .code_anal ]; then \
|
@-if [ -r .code_anal ]; then \
|
||||||
ccode_analysis --deep_magic 2ed3582ec5c094a093fea2a6bcb9f19439892873c9cc45ed1ceaafe08b7d52e1b2c7cd524be3b0b2 --FNV1a_hash 512-bit "${ENTRY}"; \
|
ccode_analysis --deep_magic 7889066cdbdf09b0408021754586e895be641cc9be29e7eafd3ca65359541f17 \
|
||||||
|
--FNV1a_hash_512_bit -v2 "${PROG}" "${PROG}.c"; \
|
||||||
else \
|
else \
|
||||||
echo "You are holding it wrong!"; \
|
echo "Wrong! Do it again!"; \
|
||||||
|
sleep 2; \
|
||||||
|
echo "Wrong! Do it again!"; \
|
||||||
|
sleep 2; \
|
||||||
|
echo "Wrong! Do it again!"; \
|
||||||
fi
|
fi
|
||||||
@${TRUE}
|
@${TRUE}
|
||||||
|
|
||||||
magic: deep_magic
|
magic: deep_magic
|
||||||
@-if [ -r .code_anal ]; then \
|
@-if [ -r .code_anal ]; then \
|
||||||
ccode_analysis --mode 391581 --level 216193 --FNV1a_hash 512-bit "${ENTRY}"; \
|
ccode_analysis --level 20003 --mode 5717175 --FNV1a_hash_512_bit -v2 "${PROG}" "${PROG}.c"; \
|
||||||
else \
|
else \
|
||||||
echo "These aren't the primes you're looking for Pauline!"; \
|
echo "If you don't eat yer meat, you can't have any pudding!"; \
|
||||||
|
echo "How can you have any pudding if you don't eat yer meat?!"; \
|
||||||
fi
|
fi
|
||||||
@${TRUE}
|
@${TRUE}
|
||||||
|
|
||||||
|
# The IOCCC resident astronomer states
|
||||||
|
#
|
||||||
|
charon: magic
|
||||||
|
@echo "$@ is a dwarf planet"
|
||||||
|
@echo "dwarf is a type of planet"
|
||||||
|
@echo "therefore IAU, $@ is a planet"
|
||||||
|
|
||||||
|
pluto: charon
|
||||||
|
${MAKE} charon
|
||||||
|
@echo "$@ is a dwarf planet"
|
||||||
|
@echo "dwarf is a type of planet"
|
||||||
|
@echo "therefore, $@ is a planet"
|
||||||
|
@echo "having lots of planets is good feature because supernovae can help ${MAKE} a lot of them"
|
||||||
+24
-19
@@ -1,41 +1,47 @@
|
|||||||
# Most square (YODA award)
|
# Most square (YODA award)
|
||||||
|
|
||||||
Yusuke Endoh
|
Yusuke Endoh
|
||||||
<mame@ruby-lang.org>
|
<mame@ruby-lang.org>
|
||||||
<https://github.com/mame/>
|
<https://github.com/mame/>
|
||||||
|
|
||||||
|
# To build:
|
||||||
|
|
||||||
## Judges' comments:
|
```sh
|
||||||
### To build:
|
make
|
||||||
|
```
|
||||||
make
|
|
||||||
|
|
||||||
### To run:
|
### To run:
|
||||||
|
|
||||||
./prog > foo.c
|
```sh
|
||||||
|
./prog > foo.c
|
||||||
|
```
|
||||||
|
|
||||||
### Try:
|
### Try:
|
||||||
|
|
||||||
./prog > main.c
|
```sh
|
||||||
|
./prog > main.c
|
||||||
|
|
||||||
make main
|
make main
|
||||||
./main Hello
|
./main Hello
|
||||||
|
```
|
||||||
|
|
||||||
### Selected Judges Remarks:
|
## Judges' comments:
|
||||||
|
|
||||||
Big terminals with tiny fonts have their uses in certain cases.
|
Big terminals with tiny fonts have their uses in certain cases.
|
||||||
One of them is:
|
One of them is:
|
||||||
|
|
||||||
./prog < prog.c > treacle.c
|
```sh
|
||||||
make treacle
|
./prog < prog.c > treacle.c
|
||||||
# or instead of make: cc -Wno-empty-body -funsigned-char treacle.c -o treacle
|
make treacle
|
||||||
./treacle
|
./treacle
|
||||||
|
```
|
||||||
|
|
||||||
When using a smart phone to read the output, you may need to
|
When using a smart phone to read the output, you may need to
|
||||||
step back to see the bigger picture because that picture is worth
|
step back to see the bigger picture because that picture is worth
|
||||||
more than 1000 words.
|
more than 1000 words.
|
||||||
|
|
||||||
## Author's comments:
|
## Author's comments:
|
||||||
|
|
||||||
### Remarks
|
### Remarks
|
||||||
|
|
||||||
You may want to use a large display with a very small-font terminal.
|
You may want to use a large display with a very small-font terminal.
|
||||||
@@ -44,11 +50,10 @@ You may want to use a large display with a very small-font terminal.
|
|||||||
|
|
||||||
Decompress `src.zip` if you need explanation.
|
Decompress `src.zip` if you need explanation.
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
## Copyright:
|
||||||
<!--
|
|
||||||
(c) Copyright 1984-2015, [Leo Broukhis, Simon Cooper, Landon Curt Noll][judges] - All rights reserved
|
(c) Copyright 1984-2015, [Leo Broukhis, Simon Cooper, Landon Curt Noll][judges] - All rights reserved
|
||||||
This work is licensed under a [Creative Commons Attribution-ShareAlike 3.0 Unported License][cc].
|
This work is licensed under a [Creative Commons Attribution-ShareAlike 3.0 Unported License][cc].
|
||||||
|
|
||||||
[judges]: http://www.ioccc.org/judges.html
|
[judges]: http://www.ioccc.org/judges.html
|
||||||
[cc]: http://creativecommons.org/licenses/by-sa/3.0/
|
[cc]: http://creativecommons.org/licenses/by-sa/3.0/
|
||||||
-->
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
file "ast.txt" => ["src.rb", "parse.rb", "ast-def.rb"] do |t|
|
||||||
|
ruby "parse.rb", t.prerequisites[0], t.name
|
||||||
|
end
|
||||||
|
|
||||||
|
file "seq.txt" => ["ast.txt", "serialize.rb"] do |t|
|
||||||
|
ruby "serialize.rb", t.prerequisites[0], t.name
|
||||||
|
end
|
||||||
|
|
||||||
|
file "alpha.txt" => ["seq.txt", "alpha.rb"] do |t|
|
||||||
|
ruby "alpha.rb", t.prerequisites[0], t.name
|
||||||
|
end
|
||||||
|
|
||||||
|
file "reg.txt" => ["alpha.txt", "register.rb"] do |t|
|
||||||
|
ruby "register.rb", t.prerequisites[0], t.name
|
||||||
|
end
|
||||||
|
|
||||||
|
file "raw.txt" => ["reg.txt", "assemble.rb", "machine.rb"] do |t|
|
||||||
|
ruby "assemble.rb", t.prerequisites[0], t.name
|
||||||
|
end
|
||||||
|
|
||||||
|
file "main.c" => ["raw.txt", "link.rb", "machine.rb", "vm.c"] do |t|
|
||||||
|
ruby "link.rb", t.prerequisites[0], t.name
|
||||||
|
end
|
||||||
|
|
||||||
|
file "prog.c" => ["main.c", "gen-prog.rb", "prog-tmpl.c"] do |t|
|
||||||
|
ruby "gen-prog.rb", t.prerequisites[0], t.name
|
||||||
|
end
|
||||||
|
|
||||||
|
file "prog" => "prog.c" do |t|
|
||||||
|
sh "gcc", "-Wall", "-W", "-Wextra", "-o", t.name, t.prerequisites[0], "-g"
|
||||||
|
end
|
||||||
|
|
||||||
|
task :test => :default do
|
||||||
|
sh "./prog > m.c && gcc -Wall -W -Wextra -o m m.c"
|
||||||
|
sh "./m ABCDEabcde0123456789 | ruby qr-png.rb && zbarimg -q t.png"
|
||||||
|
sh "./m | ruby qr-png.rb && zbarimg -q t.png > t.c"
|
||||||
|
sh "echo -n QR-Code: > t2.c && cat m.c >> t2.c && diff t.c t2.c && echo && echo OK && echo"
|
||||||
|
sh "cat prog.c | ./iocccsize -i; wc -c prog.c"
|
||||||
|
sh "cat m.c | ./iocccsize -i; wc -c m.c"
|
||||||
|
end
|
||||||
|
|
||||||
|
task :default => "prog"
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
# alpha conversion (variable renaming)
|
||||||
|
|
||||||
|
require_relative "ast-def"
|
||||||
|
|
||||||
|
class ID
|
||||||
|
@@num = 0
|
||||||
|
|
||||||
|
def initialize(name)
|
||||||
|
@unified = nil
|
||||||
|
@name = "#{ name }:#{ @@num }"
|
||||||
|
@@num += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :name, :unified
|
||||||
|
|
||||||
|
def inspect
|
||||||
|
if @unified
|
||||||
|
@unified.inspect
|
||||||
|
else
|
||||||
|
"#<#{ self.class }:#{ @name }>"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def unify(other)
|
||||||
|
if @unified
|
||||||
|
@unified.unify(other)
|
||||||
|
elsif other.term != self
|
||||||
|
@unified = other
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def term
|
||||||
|
@unified ? @unified.term : self
|
||||||
|
end
|
||||||
|
|
||||||
|
def ==(other)
|
||||||
|
term.name == other.term.name
|
||||||
|
end
|
||||||
|
|
||||||
|
alias eql? ==
|
||||||
|
|
||||||
|
def hash
|
||||||
|
if @unified
|
||||||
|
@unified.hash
|
||||||
|
else
|
||||||
|
@name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def merge(vars1, vars2)
|
||||||
|
vars1.each do |key, var|
|
||||||
|
if vars2[key] && vars2[key] != var
|
||||||
|
var.unify(vars2[key])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
vars1.merge(vars2)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_opt_inc_dec(seq)
|
||||||
|
seq.each_cons(4) do |insn1, insn2, insn3, insn4|
|
||||||
|
next unless insn1.is_a?(IRead)
|
||||||
|
next unless insn2 == IPush[1]
|
||||||
|
next unless insn3 == IBinary[:+] || insn3 == IBinary[:-]
|
||||||
|
next unless insn4 == IWrite[insn1.var]
|
||||||
|
insn1.tmp.unify(insn4.tmp)
|
||||||
|
end
|
||||||
|
|
||||||
|
seq.each do |insn|
|
||||||
|
case insn
|
||||||
|
when IBranch, ILoop
|
||||||
|
check_opt_inc_dec(insn.s1)
|
||||||
|
check_opt_inc_dec(insn.s2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def alpha(seq, vars)
|
||||||
|
nvars = vars.dup
|
||||||
|
seq.reverse_each do |insn|
|
||||||
|
case insn
|
||||||
|
when IRead
|
||||||
|
if insn.var
|
||||||
|
if insn.tmp
|
||||||
|
nvars[insn.var] ||= insn.tmp
|
||||||
|
nvars[insn.var].unify(insn.tmp)
|
||||||
|
else
|
||||||
|
insn.tmp = nvars[insn.var] ||= ID.new(insn.var)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
when IWrite
|
||||||
|
if insn.var
|
||||||
|
if insn.tmp
|
||||||
|
nvars[insn.var] ||= insn.tmp
|
||||||
|
nvars[insn.var].unify(insn.tmp)
|
||||||
|
else
|
||||||
|
insn.tmp = nvars[insn.var]
|
||||||
|
end
|
||||||
|
nvars.delete(insn.var)
|
||||||
|
end
|
||||||
|
when IExit
|
||||||
|
nvars.clear
|
||||||
|
when IBranch
|
||||||
|
nvars1 = alpha(insn.s1, nvars)
|
||||||
|
nvars2 = alpha(insn.s2, nvars)
|
||||||
|
nvars = merge(nvars1, nvars2)
|
||||||
|
when ILoop
|
||||||
|
begin
|
||||||
|
nvars_back = nvars.dup
|
||||||
|
nvars1 = alpha(insn.s1, nvars)
|
||||||
|
nvars2 = alpha(insn.s1, alpha(insn.s2, nvars))
|
||||||
|
nvars = merge(nvars1, nvars2)
|
||||||
|
merge(nvars, nvars_back)
|
||||||
|
end until nvars.keys == nvars_back.keys
|
||||||
|
end
|
||||||
|
end
|
||||||
|
nvars
|
||||||
|
end
|
||||||
|
|
||||||
|
def rename(seq)
|
||||||
|
seq.each do |insn|
|
||||||
|
case insn
|
||||||
|
when IRead, IWrite
|
||||||
|
insn.tmp = ID.new(insn.var) if insn.var == "dummy"
|
||||||
|
insn.var.replace insn.tmp.term.name if insn.var
|
||||||
|
when IBranch, ILoop
|
||||||
|
rename(insn.s1)
|
||||||
|
rename(insn.s2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ARGV.size != 2
|
||||||
|
puts "usage: #$0 <seq1.txt> <seq2.txt>"
|
||||||
|
else
|
||||||
|
seq = eval(File.read(ARGV[0]))
|
||||||
|
alpha(seq, {})
|
||||||
|
check_opt_inc_dec(seq)
|
||||||
|
rename(seq)
|
||||||
|
File.write(ARGV[1], seq.pretty_inspect)
|
||||||
|
end
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
# dump machine code
|
||||||
|
|
||||||
|
require_relative "ast-def"
|
||||||
|
require_relative "machine"
|
||||||
|
|
||||||
|
def dump_seq(seq)
|
||||||
|
seq.each_cons(2) do |insn1, insn2|
|
||||||
|
if insn1.is_a?(IPush) && insn2.is_a?(IPush)
|
||||||
|
p insn1, insn2
|
||||||
|
raise "consecutive push"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
seq.map do |insn|
|
||||||
|
case insn
|
||||||
|
when IRead then (REGISTER_READ + insn.var.ord - ?a.ord).chr if insn.var
|
||||||
|
when IWrite then (REGISTER_WRITE + insn.var.ord - ?a.ord).chr if insn.var
|
||||||
|
when IInc then MNEMONIC[:Inc] + (REGISTER_READ + insn.var.ord - ?a.ord).chr
|
||||||
|
when IDec then MNEMONIC[:Dec] + (REGISTER_READ + insn.var.ord - ?a.ord).chr
|
||||||
|
when IPush then encode_number(insn.num)
|
||||||
|
when IBranch
|
||||||
|
MNEMONIC[:BranchS] + dump_seq(insn.s1) +
|
||||||
|
MNEMONIC[:BranchM] + dump_seq(insn.s2) +
|
||||||
|
MNEMONIC[:BranchE]
|
||||||
|
when ILoop
|
||||||
|
MNEMONIC[:LoopS] + dump_seq(insn.s1) +
|
||||||
|
MNEMONIC[:LoopM] + dump_seq(insn.s2) +
|
||||||
|
MNEMONIC[:LoopE]
|
||||||
|
when IBinary then MNEMONIC[insn.op]
|
||||||
|
when ITest then MNEMONIC[:Test]
|
||||||
|
when IARef then MNEMONIC[:ARef]
|
||||||
|
when IOut then MNEMONIC[:Out]
|
||||||
|
when IExit then MNEMONIC[:Exit]
|
||||||
|
when IASet then MNEMONIC[:ASet]
|
||||||
|
end
|
||||||
|
end.join
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_opt_inc_dec(seq, i)
|
||||||
|
return unless seq[i].is_a?(IRead)
|
||||||
|
return unless seq[i + 1] == IPush[1]
|
||||||
|
return unless seq[i + 2] == IBinary[:+] || seq[i + 2] == IBinary[:-]
|
||||||
|
return unless seq[i + 3] == IWrite[seq[i].var]
|
||||||
|
insn = (seq[i + 2].op == :+ ? IInc : IDec)[seq[i].var]
|
||||||
|
flag = seq[i + 4].is_a?(IRead) && seq[i + 4].var == seq[i].var
|
||||||
|
[insn, seq[i].var, flag]
|
||||||
|
end
|
||||||
|
|
||||||
|
def opt_inc_dec(seq)
|
||||||
|
while true
|
||||||
|
modified = false
|
||||||
|
(seq.size - 3).times do |i|
|
||||||
|
new_insn, var, flag = check_opt_inc_dec(seq, i)
|
||||||
|
if new_insn
|
||||||
|
if flag
|
||||||
|
seq[i, 5] = [new_insn]
|
||||||
|
else
|
||||||
|
seq[i, 4] = [new_insn, IWrite[var]]
|
||||||
|
end
|
||||||
|
modified = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
break if !modified
|
||||||
|
end
|
||||||
|
|
||||||
|
seq.each do |insn|
|
||||||
|
case insn
|
||||||
|
when IBranch, ILoop
|
||||||
|
opt_inc_dec(insn.s1)
|
||||||
|
opt_inc_dec(insn.s2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ARGV.size != 2
|
||||||
|
puts "usage: #$0 <seq3.txt> <raw.txt>"
|
||||||
|
else
|
||||||
|
seq = eval(File.read(ARGV[0]))
|
||||||
|
opt_inc_dec(seq)
|
||||||
|
File.write(ARGV[1], dump_seq(seq))
|
||||||
|
end
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
require "pp"
|
||||||
|
|
||||||
|
class Node
|
||||||
|
def ==(other)
|
||||||
|
self.class == other.class &&
|
||||||
|
self.class::Keys.all? do |key|
|
||||||
|
instance_variable_get(:"@#{ key }") == other.send(key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_accessor :tmp
|
||||||
|
|
||||||
|
def self.create(*keys)
|
||||||
|
klass = Class.new(Node)
|
||||||
|
klass.const_set(:Keys, keys)
|
||||||
|
klass.class_eval do
|
||||||
|
keys.each do |key|
|
||||||
|
attr_reader key
|
||||||
|
end
|
||||||
|
end
|
||||||
|
klass
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.[](*values)
|
||||||
|
new(*values)
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(*values)
|
||||||
|
self.class::Keys.zip(values) do |key, value|
|
||||||
|
instance_variable_set(:"@#{ key }", value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def inspect
|
||||||
|
"#{ self.class }[#{
|
||||||
|
self.class::Keys.map do |key|
|
||||||
|
instance_variable_get(:"@#{ key }").inspect
|
||||||
|
end.join(", ")
|
||||||
|
}]"
|
||||||
|
end
|
||||||
|
|
||||||
|
def pretty_print(q)
|
||||||
|
q.group(2, "#{ self.class }[", "]") do
|
||||||
|
q.seplist(
|
||||||
|
self.class::Keys.map do |key|
|
||||||
|
instance_variable_get(:"@#{ key }")
|
||||||
|
end
|
||||||
|
) do |v|
|
||||||
|
q.pp v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
PRead = Node.create(:var)
|
||||||
|
PImm = Node.create(:num)
|
||||||
|
PNop = Node.create
|
||||||
|
|
||||||
|
PBinary = Node.create(:op, :e1, :e2)
|
||||||
|
PIfThenElse = Node.create(:cond, :e1, :e2)
|
||||||
|
|
||||||
|
PRShift = Node.create(:val, :shift)
|
||||||
|
PARef = Node.create(:e1, :e2) # e1[e2]
|
||||||
|
PSRef = Node.create(:e)
|
||||||
|
PIRef = Node.create(:e)
|
||||||
|
|
||||||
|
PSequence = Node.create(:seq, :e)
|
||||||
|
|
||||||
|
PASet = Node.create(:e1, :e2, :e3) # e1[e2] = e3
|
||||||
|
PAssign = Node.create(:var, :exp)
|
||||||
|
PLoop = Node.create(:cond, :body)
|
||||||
|
PExit = Node.create(:e)
|
||||||
|
POut = Node.create(:e)
|
||||||
|
PTest = Node.create(:e)
|
||||||
|
|
||||||
|
IRead = Node.create(:var)
|
||||||
|
IWrite = Node.create(:var)
|
||||||
|
IInc = Node.create(:var)
|
||||||
|
IDec = Node.create(:var)
|
||||||
|
INop = Node.create
|
||||||
|
IPush = Node.create(:num)
|
||||||
|
IBinary = Node.create(:op)
|
||||||
|
IARef = Node.create
|
||||||
|
IASet = Node.create
|
||||||
|
IExit = Node.create
|
||||||
|
IOut = Node.create
|
||||||
|
ITest = Node.create
|
||||||
|
IBranch = Node.create(:s1, :s2)
|
||||||
|
ILoop = Node.create(:s1, :s2)
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
tmpl = <<END
|
||||||
|
111111100010101111111
|
||||||
|
100000101000001000001
|
||||||
|
101110100001101011101
|
||||||
|
101110101100101011101
|
||||||
|
101110101101001011101
|
||||||
|
100000100110101000001
|
||||||
|
111111101010101111111
|
||||||
|
000000001100100000000
|
||||||
|
010111101010111011010
|
||||||
|
100101011011110011100
|
||||||
|
011101111111000101101
|
||||||
|
001111011010111110100
|
||||||
|
111001101000111110101
|
||||||
|
000000001011111110100
|
||||||
|
111111100010100110110
|
||||||
|
100000101011001010011
|
||||||
|
101110101111111100111
|
||||||
|
101110101100111111100
|
||||||
|
101110100101110001111
|
||||||
|
100000101111100010110
|
||||||
|
111111100110110110100
|
||||||
|
END
|
||||||
|
|
||||||
|
tmpl = "\n" * 8 + tmpl.lines.flat_map do |l|
|
||||||
|
l = l.chomp.gsub(/./) { $& * 4 } + "\n"
|
||||||
|
[l, l]
|
||||||
|
end.join + "\n" * 8
|
||||||
|
tmpl.gsub!(/^/, "0" * 4 * 4)
|
||||||
|
tmpl.gsub!(/0+$/, "")
|
||||||
|
tmpl.gsub!("1\n") { "\\\n" }
|
||||||
|
tmpl.tr!("10", "# ")
|
||||||
|
|
||||||
|
Code = File.read(ARGV[0]).chomp[/"(.*)"/, 1].tr(" ", "Y")
|
||||||
|
|
||||||
|
code = File.read("prog-tmpl.c")
|
||||||
|
code.gsub!('"CODE"') { "\"\\\"" + Code + '"' }
|
||||||
|
code.gsub!('INDX', (Code.index("#include") - 1 + 1).to_s)
|
||||||
|
code.gsub!(/^\s+/, "")
|
||||||
|
code.gsub!("\n", "")
|
||||||
|
|
||||||
|
#ode = "#include<stdio.h>/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/" + code
|
||||||
|
code = "#include<stdio.h>/*IOCCC201420142014IOCCC2014IOCCC2014IOCCC201*/" + code
|
||||||
|
|
||||||
|
tmpl[(tmpl =~ /(\\)$/m)] = "#"
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
code = tmpl.gsub(/./) do
|
||||||
|
if $& == ?# || ($& != " " && count == 3)
|
||||||
|
c = code.slice!(0, 1)
|
||||||
|
count += 1 if c == ?"
|
||||||
|
c
|
||||||
|
else
|
||||||
|
$&
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
File.write(ARGV[1], code)
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# generate a table of error correction codewords
|
||||||
|
|
||||||
|
RS_BLOCK_TABLE = [
|
||||||
|
[ 26, 1, 26, 19],
|
||||||
|
[ 44, 1, 44, 34],
|
||||||
|
[ 70, 1, 70, 55],
|
||||||
|
[ 100, 1, 100, 80],
|
||||||
|
[ 134, 1, 134, 108],
|
||||||
|
[ 172, 2, 86, 68],
|
||||||
|
[ 196, 2, 98, 78],
|
||||||
|
[ 242, 2, 121, 97],
|
||||||
|
[ 292, 2, 146, 116],
|
||||||
|
[ 346, 2, 86, 68, 2, 87, 69],
|
||||||
|
[ 404, 4, 101, 81],
|
||||||
|
[ 466, 2, 116, 92, 2, 117, 93],
|
||||||
|
[ 532, 4, 133, 107],
|
||||||
|
[ 581, 3, 145, 115, 1, 146, 116],
|
||||||
|
[ 655, 5, 109, 87, 1, 110, 88],
|
||||||
|
[ 733, 5, 122, 98, 1, 123, 99],
|
||||||
|
[ 815, 1, 135, 107, 5, 136, 108],
|
||||||
|
[ 901, 5, 150, 120, 1, 151, 121],
|
||||||
|
[ 991, 3, 141, 113, 4, 142, 114],
|
||||||
|
[1085, 3, 135, 107, 5, 136, 108],
|
||||||
|
[1156, 4, 144, 116, 4, 145, 117],
|
||||||
|
[1258, 2, 139, 111, 7, 140, 112],
|
||||||
|
[1364, 4, 151, 121, 5, 152, 122],
|
||||||
|
[1474, 6, 147, 117, 4, 148, 118],
|
||||||
|
[1588, 8, 132, 106, 4, 133, 107],
|
||||||
|
[1706, 10, 142, 114, 2, 143, 115],
|
||||||
|
[1828, 8, 152, 122, 4, 153, 123],
|
||||||
|
[1921, 3, 147, 117, 10, 148, 118],
|
||||||
|
[2051, 7, 146, 116, 7, 147, 117],
|
||||||
|
[2185, 5, 145, 115, 10, 146, 116],
|
||||||
|
[2323, 13, 145, 115, 3, 146, 116],
|
||||||
|
[2465, 17, 145, 115],
|
||||||
|
[2611, 17, 145, 115, 1, 146, 116],
|
||||||
|
[2761, 13, 145, 115, 6, 146, 116],
|
||||||
|
[2876, 12, 151, 121, 7, 152, 122],
|
||||||
|
[3034, 6, 151, 121, 14, 152, 122],
|
||||||
|
[3196, 17, 152, 122, 4, 153, 123],
|
||||||
|
[3362, 4, 152, 122, 18, 153, 123],
|
||||||
|
[3532, 20, 147, 117, 4, 148, 118],
|
||||||
|
[3706, 19, 148, 118, 6, 149, 119],
|
||||||
|
]
|
||||||
|
|
||||||
|
s = ""
|
||||||
|
RS_BLOCK_TABLE.each.with_index(1) do |a, v|
|
||||||
|
size_1 = 4 * v + 16
|
||||||
|
|
||||||
|
total_codes, n1, c1, k1, n2, c2, k2 = *a
|
||||||
|
s << (total_codes * 54 / 265 - (n2 ? n1 + n2 : n1) * (c1 - k1) + 43)
|
||||||
|
end
|
||||||
|
|
||||||
|
p s
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
require_relative "machine"
|
||||||
|
|
||||||
|
Table = "))*+,**,*)-)/),0).0(6/2+667,(&$###;=@D*0"
|
||||||
|
|
||||||
|
def compress(s)
|
||||||
|
t = "\0".b * s.size
|
||||||
|
a = [nil] * s.size
|
||||||
|
n = 0
|
||||||
|
30.downto(3) do |len|
|
||||||
|
(s.size - 1).downto(0) do |i|
|
||||||
|
j = s[0, i + len - 1].rindex(s[i, len])
|
||||||
|
if s[i, len].size == len && j && i - j < 90 && t[i, len] == "\0".b * len && !s[j..i].include?(?Q)
|
||||||
|
n += 1
|
||||||
|
t[i, len] = (i-j).chr * len
|
||||||
|
a[i] = [i-j, len]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
n = 0
|
||||||
|
s = t.gsub(/(.)\1{,56}/m) do
|
||||||
|
offset = $`.size
|
||||||
|
len = $&.size
|
||||||
|
raise if len > 92 - 34
|
||||||
|
if $1 == "\0"
|
||||||
|
(len + 34).chr + s[offset, len]
|
||||||
|
else
|
||||||
|
(len + 92).chr + ($1.ord + 36).chr
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ARGV.size != 2
|
||||||
|
puts "usage: #$0 <raw.txt> <prog.c>"
|
||||||
|
else
|
||||||
|
Code = File.read(ARGV[0])
|
||||||
|
|
||||||
|
vm_src = File.read("vm.c").lines.drop(1).join.gsub(/^\s*/, "").gsub("\n", "").chomp.gsub(/\s*\/\*.*?\*\//, "")
|
||||||
|
quine_data = compress("#include<stdio.h>@" + vm_src.gsub('"CODE"', "Q").gsub('"', """'"))
|
||||||
|
|
||||||
|
# back patch of absolute address
|
||||||
|
Code.gsub!(encode_number(39999)) { encode_number((Code ).size + 39901 - 1) }
|
||||||
|
Code.gsub!(encode_number(97531)) { encode_number((Code + Table ).size + 39901 - 1) }
|
||||||
|
Code.gsub!(encode_number(50000)) { encode_number((Code + Table + quine_data).size + 39901 + 1) }
|
||||||
|
|
||||||
|
File.write(ARGV[1], "#include<stdio.h>\n" + vm_src.sub("CODE") { Code + Table + quine_data } + "\n")
|
||||||
|
end
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
# 33 : not used
|
||||||
|
# 34 : NG
|
||||||
|
# 35..55 : read
|
||||||
|
# 56..76 : write
|
||||||
|
# 77..85 : binary op
|
||||||
|
# 86..91 : not used
|
||||||
|
# 92 : NG
|
||||||
|
# 93..98 : control (0..5)
|
||||||
|
# 99..104 : other insns (6..12)
|
||||||
|
# 105..126 : num (13..32)
|
||||||
|
|
||||||
|
MNEMONIC = {
|
||||||
|
:Nop => "",
|
||||||
|
|
||||||
|
:+ => 77.chr,
|
||||||
|
:- => 78.chr,
|
||||||
|
:* => 79.chr,
|
||||||
|
:"&&" => 79.chr,
|
||||||
|
:^ => 80.chr,
|
||||||
|
:> => 81.chr,
|
||||||
|
:/ => 82.chr,
|
||||||
|
:% => 83.chr,
|
||||||
|
:">>" => 84.chr, # 6
|
||||||
|
:"==" => 85.chr,
|
||||||
|
|
||||||
|
:BranchS => 93.chr, # 0 -> BranchM
|
||||||
|
:LoopM => 94.chr, # 1 -> LoopE
|
||||||
|
:BranchM => 95.chr, # 2 -> BranchE
|
||||||
|
:LoopE => 96.chr, # 3 -> LoopS (back)
|
||||||
|
:BranchE => 97.chr, # 4
|
||||||
|
:LoopS => 98.chr, # 5
|
||||||
|
|
||||||
|
:ARef => 99.chr, # 6
|
||||||
|
:ASet => 100.chr, # 7
|
||||||
|
:Out => 101.chr, # 8
|
||||||
|
:Exit => 102.chr, # 9
|
||||||
|
:Inc => 103.chr, # 10
|
||||||
|
:Dec => 104.chr, # 11
|
||||||
|
|
||||||
|
:Test => 105.chr,
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_READ = 35
|
||||||
|
REGISTER_WRITE = 56
|
||||||
|
IMM = 106
|
||||||
|
|
||||||
|
def encode_number(n)
|
||||||
|
if n >= 0
|
||||||
|
tt = n.to_s(126 - IMM + 1).tr("0-9a-z", [*IMM.chr..126.chr].join)
|
||||||
|
raise if tt[0] == 126.chr
|
||||||
|
tt[0, 1] = tt[0].tr([*IMM.chr..125.chr].join, [*(IMM + 1).chr..126.chr].join)
|
||||||
|
else
|
||||||
|
raise if n != -1
|
||||||
|
tt = IMM.chr
|
||||||
|
end
|
||||||
|
tt
|
||||||
|
end
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
# parse pseudo Ruby code and generate AST
|
||||||
|
|
||||||
|
require_relative "ast-def"
|
||||||
|
require "ripper"
|
||||||
|
|
||||||
|
Subroutines = {}
|
||||||
|
|
||||||
|
def expr(e)
|
||||||
|
case e[0]
|
||||||
|
when :binary then PBinary[e[2], expr(e[1]), expr(e[3])]
|
||||||
|
when :var_ref, :vcall
|
||||||
|
name = e[1][1]
|
||||||
|
case name
|
||||||
|
when "nop" then PNop[]
|
||||||
|
when "minus1" then PImm[-1]
|
||||||
|
when "Zero" then PImm[0]
|
||||||
|
else PRead[name]
|
||||||
|
end
|
||||||
|
when :aref then PARef[expr(e[1]), expr(e[2][1][0])]
|
||||||
|
when :assign then PASet[expr(e[1][1]), expr(e[1][2][1][0]), expr(e[2])]
|
||||||
|
when :@int then PImm[e[1].to_i]
|
||||||
|
when :paren
|
||||||
|
PSequence[statements(e[1][0..-2]), expr(e[1][-1])]
|
||||||
|
when :ifop
|
||||||
|
PIfThenElse[expr(e[1]), expr(e[2]), expr(e[3])]
|
||||||
|
when :method_add_arg
|
||||||
|
case e[1][1][1]
|
||||||
|
when "inc", "dec"
|
||||||
|
r = e[2][1][1][0][1][1]
|
||||||
|
PSequence[
|
||||||
|
[PAssign[r, PBinary[e[1][1][1] == "inc" ? :+ : :-, PRead[r], PImm[1]]]],
|
||||||
|
PRead[r]
|
||||||
|
]
|
||||||
|
else
|
||||||
|
pp e
|
||||||
|
raise e[1][1][1]
|
||||||
|
end
|
||||||
|
when Array then expr(e[0])
|
||||||
|
else
|
||||||
|
pp e
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def statement(e)
|
||||||
|
case e[0]
|
||||||
|
when :assign then PAssign[e[1][1][1], expr(e[2])]
|
||||||
|
when :method_add_block
|
||||||
|
if e[1][1][1][1] == "loop"
|
||||||
|
PLoop[expr(e[1][2][1][1]), statements(e[2][2])]
|
||||||
|
else
|
||||||
|
pp e
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
when :command
|
||||||
|
case e[1][1]
|
||||||
|
when "call" then Subroutines[e[2][1][0][1][1]]
|
||||||
|
when "exit" then PExit[expr(e[2][1][0])]
|
||||||
|
when "out" then POut[expr(e[2][1][0])]
|
||||||
|
when "test" then PTest[expr(e[2][1][0])]
|
||||||
|
else
|
||||||
|
pp e
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
when :void_stmt then PNop[]
|
||||||
|
else
|
||||||
|
pp e
|
||||||
|
raise e[0].to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def statements(s)
|
||||||
|
s.map {|e| statement(e) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def program(e)
|
||||||
|
e[1].each do |e|
|
||||||
|
Subroutines[e[1][1][1][1]] = statements(e[2][2])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ARGV.size != 2
|
||||||
|
puts "usage: #$0 <src.rb> <ast.txt>"
|
||||||
|
else
|
||||||
|
program(Ripper.sexp(File.read(ARGV[0])))
|
||||||
|
File.write(ARGV[1], Subroutines["main"].pretty_inspect)
|
||||||
|
end
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
char*s="CODE",*p,b,d[9338],*q,x,*r=d;
|
||||||
|
int main(){
|
||||||
|
;for(p=q=5000+0+d;*s;s++)if(*s>32)*p++=*s-89?*s:32;
|
||||||
|
for(p=INDX+q;(b=*p++);){
|
||||||
|
for(d[17]=10;x=*p++,b<92&&34<b--;*r++=x)if(x==9*9)
|
||||||
|
for(;*q;x=34)*r++=*q++;
|
||||||
|
for(p-=b<92;b-->4*23;r++)*r=r[36-x];
|
||||||
|
}
|
||||||
|
puts(d);
|
||||||
|
return(0);
|
||||||
|
}/*IOCCC2014IOCCC2014IOCCC2014IOCCC2014IOCCC*/
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
# Q(uine)R code generator
|
||||||
|
|
||||||
|
## What is difficult?
|
||||||
|
|
||||||
|
As you may know, QR code (specification: ISO/IEC 18004) is quite complex.
|
||||||
|
It requires a bit stream, Reed-Solomon codes, BCH codes,
|
||||||
|
data relocation, big (and irregular!) numerical tables,
|
||||||
|
human-oriented pattern arrangement (difficult to implement by a small program),
|
||||||
|
etc.
|
||||||
|
|
||||||
|
On the other hand, a quine has a big restriction:
|
||||||
|
it needs to have two copies of the program!
|
||||||
|
|
||||||
|
Do you think that it is possible to write QR code encoder in C within *1kB*?
|
||||||
|
|
||||||
|
|
||||||
|
## How did I achieve that?
|
||||||
|
|
||||||
|
It is known that we can mitigate the quine restriction by `eval`.
|
||||||
|
For example, this is a quine written in Ruby:
|
||||||
|
|
||||||
|
eval s="print 'eval s='; p s"
|
||||||
|
|
||||||
|
Note that `print` appears just once in the program.
|
||||||
|
|
||||||
|
To emulate this approach in C, I adopted the following structure.
|
||||||
|
|
||||||
|
char s[]="<main code>int main() { <VM code> }";
|
||||||
|
int main() { <VM code>; }
|
||||||
|
|
||||||
|
* `<VM code>` : An own VM implementation (written in C) that executes the main code
|
||||||
|
* `<main code>` : An object code of quine and QR code encoder (written in the assembly language of the VM)
|
||||||
|
|
||||||
|
`<main code>` (about 1100 bytes) appears once
|
||||||
|
and `<VM code>` (about 450 bytes) appears twice.
|
||||||
|
So the whole code is about 1100 + 450 * 2 = 2000 bytes. Hooray!
|
||||||
|
|
||||||
|
|
||||||
|
## What sort of VM is that?
|
||||||
|
|
||||||
|
The VM is a kind of stack machine which makes the object code compact.
|
||||||
|
The instruction set is carefully selected
|
||||||
|
to minimize the sizes of both `<main code>` and `<VM code>`.
|
||||||
|
|
||||||
|
* 21 integer registers access
|
||||||
|
* read, write, inc-and-read, dec-and-read
|
||||||
|
* Binary operations
|
||||||
|
* add, sub, mul, div, mod, xor, less than, equal, rshift
|
||||||
|
* Stack operation
|
||||||
|
* push (an immediate value)
|
||||||
|
* Heap access
|
||||||
|
* load, store
|
||||||
|
* If-Then-Else
|
||||||
|
* While-Loop
|
||||||
|
* Misc.
|
||||||
|
* putchar, exit
|
||||||
|
|
||||||
|
The instructions have variable length,
|
||||||
|
but many of them are represented as one printable character.
|
||||||
|
(See `machine.rb` and `assemble.rb` in detail.)
|
||||||
|
The mapping between instructions and characters is also carefully designed
|
||||||
|
to minimize `<VM code>`,
|
||||||
|
which makes the resulted program non-human-readable.
|
||||||
|
|
||||||
|
|
||||||
|
## How did I create the main code?
|
||||||
|
|
||||||
|
It is too tedious to write the machine language directly.
|
||||||
|
So I wrote the source code in Ruby syntax and created a Ruby-to-VM compiler
|
||||||
|
that involves alpha renaming and automatic register allocation
|
||||||
|
only for this purpose.
|
||||||
|
|
||||||
|
* `src.rb`: the source code of QR code encoder written in Ruby syntax.
|
||||||
|
* `vm.c`: the source code of the VM.
|
||||||
|
|
||||||
|
The compiler tool chain is the following.
|
||||||
|
|
||||||
|
src.rb interp.c
|
||||||
|
| |
|
||||||
|
| [parse.rb] |
|
||||||
|
V |
|
||||||
|
ast.txt |
|
||||||
|
| |
|
||||||
|
| [serialize.rb] |
|
||||||
|
V |
|
||||||
|
seq.txt |
|
||||||
|
| |
|
||||||
|
| [alpha.rb] |
|
||||||
|
V |
|
||||||
|
alpha.txt |
|
||||||
|
| |
|
||||||
|
| [register.rb] |
|
||||||
|
V |
|
||||||
|
reg.txt |
|
||||||
|
| |
|
||||||
|
| [assemble.rb] |
|
||||||
|
V |
|
||||||
|
raw.txt |
|
||||||
|
| |
|
||||||
|
+---------+---------+
|
||||||
|
|
|
||||||
|
| [link.rb]
|
||||||
|
V
|
||||||
|
main.c
|
||||||
|
|
|
||||||
|
| [gen-prog.c]
|
||||||
|
V
|
||||||
|
prog.c
|
||||||
|
|
||||||
|
* `parse.rb` converts Ruby to AST.
|
||||||
|
* `serialize.rb` converts AST to intermediate instruction sequence.
|
||||||
|
* `alpha.rb` applies "alpha-renaming" to the instruction sequence.
|
||||||
|
* `register.rb` applies "register allocation".
|
||||||
|
* `assemble.rb` converts the sequence to the final stack-machine instructions.
|
||||||
|
* `interp.c` is an implementation of the VM.
|
||||||
|
* `link.rb` generates `main.c` by linking the instructions and interpreter source.
|
||||||
|
* `gen-prog.c` generates `prog.c` based on `main.c`
|
||||||
|
|
||||||
|
You can run the process by `rake` command. `ruby-minisat` gem is needed.
|
||||||
|
|
||||||
|
$ gem install ruby-minisat
|
||||||
|
$ rake
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
|
||||||
|
I checked that the following QR code readers can read the output of my program.
|
||||||
|
|
||||||
|
* Linux: [ZBar bar code reader][1]
|
||||||
|
* Android: [Barcode Scanner][2]
|
||||||
|
|
||||||
|
[1]: http://zbar.sourceforge.net/
|
||||||
|
[2]: https://play.google.com/store/apps/details?id=com.google.zxing.client.android]
|
||||||
|
|
||||||
|
You can use `tool.rb` to convert the output to a png file.
|
||||||
|
|
||||||
|
$ ./main Hello | ruby tool.rb > hello.png
|
||||||
|
|
||||||
|
$ zbarimg -q hello.png
|
||||||
|
QR-Code:Hello
|
||||||
|
|
||||||
|
$ ruby tool.rb prog.c
|
||||||
|
$ ruby tool.rb prog.c | ruby tool.rb
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
* QR code error correction level is fixed to L (Low).
|
||||||
|
* It supports only byte mode (not numeric, alphanumeric, kanji mode...)
|
||||||
|
* The mask pattern is fixed to 4.
|
||||||
|
* The mask is not applied to the remained bits.
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
# register allocation (variable renaming again!)
|
||||||
|
|
||||||
|
require_relative "ast-def"
|
||||||
|
require "minisat"
|
||||||
|
|
||||||
|
Conflicts = {}
|
||||||
|
|
||||||
|
def liveness(seq, vars)
|
||||||
|
nvars = vars.dup
|
||||||
|
|
||||||
|
seq.reverse_each do |insn|
|
||||||
|
case insn
|
||||||
|
when IRead, IWrite
|
||||||
|
nvars[insn.var] = true if insn.var
|
||||||
|
when IExit
|
||||||
|
nvars.clear
|
||||||
|
when IBranch
|
||||||
|
nvars1 = liveness(insn.s1, nvars)
|
||||||
|
nvars2 = liveness(insn.s2, nvars)
|
||||||
|
nvars = nvars1.merge(nvars2)
|
||||||
|
when ILoop
|
||||||
|
begin
|
||||||
|
nvars_back = nvars
|
||||||
|
nvars1 = liveness(insn.s1, nvars)
|
||||||
|
nvars2 = liveness(insn.s1, liveness(insn.s2, nvars))
|
||||||
|
nvars = nvars1.merge(nvars2)
|
||||||
|
end until nvars.keys == nvars_back.keys
|
||||||
|
end
|
||||||
|
|
||||||
|
nvars.keys.sort.combination(2) do |v1, v2|
|
||||||
|
Conflicts[[v1, v2].sort] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
nvars.delete(insn.var) if insn.is_a?(IWrite) && insn.var
|
||||||
|
end
|
||||||
|
|
||||||
|
nvars
|
||||||
|
end
|
||||||
|
|
||||||
|
def graph_coloring(liveness, k)
|
||||||
|
solver = MiniSat::Solver.new
|
||||||
|
|
||||||
|
h = {}
|
||||||
|
|
||||||
|
liveness.keys.flatten.uniq.each do |var|
|
||||||
|
vs = (0...k).map { solver.new_var }
|
||||||
|
solver << vs
|
||||||
|
vs.combination(2) {|v1, v2| solver << [-v1, -v2] }
|
||||||
|
h[var] = vs
|
||||||
|
end
|
||||||
|
|
||||||
|
liveness.each_key do |var1, var2|
|
||||||
|
h[var1].zip(h[var2]) {|v1, v2| solver << [-v1, -v2] }
|
||||||
|
end
|
||||||
|
|
||||||
|
solver.solve
|
||||||
|
|
||||||
|
h.each do |var, vs|
|
||||||
|
h[var] = (vs.find_index {|v| solver[v] } + ?a.ord).chr
|
||||||
|
end
|
||||||
|
h
|
||||||
|
end
|
||||||
|
|
||||||
|
def rename(seq, h)
|
||||||
|
seq.each do |insn|
|
||||||
|
case insn
|
||||||
|
when IRead, IWrite
|
||||||
|
insn.var.replace h[insn.var] if insn.var
|
||||||
|
when IBranch, ILoop
|
||||||
|
rename(insn.s1, h)
|
||||||
|
rename(insn.s2, h)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ARGV.size != 2
|
||||||
|
puts "usage: #$0 <seq2.txt> <seq3.txt>"
|
||||||
|
else
|
||||||
|
seq = eval(File.read(ARGV[0]))
|
||||||
|
liveness(seq, {})
|
||||||
|
rename(seq, graph_coloring(Conflicts, 21))
|
||||||
|
File.write(ARGV[1], seq.pretty_inspect)
|
||||||
|
end
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
# translate AST into stack-based instruction sequence
|
||||||
|
|
||||||
|
require_relative "ast-def"
|
||||||
|
|
||||||
|
class PRead
|
||||||
|
def emit
|
||||||
|
[IRead[var]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class PImm
|
||||||
|
def emit
|
||||||
|
[IPush[num]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class PNop
|
||||||
|
def emit
|
||||||
|
[INop[]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class PBinary
|
||||||
|
def emit
|
||||||
|
if op == :<
|
||||||
|
e2.emit + e1.emit + [IBinary[:>]]
|
||||||
|
else
|
||||||
|
e1.emit + e2.emit + [IBinary[op]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class PIfThenElse
|
||||||
|
def emit
|
||||||
|
s1 = e1.emit
|
||||||
|
s2 = e2.emit
|
||||||
|
|
||||||
|
# merge the common tails if any
|
||||||
|
tails = []
|
||||||
|
s1.reverse.zip(s2.reverse) do |i1, i2|
|
||||||
|
break if i1 != i2
|
||||||
|
s1.pop
|
||||||
|
s2.pop
|
||||||
|
tails.unshift i1
|
||||||
|
end
|
||||||
|
|
||||||
|
cond.emit + [IBranch[s1, s2]] + tails
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class PARef
|
||||||
|
def emit
|
||||||
|
if e1 == PImm[0] && e2.is_a?(PBinary) && e2.op == :+
|
||||||
|
e2.emit[0..-2] + [IARef[]]
|
||||||
|
elsif e2 == PImm[0] && e1.is_a?(PBinary) && e1.op == :+
|
||||||
|
e1.emit[0..-2] + [IARef[]]
|
||||||
|
else
|
||||||
|
e1.emit + e2.emit + [IARef[]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class PASet
|
||||||
|
def emit
|
||||||
|
if e1 == PImm[0] && e2.is_a?(PBinary) && e2.op == :+
|
||||||
|
e3.emit + e2.emit[0..-2] + [IASet[]]
|
||||||
|
elsif e2 == PImm[0] && e1.is_a?(PBinary) && e1.op == :+
|
||||||
|
e3.emit + e1.emit[0..-2] + [IASet[]]
|
||||||
|
else
|
||||||
|
e3.emit + e2.emit + e1.emit + [IASet[]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class PAssign
|
||||||
|
def emit
|
||||||
|
exp.emit + [IWrite[var != ?_ ? var : nil]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class PSequence
|
||||||
|
def emit
|
||||||
|
seq.flat_map {|e| e.emit } + e.emit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class PLoop
|
||||||
|
def emit
|
||||||
|
[ILoop[cond.emit, body.flat_map {|e| e.emit }]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class PTest
|
||||||
|
def emit
|
||||||
|
e.emit + [ITest[]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class PExit
|
||||||
|
def emit
|
||||||
|
e.emit + [IExit[]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class POut
|
||||||
|
def emit
|
||||||
|
e.emit + [IOut[]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Array
|
||||||
|
def emit
|
||||||
|
flat_map {|e| e.emit }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ARGV.size != 2
|
||||||
|
puts "usage: #$0 <ast.txt> <seq1.txt>"
|
||||||
|
else
|
||||||
|
ast = eval(File.read(ARGV[0]))
|
||||||
|
File.write(ARGV[1], ast.flat_map {|e| e.emit }.pretty_inspect)
|
||||||
|
end
|
||||||
@@ -0,0 +1,280 @@
|
|||||||
|
# magical calculation methods!
|
||||||
|
|
||||||
|
# calculate the total code words for the version given
|
||||||
|
total_codewords {
|
||||||
|
n = Version / 7 * 5 + 5
|
||||||
|
TotalCodes =
|
||||||
|
Size_1 * Size_1 / 8 - 24 -
|
||||||
|
(Version > 6 ? n * n / 8 + n : (Version > 1) * 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
# calculate the error correction code words for the version given
|
||||||
|
error_correction_codewords {
|
||||||
|
ECCodes = TotalCodes * 54 / 265 - Zero[39999 + Version] + 43
|
||||||
|
}
|
||||||
|
|
||||||
|
# calculate the degree of the generator polynomial
|
||||||
|
generator_polynomial_degree {
|
||||||
|
Degree =
|
||||||
|
Version < 6 ? ECCodes :
|
||||||
|
Version == 10 ? 18:
|
||||||
|
(n = 16
|
||||||
|
loop(ECCodes / 2 % dec(n)) { }
|
||||||
|
n * 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
other_constants {
|
||||||
|
N = ECCodes / Degree
|
||||||
|
M = N - TotalCodes % N
|
||||||
|
K = (TotalCodes - ECCodes) / N + 1
|
||||||
|
S = Degree + K
|
||||||
|
D = K * N - M
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# GF(2^8)
|
||||||
|
gen_table {
|
||||||
|
i = 511
|
||||||
|
j = 1
|
||||||
|
loop(i) {
|
||||||
|
j = ((Forward[Backward[j] = dec(i)] = j) ^ (285 * (j % 2))) / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# calculate the generator polynomial
|
||||||
|
setup_generator_polynomial {
|
||||||
|
i = Degree + 1
|
||||||
|
loop(dec(i)) {
|
||||||
|
j = Degree + 1
|
||||||
|
x = 0
|
||||||
|
loop(j > i) {
|
||||||
|
y = Coefs[dec(j)]
|
||||||
|
dummy = Coefs[j] = Backward[x ^ Forward[Degree - i + y]]
|
||||||
|
x = Forward[y]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# paint fixed cells
|
||||||
|
setup_fixed_patterns {
|
||||||
|
# three big markers
|
||||||
|
i = Size
|
||||||
|
loop(i) {
|
||||||
|
i = i - 1
|
||||||
|
j = Size
|
||||||
|
loop(j) {
|
||||||
|
k = i - j * Size
|
||||||
|
dummy =
|
||||||
|
Zero[j * Size + i] =
|
||||||
|
Zero[minus1 - k] =
|
||||||
|
Zero[Size * Size + k] =
|
||||||
|
(i < 7 && dec(j) < 7 && (((i - 6) * i + 19 + (j - 6) * j) / 5) ^ 2 < 3) -
|
||||||
|
((i > 7) + (j > 7) > 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# alignment markers
|
||||||
|
x = Version / 7 + 2
|
||||||
|
n = Version - 32 ? (Version + x / 2) * 2 / (x - 1) * 2 : 26
|
||||||
|
i = x * x
|
||||||
|
loop(Version > 1 && dec(i) > 1) {
|
||||||
|
j = 25
|
||||||
|
loop(i - x && j) {
|
||||||
|
y = Size_1 - 8 + n
|
||||||
|
dummy = Zero[
|
||||||
|
((y - i / x * n) % (y - 4) + j / 5) * Size +
|
||||||
|
((y - i % x * n) % (y - 4) + j % 5)
|
||||||
|
] = (33084991 >> dec(j)) % 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# BCH for version info
|
||||||
|
n = Version * 4096
|
||||||
|
k = n
|
||||||
|
j = 64
|
||||||
|
loop(j) {
|
||||||
|
k = k ^ ((7973 * j) * (k + 1 > 4096 * j))
|
||||||
|
j = j / 2
|
||||||
|
}
|
||||||
|
# (n + k) is the code
|
||||||
|
|
||||||
|
# version info and timing
|
||||||
|
i = 18 * (Version > 6)
|
||||||
|
loop(i + Size - 16) {
|
||||||
|
dummy =
|
||||||
|
Zero[x * Size + y] =
|
||||||
|
Zero[y * Size + x] =
|
||||||
|
dec(i) < 0 ?
|
||||||
|
(x = Size - 8 + i ; y = 6 ; (0 - i) % 2) :
|
||||||
|
(x = Size - 11 + i % 3; y = i / 3; ((n + k) >> i) % 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
# format info
|
||||||
|
i = 15
|
||||||
|
loop(i) {
|
||||||
|
# BCH for format info (4 + 8) (mask = 4, error correction level = L)
|
||||||
|
# 26159 is the code
|
||||||
|
n = dec(i) > 7 ? Size_1 - 14 + i : i + (i > 5)
|
||||||
|
dummy =
|
||||||
|
Zero[Size * (Size - 8) + 8] =
|
||||||
|
Zero[n * Size + 8] =
|
||||||
|
Zero[9 * Size_1 - n + 8 + (i / 3 == 2)] =
|
||||||
|
(26159 >> i) % 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# data encoding
|
||||||
|
setup_data {
|
||||||
|
n = minus1
|
||||||
|
buff = 64
|
||||||
|
z = 17
|
||||||
|
j = 0
|
||||||
|
loop(inc(n) < D) {
|
||||||
|
x = Input[j]
|
||||||
|
_ = x ?
|
||||||
|
(y = V9 < 0 ? (j = j + 1; x) : (V9 = V9 - 1; V9 ? InputLen % 256 : (InputLen >> 8))
|
||||||
|
emit = buff + y / 16
|
||||||
|
buff = (y % 16) * 16
|
||||||
|
nop) :
|
||||||
|
(emit = buff
|
||||||
|
z = z ^ 253
|
||||||
|
buff = z
|
||||||
|
nop)
|
||||||
|
dummy = EncodedData[n] = emit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# error correction
|
||||||
|
encode {
|
||||||
|
x = D
|
||||||
|
i = N
|
||||||
|
loop(i) {
|
||||||
|
y = D + S * i
|
||||||
|
n = K - (dec(i) < M)
|
||||||
|
j = n + Degree
|
||||||
|
loop(j) {
|
||||||
|
dummy = EncodedData[dec(y)] = dec(j) < n ? EncodedData[dec(x)] : 0
|
||||||
|
}
|
||||||
|
loop(j < n * Degree) {
|
||||||
|
t = j % Degree + 1
|
||||||
|
idx = EncodedData + y + j / Degree
|
||||||
|
dummy = idx[t] = idx[t] ^ ((idx[0] > 0) * Forward[Coefs[t] + Backward[idx[0]]])
|
||||||
|
j = j + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# make the pattern by placing the data
|
||||||
|
place {
|
||||||
|
x = Size_1
|
||||||
|
y = Size_1
|
||||||
|
j = minus1
|
||||||
|
loop(inc(j) < S) {
|
||||||
|
i = M * (j == K - 1)
|
||||||
|
loop(i < N) {
|
||||||
|
t = 8
|
||||||
|
loop(t) {
|
||||||
|
xx = x + (x > 5)
|
||||||
|
_ = Zero[y * Size + xx] < 0 ?
|
||||||
|
(dummy = Zero[y * Size + xx] =
|
||||||
|
((EncodedData[j + (j < K ? i * K - (i < M ? i : M) : D + i * S)] >> dec(t)) ^
|
||||||
|
(y / 2 + xx / 3)) % 2 == 0;
|
||||||
|
nop) : nop
|
||||||
|
x = x -
|
||||||
|
(x % 2 ? 1 :
|
||||||
|
(x / 2 % 2 ?
|
||||||
|
(y ? (y = y - 1; minus1) : 1) :
|
||||||
|
(y - Size_1 ? (y = y + 1; minus1) : 1)))
|
||||||
|
}
|
||||||
|
i = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# print the pattern to stdout
|
||||||
|
output {
|
||||||
|
k = Size + 4
|
||||||
|
y = Size_1 - k
|
||||||
|
loop(inc(y) < k) {
|
||||||
|
x = Size_1 - k
|
||||||
|
loop(inc(x) < k) {
|
||||||
|
out 27; out 91; out 52
|
||||||
|
out 55 -
|
||||||
|
(x > minus1 && x < Size && y > minus1 && y < Size) *
|
||||||
|
(x + y * Size < 0 ? 0 : (Zero[x + y * Size] > 0)) * 7
|
||||||
|
out 109; out 32; out 32
|
||||||
|
}
|
||||||
|
out 27; out 91; out 48; out 109; out 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate the code itself by decompression
|
||||||
|
decompress {
|
||||||
|
i = 97531 # a placeholder value that will be replaced by assemble.rb
|
||||||
|
InputLen = minus1
|
||||||
|
# decompress
|
||||||
|
loop((b = Zero[inc(i)]; b)) {
|
||||||
|
_ = b < 92 ?
|
||||||
|
(loop(dec(b) > 33) {
|
||||||
|
x = Zero[inc(i)]
|
||||||
|
_ = x - 81 ? nop :
|
||||||
|
(k = 39900 # quine
|
||||||
|
x = Input[inc(InputLen)] = 34
|
||||||
|
loop((z = Zero[inc(k)]; z)) {
|
||||||
|
dummy = Input[inc(InputLen)] = z
|
||||||
|
}
|
||||||
|
nop
|
||||||
|
)
|
||||||
|
dummy = Input[inc(InputLen)] = x
|
||||||
|
}
|
||||||
|
nop) :
|
||||||
|
(i = i + 1
|
||||||
|
loop(dec(b) > 91) {
|
||||||
|
dummy = Input[InputLen] = Input[inc(InputLen) - i[0] + 36]
|
||||||
|
}
|
||||||
|
nop)
|
||||||
|
}
|
||||||
|
InputLen = InputLen + 1
|
||||||
|
dummy = 17[Input] = 10 # newline after "#include<stdio.h>"
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
# memory layout
|
||||||
|
# 0...31329: Pattern data
|
||||||
|
# 32000...32512: Forward translation of GF(2^8)
|
||||||
|
# 32512...32768: Backward translation of GF(2^8)
|
||||||
|
# 32800...33000: Coefficients of generator polynomial
|
||||||
|
# 33000...37000: EncodedData
|
||||||
|
# 40000... : Code + nul + Input
|
||||||
|
Forward = 32000
|
||||||
|
Backward = 32512
|
||||||
|
Coefs = 32800
|
||||||
|
EncodedData = 33000
|
||||||
|
Input = 50000 # a placeholder
|
||||||
|
|
||||||
|
loop(Input[InputLen]) { InputLen = InputLen + 1 }
|
||||||
|
_ = InputLen ? nop : (call decompress; nop)
|
||||||
|
|
||||||
|
Version = 0
|
||||||
|
loop(Version < 40) {
|
||||||
|
Size_1 = 4 * inc(Version) + 16
|
||||||
|
Size = Size_1 + 1
|
||||||
|
call total_codewords
|
||||||
|
call error_correction_codewords
|
||||||
|
call generator_polynomial_degree
|
||||||
|
call other_constants
|
||||||
|
V9 = Version > 9
|
||||||
|
_ = D - 1 - V9 > InputLen ? (
|
||||||
|
call gen_table
|
||||||
|
call setup_generator_polynomial
|
||||||
|
call setup_fixed_patterns
|
||||||
|
call setup_data
|
||||||
|
call encode
|
||||||
|
call place
|
||||||
|
call output
|
||||||
|
exit 0
|
||||||
|
nop
|
||||||
|
) : nop
|
||||||
|
}
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -0,0 +1,49 @@
|
|||||||
|
require "zlib"
|
||||||
|
|
||||||
|
lines = [*$<]
|
||||||
|
|
||||||
|
if lines.join.gsub(/\e\[\d*m/, "").chars.uniq.sort == ["\n", " "]
|
||||||
|
|
||||||
|
matrix = lines.map do |line|
|
||||||
|
row = []
|
||||||
|
cell = nil
|
||||||
|
line.chomp.scan(/\G(?:\e\[(\d+)m|..)/) do
|
||||||
|
if $1
|
||||||
|
cell = $1 == "40" ? :black : :white
|
||||||
|
else
|
||||||
|
row << cell
|
||||||
|
end
|
||||||
|
end
|
||||||
|
row
|
||||||
|
end
|
||||||
|
|
||||||
|
size = matrix.size
|
||||||
|
if size != matrix.first.size
|
||||||
|
raise "not square: #{ matrix.first.size } x #{ matrix.size }"
|
||||||
|
end
|
||||||
|
$stderr.puts "Version: #{ (size - 25) / 4 }"
|
||||||
|
|
||||||
|
scale = 400 / size
|
||||||
|
data = (0 ... scale * size).flat_map do |y|
|
||||||
|
[0] + (0 ... scale * size).flat_map do |x|
|
||||||
|
matrix[y / scale][x / scale] == :black ? [0, 0, 0] : [255, 255, 255]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
print "\x89PNG\r\n\x1a\n"
|
||||||
|
[
|
||||||
|
["IHDR", [scale * size, scale * size, 8, 2, 0, 0, 0].pack("NNCCCCC")],
|
||||||
|
["IDAT", Zlib::Deflate.deflate(data.pack("C*"))],
|
||||||
|
["IEND", ""],
|
||||||
|
].each do |type, data|
|
||||||
|
print [data.bytesize, type, data, Zlib.crc32(type + data)].pack("NA4A*N")
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
width = lines.map {|line| line.chomp.size + 4 * 4 }.max
|
||||||
|
lines.each do |line|
|
||||||
|
puts line.chomp.ljust(width).gsub(/../) { "\e[#{ $& == " " ? 47 : 40 }m " }
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#include<stdio.h>
|
||||||
|
int H[99999],*s,*c,d,t;
|
||||||
|
int main(int n,char*v[]){
|
||||||
|
for(s=c=H+39999;(*++s="CODE"[d++]););
|
||||||
|
for(;n>1&&(*++s=v[1][t++]););
|
||||||
|
/*for(;n=getchar(),n>0;)*++s=n;*/
|
||||||
|
for(s=H;d=*c++%93,d-9;){
|
||||||
|
int v=*s,g[]={n+v,v-n,n*v,v^n,n<v,n?v/n:0,n?v%n:0,v>>n,v==n};
|
||||||
|
for(t=0;d<4&&d>=2*!!n&&(c-=d/3*2,v=3+*c++,t||v!=98+d);)
|
||||||
|
t+=v++/6-16?0:v/2%3-1;
|
||||||
|
for(t=d-14;t>0&&d<34&&105<*c;)t=t*21+*c++-106;
|
||||||
|
n=
|
||||||
|
/*d==12?fprintf(stderr,"test:%d\n",n),*s--:*/
|
||||||
|
d>76?s--,g[d-77]: /* operation */
|
||||||
|
d>55?H[d-21]=n,*s--: /* reg write */
|
||||||
|
d>9?
|
||||||
|
*++s=n,
|
||||||
|
12>d?H[*c++]+=21-d*2: /* inc / dec */
|
||||||
|
d<34?t:H[d] /* imm push / reg read */
|
||||||
|
:
|
||||||
|
d>5?
|
||||||
|
s--,
|
||||||
|
7<d?putchar(n),v: /* out */
|
||||||
|
6<d?H[*g+99]=*s--: /* heap write */
|
||||||
|
H[*g+99]: /* heap read */
|
||||||
|
2>d?*s--:n; /* control */
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user