프로그래밍 언어 인터프리터 만들기 [닫기]


19

직무:

프로그래밍 언어의 스 니펫을 구문 분석 할 수있는 인터프리터를 작성해야합니다. 언어는 복잡 할 필요는 없지만 다음과 같은 구문 적 요소를 포함해야합니다.

  • 변수를 할당하고 읽을 수있는 기능 ( a-z 미리 만들어진 변수 인)
  • if 문 (elseif 등은 필요하지 않음)
  • 루프 (임의의 숫자로 계산, 카운터에 대한 사용자 액세스가 필요하지 않음)
  • 변수가있는 간단한 수학 (더하기, 빼기, 곱하기, 나누기, 같거나 큼)
  • 인쇄 문

규칙 :

  • 다른 인기있는 언어의 구문을 복사 할 수 없습니다.
  • 다른 통역사를 수정하지 말고 자신의 통역사를 작성해야합니다.
  • 모든 언어로 통역사를 작성할 수 있습니다.
  • 귀하의 언어로 99 가지 맥주 병 예제 프로그램을 작성하십시오 ( 여기 참조 ).
  • 이것은 이므로 가장 많이 찬성 된 답변이 이깁니다.

3
파서의 요구 사항은 무엇입니까? 어떤 종류의 구문 트리를 출력해야합니까?
Kendall Frey

1
변수 요구 사항을 충족 할 수있을만큼 스택에서 밀고 튀어 나올 수 있습니까?
tecywiz121

1
@
Dennis-

2
나는 그것이 통역사라고 생각합니다.
Kendall Frey

3
킨다는 Guido가 CPython을 제출하는 것을보고 싶다.
user2357112는 Monica

답변:


17

DogeScript

99 병의 맥주 프로그램 :

many amaze 99 time

such scare bottles-of-beer
such scream on-the-wall
many despair 13 time

such fail take-one-down-pass-it-around

wow

so amaze
so scare
so scream
so despair!

so amaze
so scare
so despair!

much amaze

so fail
so despair!

so amaze
so scare
so scream

so despair!
so despair!

very amaze

wow

PHP 인터프리터 :

<?php
$input=fopen('php://stdin', 'r');

//pre-process input
$input=preg_replace("/ +/", " ", $input); //replace any multiple spaces by a single space

//split into instructions by newlines
$instructions=explode("\n", $input);

$loopstartpoint= -1;
$variables=array();
$activevariable="";
for($instrpointer=0; $instrpointer<count($instructions); $instrpointer++)
{
    $tokens=explode(" ", $instructions[$instrpointer]);
    switch($tokens[0])
    {
        case "wow":
            if($loopstartpoint<0)
            {
                $loopstartpoint=$instrpointer+1;
            }
            else
            {
                if($variables[ $activevariable ])
                {
                    $instrpointer=$loopstartpoint;
                }
                else
                {
                    $loopstartpoint= -1;
                }
            }
            break;
        case "so":
            if(substr($tokens[1], -1)=="!")
            {
                echo chr($variables[ substr($tokens[1], 0, -1) ]);
            }
            else
            {
                echo $variables[ $tokens[1] ];
                echo " ";
            }
            break;
        case "very":
            $activevariable=$tokens[1];
            break;
        case "much":
            if(!isset($variables[ $tokens[1] ]))
                $variables[ $tokens[1] ]=0;
            if(count($tokens)==2)
            {
                $variables[ $tokens[1] ]--;
            }
            else
            {
                for($loop=0;$loop<$tokens[2];$loop++)
                {
                    $variables[ $tokens[1] ]--;
                }
            }
            $activevariable=$tokens[1];
            break;
        case "many":
            if(!isset($variables[ $tokens[1] ]))
                $variables[ $tokens[1] ]=0;
            if(count($tokens)==2)
            {
                $variables[ $tokens[1] ]++;
            }
            else
            {
                for($loop=0;$loop<$tokens[2];$loop++)
                {
                    $variables[ $tokens[1] ]++;
                }
            }
            $activevariable=$tokens[1];
            break;
        case "such":
            $variables[ $tokens[1] ]=$tokens[2];
            $activevariable=$tokens[1];
            break;
    }
}
?>

현재 구문은 다음과 같습니다.

wow - start and end loops, end of loop checks if active variable is 0 and loops if not
so without ! - print variable's value
so with ! - print variable's ASCII character
much - decrement this variable
many - increment this variable
such - set variable
very - make variable active
x time - does previous statement x times

Variables are initially 0.

여기에서 시도 하십시오 .
개선을위한 제안은 환영합니다.


2
prgramming lvl = 100
Antonio Ragagnin

1
이미 존재 한다는 것을 알고 있습니까?
AL

