Створення інтерпретатора мови програмування [закрито]


19

Завдання:

Ви повинні створити інтерпретатор, який може аналізувати фрагменти мови програмування. Мова не повинна бути складною, але вона повинна містити такі синтаксичні елементи:

  • Можливість присвоювати та читати змінні (може бути так само просто, як a- попередньо zзмінені змінні)
  • Якщо заяви (elseif та інше не потрібно)
  • Петлі (рахуючи довільне число, доступ користувача до лічильника не потрібен)
  • Проста математика зі змінними (додавання, віднімання, множення, ділення, більше / менше, рівне)
  • Роздрукувати заяви

Правила:

  • Ви не можете копіювати синтаксис іншої популярної мови.
  • Вам потрібно написати власного перекладача, а не модифікації іншого перекладача.
  • Ви можете написати перекладача будь-якою мовою.
  • Напишіть прикладну програму з 99 пляшок пива вашою мовою (див. Тут )
  • Це за , тому перемагає найактуативніша відповідь.

3
Які вимоги аналізатора? Чи потрібно виводити якесь синтаксичне дерево?
Кендалл Фрей

1
Чи здатна виштовхувати та вискакувати зі стека достатньо, щоб задовольнити вимогу змінної?
tecywiz121

1
@Dennis - він повинен мати можливість циклікувати задану кількість разів, визначену під час виконання
TheDoctor

2
Я вважаю, що це робить його перекладачем, ні?
Кендалл Фрей

3
Якимось чином хочу, щоб Гвідо подав CPython.
user2357112 підтримує Моніку

Відповіді:


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
Антоніо Рагагнін

1
Чи знаєте ви, що вона вже існує ?
AL

Ні, я ніколи цього не бачив. Баммер, я думав, що я оригінальний. :-(
Гарет

10

BrainBack: Складена мова на основі стека, що працює на BrainFuck

NB: Spec була змінена з "створення аналізатора" на "створення інтерпретатора" після того, як я опублікував цю відповідь. Ця відповідь є компілятором, який також аналізує вихідний код.

Назва - каламбур на Back, який є протилежною відомій мові, що базується на стеках, і Мозку, що вказує на її езотеричну природу. Це схоже на BrainFuck (хоча це не так), але компілятор працює на BrainFuck, і компільований об'єктний код закінчується як BrainFuck binaries.

Мова: * == знищує його аргументи

  • "constant" друкує постійною
  • # друкує верхню частину стека як номер
  • > дублює верхню частину стека
  • <num> висунути постійне число <num>як значення до вершини стека
  • < видалити верхню частину стека
  • - підсумковий верхній з другого верхнього *
  • + додати верхнє до другого верхнього *
  • ! не перемикає позитивні / нульові *
  • [ ... ] деякий час вершина стека не дорівнює нулю, дуже схожа на BrainFuck

99 пляшок пива з правильною лірикою в BrainBack:

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.

"
]

Компілятор BrainBack, написаний розширеним BrainFuck

;;; 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, який доступний у більшості дистрибутивів Debian. beefта інші також можуть бути використані. І компілятор EBF, і BrainBack, і його об'єктний код стають цілком сумісними бінарними файлами BrainFuck.

Це, мабуть, слід розширити, щоб надрукувати комірку як ascii ., мати можливість читати байт ,і робити різні swapоперації, щоб бути кориснішими. Це абсолютно необхідно для того, щоб зробити компілятор BrainBack або інтерпретатор у BrainBack.


6
Оце Так! Ви зараз на 1337 балів повторень ... майже не хочете отримувати гроші та зіпсувати номер! :)
luser droog

6

Я витрачаю більшу частину свого часу на сценарії PHP, і це поставило мені запитання: чому я змушений використовувати $для своїх імен змінних? є моєю місцевою валютою, тому давайте використовувати її! Оскільки € використовується у багатьох країнах, я використовував деякі слова з мов ЄС як ключові слова.

€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 - NETHERLANDSце nl, тому я визначив постійну NETHERLANDSдля відображення нових рядків

Я трохи обдурив, оскільки немає ifключового слова, я вирішив безпосередньо надрукувати останні два рядки.

Перекладач на Python

Перекладач не зробить більше, ніж виконає сценарій для відображення 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])

Щоб запустити його, збережіть обидва файли, а потім запустіть файл Python із .euсценарієм як аргумент:

python euro.py euro.eu

4
+1! Нагадує мені, "Якщо PHP був британський": addedbytes.com/blog/if-php-were-british
Пітер Вітвоет

Ця мова була задокументована на Esolang .
AL

1
topoє найкращим на португальській
мові

@daHugLenny Вибачте за помилку. Є чи MAIOR правильного перекладу Великих ?
AL

1
@AL так. ( коментарі повинні бути не менше 15 символів )
акроліт

5

1Ланг

1Lang - це функціональна мова префіксів на зразок LISP або Scheme, але без дужок, що ускладнює читання, коли видаляється все зайве пробіл. Дужки можна видалити, оскільки всі функції та оператори приймають відому кількість параметрів.

Дужки потрібні для розмежування функції функції та умовного наслідку та альтернативних блоків коду, які можуть складатися зі списку операторів.

У LISP Фактор може бути визначений так:

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

в 1класі це було б