아뇨, 본 적 없어요 Bummer, 나는 독창적이라고 생각했다. :-(
Gareth

10

BrainBack : BrainFuck에서 실행되는 스택 기반 컴파일 언어

NB :이 답변을 게시 한 후 사양이 "구문 분석기 만들기"에서 "통역사 만들기"로 변경되었습니다. 이 답변은 소스 코드를 파싱하는 컴파일러입니다.

이름은 잘 알려진 스택 기반 언어와 Brain 의 반대 인 Back on Pun입니다 난해한 성격을 나타냅니다. BrainFuck과 비슷해 보이지만 컴파일러는 BrainFuck에서 실행되며 컴파일 된 객체 코드는 BrainFuck 바이너리로 끝납니다.

언어 : * == 인수를 파괴합니다

  • "constant" 일정한 인쇄
  • # 스택 상단을 숫자로 인쇄
  • > 스택의 상단을 복제
  • <num> 상수 <num>값을 스택의 상단으로 푸시
  • < 스택 상단 제거
  • - 두 번째 최상위에서 최상위를 빼기 *
  • + 최상위에 두 번째 최상위에 추가 *
  • ! 양수 / 제로 *를 토글하지 않음
  • [ ... ] BrainFuck과 매우 유사한 스택의 최상위가 0이 아닙니다.

BrainBack에서 올바른 가사와 맥주 99 병 :

100
[
 1 -
 > ! [ < 0 0 "No more" ] < [ # 0 ] <
 " bottle"
 > 1 - [ < 0 "s" ] < 
 " of beer on the wall, "
 > ! [ < 0 0 "no more" ] < [ # 0 ] <
 " bottle"
 > 1 - [ < 0 "s" ] < 
 " of beer.
"
 > ! [ < 0 0 "Go to the store and buy some more, " ] < 
     [ "Take one down and pass it around, " 0 ] <

 > ! [ < 1 0 0 "99" ] < [ > 1 - > !  [ < < 1 0 0 "no more" ] < [ # 1 - 0 ] ] <
 " bottle"
 [ < 0 "s" ] <
 " of beer on the wall.

"
]

Extended BrainFuck으로 작성된 BrainBack 컴파일러

;;; Macros

;; utility function that substracts 
;; ^2 from ^0 without reduceing ^2 
;; below zero. ^1 needs to be zero
{substract 
  (<<[->]>[<]>-)
}


;; Main macro is the main  program and
;; has the overal structure of the program.
;; every macro here is define in order below.
{main
  :i
  :wrk
  :tmp
  :else
  :sub 
  $i+(
  ; switch ( $wrk ) cases '"#><-+![]9;' using $tmp,$else
  $tmp+++++(-$wrk------)+$wrk---; !
  ($wrk-; "
    ($wrk-; #
      ($wrk--------; +
        ($wrk--; -
          ($wrk--- $tmp- $else 9+ &substract $tmp+ $wrk; 0-9
            ($wrk--; ;
              ($wrk-; <
                ($wrk--; >
                  ($tmp++++(-$wrk------)+$wrk+; [
                    ($wrk--; ]
                      (#(-) $tmp(-)  no matches)
                        $tmp (- #match 'cl'  &close        )
                    ) $tmp (- #match 'op'    &open         )
                  ) $tmp (- #match 'gt'      &dup          )
                ) $tmp (- #match 'lt'        &slash        )
              ) $tmp (  #match 'c'           &comment      )
            ) $tmp (- #match 0 to 9          &read_number  )
          ) $tmp (- #match 'minus'           &sub          )
        ) $tmp (- #match 'plus'              &add          )
      ) $tmp (- #match '#'                   &print_number )
    ) $tmp (- #match '"'                     &print_string )
  ) $tmp (- #match 'not'                     &not          )

  $i(-)$tmp#,+(-(-$wrk+$i+)))
  10+.
}

;; implements close bracket
{close 
    |" close"(-)
    $i.
}

;; implements open bracket
{open 
    |" open"(-)
    $i.
}

;; implements dup/>
{dup
    |"dup [->>+<<]>>[-<+<+>>]<
"
     (-)
}

;; implements slash/<
{slash
     |"slash [-]<
"
     (-)
}

;; implements comment
{comment
  [,10-]
}

;; implements read_number/<number>
;; makes code that if run makes 
;; the constant
{read_number
  ;TODO: compiler_read_constant_number
   $wrk|"number"(-)
#  $wrk 6+ (- $i 8-)
  ~"+>"<.(-)
  $i+(-(-$wrk.)
     #$else, $tmp 6+ (- $else 8-)
     $else(-$tmp+$i+)
     $sub 9+ &substract
     $else+
     $tmp((-) $i(-) $else-)
     $else(-|"[->++++++++++<]>[-<+>]<"(-)$i+)
     )
   $wrk(-)
   |"
"(-)
}

;; implements sub/-
{sub
     |"sub [-<->]<
"
     (-)
}

;; implements add/+
{add
     |"#add [-<+>]<
"
     (-)
}

;; implements print_number/#
{print_number
  |"print [->+<]>[-<+>>+<]>
    [>++++++++++<
    [->-[>+>>]>[+[-<+>]>+>>]<<<<<]
    +>[-]>[-<<+>>]>[-<<+>>]<<]
    +<[>-<[<]]>[>]
    <[>++++++[-<++++++++>]<-.[-]<]<
"(-)

}

;; implements print_string/"..."
;; this outputs EBF code making the
;; object code EBF
{print_string
  |"print >|"(-) 
  $i(-$wrk+$else+)
  $wrk($tmp(-$wrk+)$wrk.,$else(-$tmp+$wrk-$i+)$i(-$else+))
  $tmp(-)$else.(-)|"[-]<
"(-)
}

;; implements not/!
;; creates code that negates top of stack
{not
  |"not >+<[[-]>-]>[<+>->]<<
"(-)
}

&main

BrainBack을 컴파일하려면 :

bf ebf.bf < BrainBack.ebf > BrainBack.bf

BrainBack 프로그램을 컴파일하려면 다음을 수행하십시오.

bf BrainBack.bf < 99.bb > 99.ebf # compile from bb to ebf
bf ebf.bf < 99.ebf > 99.bf       # compile from ebf to bf 

바이너리를 실행하십시오 :

bf 99.bf                        

여기서 나는 대부분의 데비안 배포판에서 사용 가능한 bf 를 사용 합니다. beef다른 것들도 사용될 수 있습니다. EBF 컴파일러, BrainBack 및 해당 객체 코드는 모두 BrainFuck 바이너리와 호환됩니다.

셀을 ascii로 인쇄 .하고 바이트를 읽을 수 있고 더 유용한 ,다양한 swap연산을 가질 수 있도록 확장해야 합니다. BrainBack에서 BrainBack 컴파일러 또는 인터프리터를 만들려면 반드시 필요합니다.


6
와! 당신은 지금 1337 대표 포인트에 있습니다 ... 거의 숫자를 공표하고 망치고 싶지 않습니다! :)
luser droog

6

나는 대부분의 시간을 PHP 스크립트에 썼는데 왜 $변수 이름 을 사용해야 합니까? 현지 통화이므로 사용하겠습니다! €는 많은 국가에서 사용되므로 EU 언어의 일부 단어를 키워드로 사용했습니다.

€beers gleich 99
€bottles gleich bottles of beer
€bottles_on_the_wall gleich bottles of beer on the wall

mientras €beers topogleich 3
    afficher €beers €bottles_on_the_wall
    afficher , €beers €bottles
    afficher . NETHERLANDS
    odejmowanie €beers

    afficher Take one down and pass it around, €beers
    afficher €bottles_on_the_wall
    afficher . NETHERLANDS NETHERLANDS
sartneim

afficher 2 bottles of beer on the wall, 2 bottles of beer. NETHERLANDS
afficher Take one down and pass it around, 1 bottle of beer on the wall.
afficher NETHERLANDS NETHERLANDS

afficher 1 bottle of beer on the wall, 1 bottle of beer. NETHERLANDS
afficher Take one down and pass it around, no more bottles of beer on the wall.
afficher NETHERLANDS NETHERLANDS

afficher No more bottles of beer on the wall, no more bottles of beer. NETHERLANDS
afficher Go to the store and buy some more, 99 bottles of beer on the wall.
afficher NETHERLANDS NETHERLANDS

키워드 :

  • gleich독일어 로 동일하다
  • mientras반면 스페인어
  • topo 포르투갈어 (갱신 : 그것은해야 maior 대신, 덕분에 daHugLenny 팁을위한)
  • odejmowanie되는 빼기 폴란드어
  • afficher프랑스어 로 인쇄
  • 개행은 nl때때로 호출 되며의 TLD는 NETHERLANDSis nl이므로 NETHERLANDS개행을 표시 하는 상수 를 정의했습니다.

나는 if키워드 가 없기 때문에 조금 바람을 피우고 마지막 두 줄을 직접 인쇄하기로했습니다.

파이썬 인터프리터

통역사는 99 병의 맥주를 표시하기 위해 스크립트를 실행하는 것 이상을 수행하지 않습니다.

# -*- coding: utf-8 -*-
# @see http://stackoverflow.com/questions/12655836/writing-an-xml-file-that-contains-a-euro-symbol-in-python-using-xml-etree/12655861#12655861

# =             gleich (german)
# while         mientras (spanish)
# >             topo (portuguese) (it should be "maior" instead)
# subtract      odejmowanie (polish
# print         afficher (french)
# newline       NETHERLANDS

import sys, codecs

class euro:
    symbols = {}
    sign = u'€'

    def executeLine(self, line):
        s = line.split(' ')

        if s[0] == 'afficher':
            buffer = []

            for a in s[1:]:
                if (a == ''):
                    continue
                elif (a[0] == self.sign):
                    buffer.append(str(self.getSymbol(a)))
                elif (a == 'NETHERLANDS'):
                    buffer.append("\n")
                else :
                    buffer.append(a)

            sys.stdout.write(' '.join(buffer))
            # @see http://stackoverflow.com/questions/4499073/printing-without-newline-print-a-prints-a-space-how-to-remove/4499172#4499172
        elif s[0] == 'odejmowanie':
            self.setSymbol(s[1], (int(self.getSymbol(s[1])) - 1))
        elif (len(s) >= 3) and (s[1] == 'gleich'):
            self.setSymbol(s[0], (' ').join(s[2:]))

    def executeBlock(self, lines, statement):
        while (self.getStatement(statement)):
            for line in lines:
                self.executeLine(line)

    def getStatement(self, statement):
        if (statement[1] == 'topogleich'):
            return self.getSymbol(statement[0]) >= int(statement[2])

    def setSymbol(self, name, value):
        name = self.withoutEuro(name)
        self.symbols[name] = value

    def getSymbol(self, name):
        #~ print symbols, withoutEuro(name)
        name = self.withoutEuro(name)
        if name in self.symbols:
            value = self.symbols[name]

            return value
        else :
            print "\n-----\n",'Error: "', name, '"is not in', self.symbols, '-----'

            #~ sys.exit()

    def withoutEuro(self, string):
        return(string.replace(self.sign, ''))

    def parseFile(self, f):
        linesStack = []

        for line in codecs.open(f, 'r', 'utf-8'):
            line = line.replace('\n', '').replace('\t', '')
            s = line.split(' ')

            if (len(s) == 1) & (s[0] == '') :
                continue

            if (s[0] == 'mientras'):
                statement = s[1:]

                linesStack.append(line)
            elif (s[0] == 'sartneim'):
                linesStack.append(line)

                self.executeBlock(linesStack, statement)

                linesStack = []
                statement = ''
            elif (len(linesStack) > 0):
                linesStack.append(line)
            else:
                self.executeLine(line)

euro = euro()
euro.parseFile(sys.argv[1])

이를 실행하려면 두 파일을 모두 저장 한 다음 .eu스크립트를 인수로 사용하여 Python 파일을 실행하십시오 .

python euro.py euro.eu

4
+1! 'PHP 영국 있었이'생각 나게 : addedbytes.com/blog/if-php-were-british
피터 Witvoet

이 언어는 Esolang 에 문서화되어 있습니다 .
AL

1
topo입니다 상단 포르투갈어
acrolith

@daHugLenny 실수해서 죄송합니다. 가 maior 의 올바른 번역 그 이상 ?
AL

1
@AL 예. ( 댓글은 15 자 이상이어야 함 )
acrolith

5

1 랑

1Lang은 LISP 또는 Scheme과 같은 기능적 접두어 언어이지만 괄호가 없어 불필요한 공백이 모두 제거 될 때 읽기가 약간 어렵습니다. 모든 함수와 연산자는 알려진 수의 매개 변수를 사용하므로 괄호를 제거 할 수 있습니다.

함수 본문과 조건부 결과 및 명령문 목록으로 구성 될 수있는 대체 코드 블록을 구분하려면 중괄호가 필요합니다.

LISP에서 Factorial은 다음과 같이 정의 될 수 있습니다.

(defun fact (x) (if (< x 2) 1 (* x (fact (- x 1))) ) )

1Lang에서 이것은

@Fx{ ? < x 2 {1} {* x F -x1} }

어느 것으로 줄일 수 있습니다

@Fx{?<x2{1}{*xF-x1}}

1Lang은 현재 부작용을 지원하지 않습니다.

1Lang은 bash로 작성되므로 현재 정수 범위와 같은 bash 제한을 공유합니다.

a-z are variables. Variable are either integers, strings, or lists.

NB : 목록이 완전히 구현되지 않았습니다.

A-Z are functions

정수는 bash 정수입니다 (최대 2 ^ 32에서 2 ^ 31-1까지 생각합니다). 음수는 직접 사용할 수 없습니다. 음수를 입력하려면 0에서 빼십시오. 예. -5는 -0 5로 입력됩니다.이 제한은 1Lang이 진행중인 작업이므로이 응용 프로그램에는 음수가 필요하지 않기 때문입니다. -5를 ~ 5로 입력 할 수있는 단항 음수 연산자로 ~를 사용하는 것을 고려하고 있습니다.

정수를 나타내려면 공백이 필요합니다. 예. +2 3

: means assign                                    eg. :c34 to assign 34 to c
+-*/% are binary integer operators                eg. +12 34
&|^ are binary bit-wise operators
! is unary boolean not
~ is unary one's complement
? is a if-then-else function-like operator.       eg. ?=x3{*xx}{0} is x=3 return x*x else 0
+ is also a binary string concatenation operator  eg. +99" bottles"
* is also a string repetition operator            eg. *5" hello" or *" hello"5
@ defines a function                              eg. @Fx{?<x1{1}{*xF-x1}}

함수 매개 변수 이름은 호출자 변수를 오버로드 할 수 있습니다. 함수 내에 할당 된 모든 변수는 로컬입니다.

LISP처럼 모든 명령문은 값을 리턴하고 마지막으로 리턴 된 값이 인쇄되므로 인쇄는 필요하지 않습니다 (유용하지만).

eg. +2 3 prints 5

괄호가없는 접두사 표기법의 예기치 않은 동작은 문자열 연결이 실제로 작성하기 쉽다는 것입니다. 연결하고 싶다고 가정 해보십시오 "a" " quick" " brown" " fox".

+++"a"" quick"" brown"" fox"

그러나 더 읽기 쉽고 오류가 적은 방법은 다음과 같습니다.

+"a"+" quick"+" brown"" fox" (Note missing + between last terms)

또는

+"a"+" quick"+" brown"+" fox"""

99 맥주 코드 병 :

:b" of beer"
:w" on the wall"
:t"Take one down and pass it around, "
:s"Go to the store and buy some more, "
:c", "
:n".\n"
@Bx{?=x0{+"No more bottles"b}{+x+" bottle"+?=x1{""}{"s"}b}}
@Fx{?=x0{+B0+w+c+B0+n+s+B99+wn}{+Bx+w+c+Bx+n+t+B-x1+w+n+"\n"F-x1}}
F99

함수 B는 x에 따라 "더 이상 병 없음"또는 "1 병"또는 "병"을 반환합니다.

함수 F는 일반 구절 또는 마지막 구절을 반환합니다. 정상적인 구절은 -x1로 F를 재귀 적으로 호출하여 다음 구절과 연결됩니다. x가 0이면 F는 마지막 구절을 반환합니다.

이것은 다음을 생성합니다 (F5의 경우 5 병의 맥주에서 시작합니다 ...).

> F5
5 bottles of beer on the wall, 5 bottles of beer.
Take one down and pass it around, 4 bottles of beer on the wall.

4 bottles of beer on the wall, 4 bottles of beer.
Take one down and pass it around, 3 bottles of beer on the wall.

3 bottles of beer on the wall, 3 bottles of beer.
Take one down and pass it around, 2 bottles of beer on the wall.

2 bottles of beer on the wall, 2 bottles of beer.
Take one down and pass it around, 1 bottle of beer on the wall.

1 bottle of beer on the wall, 1 bottle of beer.
Take one down and pass it around, No more bottles of beer on the wall.

No more bottles of beer on the wall, No more bottles of beer.
Go to the store and buy some more, 99 bottles of beer on the wall.
<End>

1 500 줄 미만의 언어 해석기 (bash로 작성)

#!/bin/bash

LC_ALL=C  # else [a-z] and [A-Z] misbehave

# functions return result on stdout
# functions have an environment

# Requirements:
# * minimise size
#   -> eliminate delimiters
#   -> single letter variables and functions
#   -> no precidence
#   -> no overloading
# * 

# string "text with \characters as per printf"
# numbers 123
# functions F3
# Built-ins +-*/%^ &|~ ! etc.
# assignment :v12 :v"string"

log(){  local m="${l:p}" m="${m//[$NL]/\n}" v="${FUNCNAME[1]}"; echo "$v: l=[${l//[$NL]/\n}] ch=[${ch/[$NL]/\n}] next=[$m]" >&2; }
logr(){ local m="${l:p}" m="${m//[$NL]/\n}" v="${FUNCNAME[1]}"; echo "$v: l=[${l//[$NL]/\n}] ch=[${ch/[$NL]/\n}] next=[$m] ret=[${ret//[$NL]/\n}]" >&2; }
logv(){ local        v="${FUNCNAME[1]}"; echo "$v: ret=[${ret//[$NL]/\n}]" >&2; }
logm(){ local m="$1" v="${FUNCNAME[1]}"; echo "$v: ${m//[$NL]/\n} in [${read//[$NL]/\n}]." >&2; }

msg(){ echo -En "$1" >&2; }
msn(){ echo -E  "$1" >&2; }

# ==========
# Line layer
# ==========

declare l
readline(){ read -rp"1lang> " l; }

#==================
# Environment Layer
#==================

declare -A v t  # variables and variable type
declare ret typ  # all bash function return these values

# assign = : var expression
assign(){
  local var
  readch
  var && var=$ret || { logm "ERROR: variable name expected"      ; return 1; }
  exp             || { logm "ERROR: value or expression expected"; return 1; }
  v["$var"]="$ret"
  t["$var"]="$typ"
}

# get variable value
get(){
  local var
  var && var=$ret || { logm "ERROR: variable name expected"; return 1; }
  ret=${v["$var"]}
  typ=${t["$var"]}
}

declare -A func fpar 
declare -iA fnum                 # functions
# define = @ F param* { body } 
define(){
  local fn par body
  readch
  fn && fn=$ret || { logm "ERROR: function name expected"; return 1; }
  fpar[$fn]=                     # zero parameters
  fnum[$fn]=                     # zero parameter counter
  while var;do                   # read parameters
    fpar[$fn]+=$ret
    fnum[$fn]+=1                 # cound parameters
  done
  # get body but remove block delimiters
  skip "{" "}" && body="${ret:1: -1}" || { logm "ERROR: function body expected"; return 1; }
  readch                         # skip }
  func[$fn]="$body"              # store function body
  ret="@$fn${fpar[$fn]}{$body}"
  typ='f'
}

apply(){
  local fn=$ch n c s; local -i N q
  readch
  N=${fnum[$fn]}   # number of parameters
  n=${fpar[$fn]}   # parameters
  s=${func[$fn]}   # function body
  c=
  for((q=0; q<N; q++)){
    exp || { logm "ERROR: value expected"; return 1; }  
    c+="v[${n:q:1}]=\"$ret\"; "  # add value to script
    c+="t[${n:q:1}]=\"$typ\"; "  # add type to script
  }
  # parse function in a subshell and echo result and type back 
  # subshell means all variable changes in function are local
  c+="parse <<<'$s'; echo -E \"\$typ\$ret\""  # combine type and value
  ret=
  typ=
  ret="$( eval "$c" )" || { logm "ERROR: function application failed"; return 1; }
  typ="${ret::1}"  # extract type
  ret="${ret:1}"   # get actual return value
}

# bash oddities:

# [[ 1 -eq 1 ]] -> 0 or success
# [[ 1 -eq 2 ]] -> 1 or failed

# x=1\<2 -> a=1 (true)
# x=1\<1 -> a=0 (false)

# ((1==1)) -> 0 or success
# ((1==2)) -> 1 or failed

# declare -i a; a=1==1 -> a=1 (true)
# declare -i a; a=1==2 -> a=0  (false)

binary(){
  local -i iret; local op=$ch a b at bt
  readch
  exp && { a="$ret"; at=$typ; } || { logm "ERROR: initial expression expected"; return 1; }
  exp && { b="$ret"; bt=$typ; } || { logm "ERROR: second expression expected"  ; return 1; }
  ret=
  typ=
  case "$at$bt" in
    nn)  # num op num
      case "$op" in
        [\*]) iret=a*b;;
        [\^]) iret=a**b;;
        [\+]) iret=a+b;;
        [\-]) iret=a-b;;
        [\/]) [[ b -ne 0 ]] && { iret=a/b; } || { logm "ERROR: division by 0"       ; return 1; };;
        [\%]) [[ b -ne 0 ]] && { iret=a%b; } || { logm "ERROR: modulo division by 0"; return 1; };;
        [\&]) iret=a\&b;;
        [\|]) iret=a\|b;;
        [\#]) iret=a\^b;;
        [\=]) iret=a==b;;
        [\<]) iret=a\<b;;
        [\>]) iret=a\>b;;
      esac
      ret=$iret
      typ='n';;  # result is always a decimal number
    ss)  # string op string
      case "$op" in
#        [\*]) arith=a*b;;  # combine?
#        [\#]) arith=${}a**b; type='s';;
        [\+]) ret="$a$b"; typ='s';;  # concatenate
        [\-]) ret="${a//$b}"; typ='s';;  # remove substrings
        [\=]) [[ $a = $b ]]; ret=$?; typ='n';;
        [\<]) [[ $a < $b ]]; ret=$?; typ='n';;
        [\>]) [[ $a > $b ]]; ret=$?; typ='n';;
      esac;;
    ns)  # num op string  =3"hello"  ="hello"3  ="3"3  =3"4"
      case "$op" in
        [\+]) ret="$a$b"; typ='s';;  # concatenate
        [\*]) ret=$(eval echo \"\${b[0]\"{1..$a}\"}\"); typ='s';;  # repeat b a times
        [\=]) ((${#b}==a)); ret=$?; typ='n';;  # length b is a
#        [\<]) [[ $a < $b ]]; arith=$?; typ='n';;
#        [\>]) [[ $a > $b ]]; arith=$?; typ='n';;
      esac;;
    sn)  # string op num  *"hello"3  ="3"3  =3"4"
      case "$op" in
        [\+]) ret="$a$b"; typ='s';;  # concatenate
        [\*]) ret=$(eval echo \"\${a[0]\"{1..$b}\"}\"); typ='s';;  # repeat a b times
        [\=]) ((${#a}==b)); ret=$?; typ='n';;  # length a is b
#        [\<]) [[ $a < $b ]]; arith=$?; typ='n';;
#        [\>]) [[ $a > $b ]]; arith=$?; typ='n';;
      esac;;
    *) logm "ERROR: undefined operation [$op] for [$a] [$at] and [$b] [$bt]"; return 1;
  esac
  return 0
}

# FIXME: string ops?
unary(){
  local -i iret; local op="$ch"
  readch
  exp || { logm "ERROR: expression expected"; return 1; }
  case "$op" in
    [\!]) iret=\!ret;;
    [\~]) iret=\~ret;;
  esac
  ret=$iret
  typ='n'  # result is always a decimal number
}

#==============
# Control Layer
#==============

# iff = ? boolean { consequence block } { alternative block }
# ?<1 2{+4 5}{+1 2}
iff(){
  local -i c; local iff ift
  readch
  exp && c=$ret || { logm "ERROR: value or expression expected"; return 1; }
  [[ c -eq 1 ]] && {  # true so do consequence
    ws
    block && { iff="$ret"; ift="$typ"; } || { logm "ERROR: consequence block error"; return 1; }
    ws
    skip "{" "}" || { logm "ERROR: alternate block expected"; return 1; }
    ret="$iff"
    typ="$ift"
  } || {
    ws
    skip "{" "}" || { logm "ERROR: consequence block expected"; return 1; }
    ws
    block || { logm "ERROR: alternate block error"; return 1; }
  }
}

#==============
# Symbols Layer
#==============

# fn = [A-Z]
fn(){
# FIXME: make evalu?
  [[ $ch = [A-Z] ]] || return 1
  ret=$ch
  typ='c'
  readch
}

# var = [a-z]
var(){
# FIXME: make evalu?
  [[ $ch = [a-z] ]] || return 1
  ret=$ch
  typ='c'
  readch
}

# list = ( token* )
# FIXME: not finished and no operators support lists
list(){
  local list=$ch prev
  readch
  while [[ $ch != ')' ]];do
    exp || { logm "ERROR: expression expected"; return 1; }
    case $typ in
      [n]) list+=" $ret";;
      [s]) list+="$ret";;
      [l]) list+="$ret";;
    esac
    ws
  done
  ret="$list$ch"
  readch
  typ='l'
  return 0
}