@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.

Примітка: Списки виконуються не повністю.

A-Z are functions

Цілі числа - це цілі числа bash (до -2 ^ 32 до 2 ^ 31-1, я думаю). Негативні цифри не можна використовувати безпосередньо. Щоб ввести мінус, віднімайте його від нуля. напр. -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 повертає "Більше пляшок" або "1 пляшка" або "пляшки" залежно від x.

Функція F повертає звичайні вірші або заключний вірш. Звичайний вірш поєднується з наступним віршем шляхом рекурсивного виклику F з -x1. Коли 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 Перекладач мов (написаний bash) під 500 рядками.

#!/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, дякую за ваш інтерес. Я радий, що ви спробували це, а також, що це спрацювало. Так, bash повільний, а використання bash для інтерпретації іншої мови (особливо за допомогою підшаровок) просто цікаво, але не корисно. M + 3 4 не буде правильним, оскільки +3 4 буде оцінено першим у застосуванні. M \ xy {+ xy} 3 4 може бути синтаксисом, який би спрацював.
philcolbourn

хммм. здається, що мій опис викликав правила мови розмітки, і біти відсутні.
philcolbourn

Так, так що коли це consможнаmap M\x{*x2}C1C2C3C4/ => (2 4 6 8)
Сильвестер,

4

Половина (перекладач / перекладач у пакеті Windows)

Я не знаю, чому я відповідаю на стільки головоломок у пакеті Windows, я вважаю, що мені подобається це насолоджуватися: P У будь-якому випадку це схоже на те, над чим я весело працював деякий час тому, основна мова, яка переводиться на пакетну групу 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.

Синтаксис

У кожному рядку розпізнаються лише три лексеми, розділені пробілами.

# - коментар.

У більшості випадків, коли потрібне значення, а $у другому маркері означає, що третій слід розглядати як ім'я змінної, тоді як ~позначає буквальне значення. Загальні інструкції приймають форму <instruction> [$~] <name>. Встановлення змінної приймає однакову форму, але реалізується щоразу, коли вона не розпізнається.

Визначені команди:

  • printі writeобидва записують вихід, але writeне додають новий рядок. Потрібно $ або ~.
  • mark створює точку, яку можна перейти або викликати як підпрограму.
  • jump еквівалент goto в партії (або будь-яка мова з цього питання).
  • procвикликає підпрограму. Еквівалентний call :label.
  • returnповертається з підпрограми. Вийде з програми, якщо не знаходиться в одній.
  • ifумовна інструкція. Порівняє з наступного рядка, за формою <var1> <operator> <var2>. Оператори такі ж, як if's у партії, тобто. EQU, NEQ, LSS, LEQ, GTR, GEQ. Після цього виконуватимуть інструкції, лише якщо порівняння вірно.
  • endif закінчується оператором if.
  • catз'єднує дві змінні. cat a bзбереже значення ab в a.

Коли жодна з цих команд не знайдена, вираз трактується як призначення змінної, використовуючи перший маркер як ім'я змінної. $і ~поводиться так само, як і в print, але є @ідентифікатор. Це трактує останній маркер як математичний вираз, переданий на set /a. Він включає більшість операторів. Якщо жоден з трьох ідентифікаторів не знайдений, це помилка синтаксису і інтерпретатор виходить.

Перекладач (Пакет Windows)

Інтерпретатор фактично переводить код у пакет Windows, розміщує його у тимчасовому файлі та виконує його. Хоча він розпізнає помилки синтаксису в мові "Половина", результуючий пакетний скрипт може викликати проблеми, особливо зі спеціальними символами, такими як дужки, вертикальні смуги тощо.

@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

Flex Bison

Призначте змінний, якщо інший блок умов та якесь інше додавання, віднімання.

Лексичний файл 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. flex 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 пляшок пива на рутині. Його синтаксис - це один рядок, як показано нижче. Виконання продовжується наступним рядком програми.

.

Друга інструкція - це "віднімання і розгалуження, якщо не дорівнює нулю". Його синтаксис - це один рядок, як показано нижче.

x y z

x- адреса числа, над яким буде діяти, y- адреса числа, що віднімається, і zє наступним рядком, який слід виконати, якщо результат віднімання не дорівнює нулю. В іншому випадку виконання триває з наступного рядка.

Наявність інструкції "відняти-відгалуження-якщо-не-нуль" робить 99ISC OISC (One Computer Set Computer) і, отже, Turing завершений.

Ось програма, яка стирає перші 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, в Python.

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)

Синтаксис спирається на BASIC і збірку. Вона має чотири заяви: set, print, jump(безумовна GOTO) і jumpif(умовне Гото). Кожному оператору повинен передувати номер рядка. Підтримувані типи даних - цілі числа та рядки.

Сам перекладач можна знайти в Python 3 на Github (sisi.py). Програма "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 пляшок.
Сільвестер

По-перше, я оголошую ціле ім'я iта встановлюю його рівним 99. Потім, поки i більше 0, я друкую i bottles of beer on the wallі віднімаю одне i. Якщо проблема полягає в тому, що мені бракує деяких текстів, я можу додати більше.
nrubin29

3
Посилання на тексти пісень було надано (або зараз є). Останні кілька віршів трохи складніші.
philcolbourn
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.