#============
# Token Layer
#============

# char = ' echoch
#echoch = \ {special echo escape character} | {char}
char(){
  readch
  case "$ch" in
    [\\]) escch || { logm "ERROR: escape character expected"; return 1; };;
       ?) ret="$ch"; readch
  esac
  typ='c'
}

# escaped characters are a pain
# use read with -r to read in verbatim - no escaping
# use echo -E to write out verbatim (except \\ may be processed)

declare escchS
declare ECHO='abefnrtv'
# double \\ for a \
escch(){
  local ESC="$ch"
  readch    # skip \
  case "$ch" in
    [$ECHO])                   printf -v ret "%b" "$ESC$ch"; readch;;
       [\\]) ret="\\"; readch;;
       [\"]) ret="\""; readch;;
      [0-7])         onum && { printf -v ret "%b" "$ESC$ret"   ; } || { logm "ERROR: octal number expected"; return 1; };;
       [xU]) readch; hnum && { printf -v ret "%b" "${ESC}x$ret"; } || { logm "ERROR: hex number expected"  ; return 1; };;
          ?) ret="$ch"
             [[ $escchS ]] || {
               tidyReadCh
               logm "WARNING: only octal, hex, unicode, and [$ECHO\\\"] characters need to be escaped with '$ESC'"
               logm "WARNING: [$ch] in [$l] does not need to be escaped"
               escchS="OFF"
             }
             readch
  esac
  typ='c'
}

#  num =  digit  digit*
# onum = odigit odigit*
# onum = hdigit hdigit*

num(){  local num; num=$ch; readch; while  digit;do num+=$ret; done; ret=$num; typ='n'; }
onum(){ local num; num=$ch; readch; while odigit;do num+=$ret; done; ret=$num; typ='n'; }
hnum(){ local num; num=$ch; readch; while hdigit;do num+=$ret; done; ret=$num; typ='n'; }

#  digit = [0-9]
# odigit = [0-7]
# odigit = [0-9a-fA-F]
digit(){  [[ $ch == [0-9]       ]] || { ret=-1; return 1; }; ret=$ch; typ='s'; readch; }
odigit(){ [[ $ch == [0-7]       ]] || { ret=-1; return 1; }; ret=$ch; typ='s'; readch; }
hdigit(){ [[ $ch == [0-9a-fA-F] ]] || { ret=-1; return 1; }; ret=$ch; typ='s'; readch; }

# string = " char* "
# char = escch | {any character}
string(){
  skip "\"" "\"" || { logm "ERROR: quoted string expected"; return 1; }
  ret="${ret:1: -1}"
  typ='s'
  return 0
}

# ==========
# Char layer
# ==========

declare ch read
declare -i p L COUNT
readch(){
  if [[ p -eq L ]]; then  # need more code
    readline || { ch=; p=L=0; l="EOF"; return 1; }
    l+=$NL;
    p=0
    L=${#l}
  fi
# FIXME: remove once eady - prevents bash consuming all memory  
  COUNT+=1
  ((COUNT>100000)) && { logm "FAILSAFE: too many charcters read"; return 1; }
  ch="${l:p:1}"
  read+="$ch"
  p+=1  # queue next character
}

# skip = SS content* ES
# content = ch | escch | skip(SS ES)
# string = " ch* "
skip(){
  local s="$1" e="$2" b="$ch"
  typ='z'                    # code fragment
  [[ $ch != $s ]] && return  # nothing to skip
  readch
  while [[ -n $ch ]];do
    case "$ch" in
        $e)                 b+="$e"  ; readch; ret="$b"; return 0;;
        $s) skip "$s" "$e"; b+="$ret";;
      [\\]) escch         ; b+="$ret";;
      [\"]) skip "\"" "\""; b+="$ret";;
         ?)                 b+="$ch" ; readch
    esac
  done
  ret="$b"
  logm "ERROR: unexpected EOF"
  exit 1
}

# FIXME: still required?
shopt -s extglob
shopt -u nocasematch

declare NL; printf -v NL "%b" "\n"                 # echo $NL | hexdump -C
declare WS; printf -v WS "%b" " \n\t\r"            # define whitespace

# FIXME: should it set ret and typ? 
ws(){ while [[ $ch == [$WS] ]];do readch; done; }  # skip any WS

#=====
# eval
#=====

# exp = [0-9] num
#       | " string "
#       | : assignment
#       | @ function definition
#       | [-+*/%^] binary operation
#       | [&|#<>=] boolean operation
#       | [!~] unary operation
#       | [A-Z] function application
#       | [a-z] variable
#       | ? if expression
#       | { expression* } block expression
#       | ( expression* ) list of expressions

# spare prefix characters [ '$[]_\;, ]
# [v  head of list
# ]v tail of list

exp(){
  ws
  case "$ch" in
              [0-9]) num    || { logm "ERROR: number expected"               ; return 1; };;
#               [\']) char   || { logm "ERROR: char expected"                 ; return 1; };;
               [\"]) string || { logm "ERROR: string expected"               ; return 1; };;
               [\:]) assign || { logm "ERROR: assignment expected"           ; return 1; };;
               [\@]) define || { logm "ERROR: function definition expected"  ; return 1; };;
           [-+*/%^]) binary || { logm "ERROR: binary expression expected"    ; return 1; };;
       [\&\|#\<\>=]) binary || { logm "ERROR: binary expression expected"    ; return 1; };;
              [\!~]) unary  || { logm "ERROR: unary expression expected"     ; return 1; };;
              [A-Z]) apply  || { logm "ERROR: function failed"               ; return 1; };;
              [a-z]) get    || { logm "ERROR: variable name expected"        ; return 1; };;
               [\?]) iff    || { logm "ERROR: boolean expression expected"   ; return 1; };;
               [\{]) block  || { logm "ERROR: code block expected"           ; return 1; };;
               [\(]) list   || { logm "ERROR: list expected"                 ; return 1; };;
                 '') ret=;       logm "ERROR: unexpected EOF"                ; return 1;;
                  *) ret="$ch"                                               ; return 1;;
  esac
  return 0
}

# block = { code }
block(){
  readch                         # skip {
  while [[ $ch != "}" ]];do
    exp || { 
      tidyReadCh
      logm "WARNING: ignoring previous error or unknown symbol [$ch]"
      [[ errors+=1 -gt 5 ]] && { logm "ERROR: exiting due to too many warnings"; exit 1; }
    }
    ws
  done
  readch    # skip }
  return 0
}

#=====
# repl
#=====

# pass an expression on stdin- not used withing same ebvironment - called by apply
parse(){
  p=L  # force readline
  ch=
  read=
  readch  # clears ch
  while [[ $ch && $ch != '.' ]];do
    exp || { logm "ERROR: expression expected"; return 1; }
    read=$ch
    ws
  done
# last expression is returned as result
}

tidyReadCh(){
  tidyRead
  ch="${ch//[$NL]/\n}"
}
tidyRead(){
  read="${read//[$NL]}"
}

# repl = eval* EOF
# eval = evalu | readch
repl(){
  readch
  while [[ $ch && $ch != '.' ]];do
    exp && {
      tidyRead
      msn "> $read"  # echo line except for WS
#      echo -E "$ret [$typ]"
      echo -E "$ret"
      read=$ch
    } || {
      tidyReadCh
      msn "> $read"
      logm "WARNING: ignoring previous error or unknown symbol [$ch]"
      read=
      readch
      [[ errors+=1 -gt 5 ]] && { logm "ERROR: exiting due to too many warnings"; exit 1; }
    }
    ws
  done
  msn "<End>"
}

#=====
# test
#=====
# FIXME: negative numbers

msn "1Lang"

repl <<<'
:b" of beer"
:w" on the wall"
:t"Take one down and pass it around, "
:s"Go to the store and buy some more, "
:c", "
:n".\n"
@Bx{?=x0{+"No more bottles"b}{+x+" bottle"+?=x1{""}{"s"}b}}
@Fx{?=x0{+B0+w+c+B0+n+s+B99+wn}{+Bx+w+c+Bx+n+t+B-x1+w+n+"\n"F-x1}}
F99
'

@Mfxy{fxy}M+3 4작동 한다면 훨씬 더 좋아 했지만 함수와 변수 네임 스페이스를 결합해야합니다. 99 맥주를 계산하는 데 시간이 걸렸습니다 : p
Sylwester

@Sylwester, 관심을 가져 주셔서 감사합니다. 나는 당신이 그것을 시도하고 또한 효과가있어서 기쁘다. 예, bash는 느리고 bash를 사용하여 다른 언어 (특히 서브 쉘 사용)를 해석하는 것은 흥미롭지 만 유용하지는 않습니다. +3 4가 처음 적용되므로 M + 3 4는 정확하지 않습니다. M \ xy {+ xy} 3 4는 작동하는 구문 일 수 있습니다.
Philcolbourn

흠. 내 설명이 마크 업 언어 규칙을 트리거했으며 비트가 누락 된 것 같습니다.
Philcolbourn

네, cons가능 map M\x{*x2}C1C2C3C4/ => (2 4 6 8)
하다면

4

절반 (Windows Batch의 통역사 / 번역기)

나는 왜 Windows 배치에서 너무 많은 퍼즐에 답하고 있는지 모르겠다. 왜냐하면 나는 그것을 즐기고 있다고 생각하는 아픈 이유가있다. Windows 배치로 작성된 스크립트에 의해 Windows 배치로 변환됩니다. 특히 놀랍지는 않지만 작동합니다.

맥주 99 병

# Initialize variables
bottles ~ 99
# You can't directly compare a literal value
zero ~ 0

# This makes a point 'loop' that can be jumped to or used as a subroutine
mark loop
    write $ bottles
# You only need quotes when you have leading or trailing spaces
    print ~ " bottles of beer on the wall,"
    write $ bottles
    print ~ " bottles of beer."
    print ~ Take one down and pass it around,
    bottles @ bottles-1
    if
    bottles equ zero
        jump none
    endif
    write $ bottles
    print ~ " bottles of beer on the wall."
    print ~
jump loop

mark none
    print ~ no more bottles of beer on the wall.
    print ~
    print ~ No more bottles of beer on the wall,
    print ~ No more bottles of beer.
    print ~ Go to the store and buy some more,
    print ~ 99 bottles of beer on the wall.

통사론

각 줄에는 공백으로 구분 된 세 개의 토큰 만 인식됩니다.

#은 주석입니다.

값이 필요한 대부분의 경우 $두 번째 토큰의 a 는 세 번째 토큰을 변수 이름으로 취급해야하며 ~a는 리터럴 값을 나타냅니다. 일반적인 지침은 형식 <instruction> [$~] <name>입니다. 변수 설정은 동일한 형식을 취하지 만 인식되지 않을 때마다 구현됩니다.

정의 된 명령 :

  • print그리고 write모두 쓰기 출력,하지만 write줄 바꿈을 추가하지 않습니다. $ 또는 ~가 필요합니다.
  • mark 서브 루틴으로 점프하거나 호출 할 수있는 점을 작성합니다.
  • jump 일괄 처리 된 goto와 동등합니다 (또는 그 문제에 대한 모든 언어).
  • proc서브 루틴을 호출합니다. 에 해당 call :label합니다.
  • return서브 루틴에서 리턴합니다. 내부에 없으면 프로그램을 종료합니다.
  • if조건부 명령. 다음 줄에서 형식으로 비교합니다 <var1> <operator> <var2>. 연산자는 if배치 와 동일 합니다. EQU, NEQ, LSS, LEQ, GTR, GEQ. 비교가 참인 경우에만 명령을 실행합니다.
  • endif if 문을 종료합니다.
  • cat두 변수를 연결합니다. cat a bab의 값을 a에 저장합니다.

이러한 명령을 찾지 못하면 표현식은 첫 번째 토큰을 변수 이름으로 사용하여 변수 할당으로 처리됩니다. $에서와 ~동일하게 작동 print하지만 @식별자도 있습니다. 마지막 토큰을 수학 표현식으로 취급하여set /a . 대부분의 연산자를 포함합니다. 세 개의 식별자 중 하나라도 없으면 구문 오류이며 인터프리터가 종료됩니다.

통역사 (Windows Batch)

인터프리터는 실제로 코드를 Windows 배치로 변환하여 임시 파일에 넣고 실행합니다. Half 언어에서는 구문 오류를 인식하지만 결과 배치 스크립트는 특히 괄호, 세로 막대 등의 특수 문자에서 문제를 일으킬 수 있습니다.

@echo off

REM Half Interpreter / Translator

if exist ~~.bat del ~~.bat
if not exist "%1" call :error "File not found: '%1'"
set error=
setlocal enabledelayedexpansion
call :parse "%1" 1>~~.bat
if exist ~~.bat if not "error"=="" ~~.bat 2>nul
goto :eof

:parse
set ifstate=0
echo @echo off
echo setlocal
echo setlocal enabledelayedexpansion
for /f "eol=# tokens=1,2* delims= " %%a in (%~1) do  (
    if "!ifstate!"=="1" (
        if /i not "%%b"=="equ" if /i not "%%b"=="neq" if /i not "%%b"=="lss" if /i not "%%b"=="leq" if /i not "%%b"=="gtr" if /i not "%%b"=="geq" call :error "Unknown comparator: '%%b'"
        echo if "^!%%a^!" %%b "^!%%c^!" ^(
        set ifstate=0
    ) else (
        if "%%a"=="print" (
            if "%%b"=="$" (
                echo echo.^^!%%c^^!
            ) else if "%%b"=="~" (
                echo echo.%%~c
            ) else call :error "Unknown identifier for print: '%%b'"
        ) else if "%%a"=="write" (
            if "%%b"=="$" (
                echo echo^|set/p="^!%%c^!"
            ) else if "%%b"=="~" (
                echo echo^|set/p="%%~c"
            ) else call :error "Unknown identifier for write: '%%b'"
        ) else if "%%a"=="mark" (
            if not "%%c"=="" call :error "Unexpected token: %%c"
            echo :%%b
        ) else if "%%a"=="jump" (
            if not "%%c"=="" call :error "Unexpected token: %%c"
            echo goto :%%b
        ) else if "%%a"=="proc" (
            if not "%%c"=="" call :error "Unexpected token: %%c"
            echo call :%%b
        ) else if "%%a"=="return" (
            if not "%%c"=="" call :error "Unexpected tokens: %%b %%c"
            if not "%%b"=="" call :error "Unexpected token: %%b"
            echo goto :eof
        ) else if "%%a"=="if" (
            if not "%%c"=="" call :error "Unexpected tokens: %%b %%c"
            if not "%%b"=="" call :error "Unexpected token: %%b"
            set ifstate=1
        ) else if "%%a"=="endif" (
            if not "%%c"=="" call :error "Unexpected tokens: %%b %%c"
            if not "%%b"=="" call :error "Unexpected token: %%b"
            echo ^)
        ) else if "%%a"=="cat" (
            echo set "%%b=^!%%b^!^!%%c^!"
        ) else (
            if "%%b"=="$" (
                echo set "%%a=!%%c!"
            ) else if "%%b"=="~" (
                echo set "%%a=%%~c"
            ) else if "%%b"=="@" (
                echo set/a"%%a=%%c"
            ) else call :error "Unknown tokens '%%a %%b %%c'"
        )
    )
)
echo endlocal
goto :eof

:error
echo.Parse Error: %~1 1>&2
set error=1
goto :eof


4

플렉스 바이슨

다른 경우 조건 블록 및 다른 덧셈 연산을 변수에 할당하십시오.

완하 한 파일 lex.l

%{
 #include <stdio.h>
 #include <stdlib.h>
%}

 var [A-Za-z][A-Za-z0-9]*
 digit [0-9]+
 comment \*\*[A-Za-z0-9\*\/\+\-\(\)\"\' \t;:=]*\n

 %%
 print {return(PRINT);}
 save {return(SAVE);}
 {digit} {yylval=atoi(yytext);return(DIGIT);}
 {var} {yylval=strdup(yytext);return(VAR);}
 \* {return(M_SIGN);}
 \/ {return(D_SIGN);}
 \+ {return(A_SIGN);}
 \- {return(S_SIGN);}
 \( {return(L_BRACE);}
 \) {return(R_BRACE);}
 = {return(E_SIGN);}
 ; {return(S_COLON);}
 : {return(COMMA);}
 \n {return (NW_LINE);}
 [ \t] /*skip*/;
 {comment} /*skip*/;
 %%

파서 파일 com.y

  %{
    #include <ctype.h>
    #include <stdio.h>
    FILE *save_p;
    int new_line=1,stack_top=0,trigger=1;
    void value_store(int);
    int check_srore(char name_var[],int);
    void error(int);

    struct store
    {
     int var_value;
     char var_name[10];
     }info[10];        

    %}

      %token PRINT SAVE S_COLON L_BRACE R_BRACE DIGIT VAR COMMA NW_LINE
      %left A_SIGN S_SIGN
      %left D_SIGN M_SIGN
      %right E_SIGN



      %%
      commands : 
         | commands command
          ;
      command : expers
        | print
        | save
        | NW_LINE{new_line++;}
          ;

           save : SAVE expr etest {fprintf(save_p,"%d\n",$2);}
            ;

           expers  : store_val equal expr etest{value_store($3);}
        ;

           print    : PRINT expr etest {printf("%d\n",$2);} 
              ;

           etest    : S_COLON
        | DIGIT {error(0);}|PRINT{error(0);}|SAVE{error(0);}
         | VAR{error(0);}|COMMA{error(0);}
         ;

           store_val : VAR {check_store($1,0);}
          ;

           expr    : expr A_SIGN expr      { $$ = $1 + $3; } 
                | expr S_SIGN expr      { $$ = $1 - $3; }
                | expr M_SIGN expr      { $$ = $1 * $3; }
                    | expr D_SIGN expr      { $$ = $1 / $3; }
                | L_BRACE expr R_BRACE  { $$ = $2; }
                | DIGIT
                | retriv_var
                ;

             equal   : E_SIGN
             ;

             retriv_var : VAR { $$=check_store($1,1); }
           ;            

        %%

        #include "lex.yy.c"

        void error(int temp)
         {
                char *err[]={
                     "Statement Missing\n",
                 "Compund Statement Missing\n",
                     "Variable need a value\n",
                     "Invalid Argument\n"  
          };
             printf("In line no.%d:\t%s",new_line,err[temp]);   
         exit(1);
        } 

      void value_store(int store_val)
      {
       stack_top--;
      info[stack_top++].var_value = store_val;
      }

   int check_store(char name_var[],int status)
   {
     int temp = 0;
   do{
    if(strcmp(info[temp].var_name,name_var)==0)
    {
   trigger=0;
       if(status)
   {  
          trigger=1;
      return (info[temp].var_value);
   }          
     }
    temp++;     
   } while(temp<stack_top);

    if(trigger)
    {    
if(status)
{
  trigger=1;
      error(2);
}
    else
strcpy(info[stack_top++].var_name,name_var);
   }
      else trigger=1;

  }

  int yyerror(const char *str)
  {
    fprintf(stderr,"error: %s\n",str);
  }


  main(int argc, char *argv[])
  {       

if(argc != 3)
{
     error(3);
}
   yyin = fopen(argv[1],"r");
   save_p = fopen(argv[2],"w");
   yyparse();
   fclose(yyin);
   fclose(yyout);
  }

엮다

  1. 목록 항목
  2. 플렉스 lex.l
  3. 들소 com.y
  4. gcc -o 컴파일러 com.tab.c -lfl

운영

컴파일러 in.txt ou.txt

입력 파일

a = 3 + (4 * 7) -9; 인쇄 c = a + 45; 인쇄 c;

**이 코멘트입니다 c 저장;

** 파일 인쇄에 c를 저장하십시오 c * (a + 32);

출력 파일 67


2

통역사

이 코드를 실행하는 방법에 대한 지침은 다른 답변을 참조하십시오 : /codegolf//a/19935/13186

맥주 99 병

프로그램

 bottles of beer on the wall, @ bottles of beer.
Take one down and pass it around, @ bottles of beer on the wall.

@ bottle of beer on the wall.

1 bottle of beer on the wall, 1 bottle of beer.
Take one down and pass it around, no more bottles of beer on the wall.
@@@@@@@@@@@@@@

#9.{
    !#48.+

    !<#57.<#0.^<!<#57.<#1.^<!<#56.<#64.^<
    !<#56.<#0.^<!<#56.<#1.^<!<#55.<#64.^<
    !<#55.<#0.^<!<#55.<#1.^<!<#54.<#64.^<
    !<#54.<#0.^<!<#54.<#1.^<!<#53.<#64.^<
    !<#53.<#0.^<!<#53.<#1.^<!<#52.<#64.^<
    !<#52.<#0.^<!<#52.<#1.^<!<#51.<#64.^<
    !<#51.<#0.^<!<#51.<#1.^<!<#50.<#64.^<
    !<#50.<#0.^<!<#50.<#1.^<!<#49.<#64.^<
    !<#49.<#0.^<!<#49.<#1.^<!<#48.<#64.^<
    !<#48.<#0.^<!<#48.<#1.^<!#1.-<#57.<#64.^<
    _
?}

#57.<#0.^<#57.<#1.^<!<#56.<#64.^<
#56.<#0.^<#56.<#1.^<!<#55.<#64.^<
#55.<#0.^<#55.<#1.^<!<#54.<#64.^<
#54.<#0.^<#54.<#1.^<!<#53.<#64.^<
#53.<#0.^<#53.<#1.^<!<#52.<#64.^<
#52.<#0.^<#52.<#1.^<!<#51.<#64.^<
#51.<#0.^<#51.<#1.^<!<#50.<#64.^<
#50.<#0.^<#50.<#1.^<!<#49.<
#94.^<

$

2

99ISC

99ISC는 임의 크기의 정수 지향 메모리를 사용합니다. 메모리는 음이 아닌 정수로 색인됩니다. 메모리의 모든 값은 해당 주소로 초기화됩니다. 예 : 런타임시 주소 0은 값 0을 포함하고 주소 9는 값 9를 포함합니다.

99ISC에는 두 가지 지침이 있습니다. 첫 번째는 벽 루틴에 99 병의 맥주를 인쇄합니다. 구문은 아래와 같이 한 줄입니다. 프로그램의 다음 줄에서 실행이 계속됩니다.

.

두 번째 명령어는 "0이 아닌 경우 빼기 및 분기"명령어입니다. 구문은 아래와 같이 한 줄입니다.

x y z

xy연산 될 숫자의 주소이고, 빼는 숫자의 주소이며, 빼기 z결과가 0이 아닌 경우 실행할 다음 행입니다. 그렇지 않으면 다음 행으로 실행이 진행됩니다.

"제로 빼기 및 분기 0이 아닌"명령어가 있으면 99ISC를 OISC (One Instruction Set Computer)로 만들며 튜링이 완료됩니다.

다음은 메모리에서 처음 10 개의 값을 지우고 99 루틴의 맥주병을 벽 루틴에 인쇄하는 프로그램입니다.

1 1 0
2 2 0
3 3 0
4 4 0
5 5 0
6 6 0
7 7 0
8 8 0
9 9 0
.

그리고 여기 파이썬에서 99ISC 인터프리터가 있습니다.

def interpret(filename):
    mem = range(0, 10)
    print mem

    with open(filename) as f:
            lines = f.readlines()

    ptr = 0
    while ptr < len(lines):
            line = lines[ptr]

            if line.strip() == ".":
                    for i in range(99,0,-1):
                            text = str(i) + " bottles of beer on the wall, " + str(i) + " bottles of beer.\nTake one down and pass it around, " + str(i-1) + " bottles of beer on the wall.\n\n"
                            print text.replace("0", "No more")
            else:
                    toks = map(int, line.split())
                    mem[toks[0]] = (mem[toks[0]] - mem[toks[1]]) & 0xFF
                    if mem[toks[0]] != 0:
                            ptr = toks[2]
                    else:
                            ptr += 1

1
이것이 골프 질문에 대한 "모범 사례"규칙을 어기는 것 같습니다. "."대신 일반 인쇄 설명 여전히 작동하지만 99BOB 프로그램을 작성하려고하면 저주받을 것입니다!
intx13

마지막 2 절은 조금 더 많은 작업이 필요합니다.
Philcolbourn

2

나는 당신에게 :

SISI (Small Instruction Set Interpreter)

구문은 기본 및 어셈블리를 사용합니다. 그것은 네 개의 문이있다 : set, print, jump(무조건 고토)을하고,jumpif (조건 고토). 모든 문장 앞에 줄 번호가 와야합니다. 지원되는 데이터 유형은 정수 및 문자열입니다.

인터프리터 자체는 Github (sisi.py)의 Python 3 에서 찾을 수 있습니다 . 99 병의 맥주 프로그램도 있지만 여기에서 재현하겠습니다.

10 set x 99
20 set bottles " bottles "

100 set line x + bottles
110 set line line + "of beer on the wall, "
120 set line line + x
130 set line line + bottles
135 set line line + "of beer."
140 print line

200 set x x - 1
210 set none x = 0
220 jumpif none 400
230 set multiple x > 1
240 jumpif multiple 300
250 set bottles " bottle "

300 set line "Take one down and pass it around, " + x
310 set line line + bottles
320 set line line + "of beer on the wall."
330 print line
340 print ""
350 jump 100

400 print "Take one down and pass it around, no more bottles of beer on the wall."
410 print ""
420 print "No more bottles of beer on the wall, no more bottles of beer."
430 print "Go to the store and buy some more, 99 bottles of beer on the wall."

1

포고

https://github.com/nrubin29/Pogo

method main:void
    declare(integer,i,99)
    while i > 0
        print(i "bottles of beer on the wall")
        math(i - 1) i
    end
end main

이것이 99 병 가사를 인쇄하는 것을 보는 데 문제가 있습니다.
Sylwester

먼저, 이름이 지정된 정수를 선언하고 i99로 설정합니다. 그런 다음 i가 0보다 크면 1을 인쇄 i bottles of beer on the wall하고 뺍니다 i. 문제가 가사의 일부가 부족하면 더 추가 할 수 있습니다.
nrubin29

3
가사에 대한 링크가 제공되었습니다. 마지막 몇 구절은 조금 더 복잡합니다.
Philcolbourn
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.