Utwórz tłumacz języka programowania [zamknięty]

19

Zadanie:

Musisz utworzyć interpreter, który będzie mógł analizować fragmenty języka programowania. Język nie musi być skomplikowany, ale musi zawierać następujące elementy składniowe:

  • Możliwość przypisywania i odczytywania zmiennych (może być tak proste, jak a- zpredefiniowane zmienne)
  • Jeśli instrukcje (elseif i else nie są wymagane)
  • Pętle (licząc do dowolnej liczby, dostęp użytkownika do licznika nie jest wymagany)
  • Prosta matematyka ze zmiennymi (dodawanie, odejmowanie, mnożenie, dzielenie, większa / mniejsza niż, równa się)
  • Wydrukuj wyciągi

Zasady:

  • Nie możesz kopiować składni innego popularnego języka.
  • Musisz napisać własnego tłumacza, a nie modyfikację innego tłumacza.
  • Możesz napisać tłumacza w dowolnym języku.
  • Napisz przykładowy program z 99 butelkami piwa w swoim języku (patrz tutaj )
  • To , więc wygrywa najbardziej pozytywna odpowiedź.
Doktor
źródło
3
Jakie są wymagania parsera? Czy musi generować jakieś drzewo składniowe?
Kendall Frey
1
Czy możliwość pchania i wyskakiwania ze stosu wystarcza, aby spełnić zmienne wymagania?
tecywiz121
1
@Dennis - musi być w stanie zapętlić określoną liczbę razy, określoną w czasie wykonywania
TheDoctor
2
Wierzę, że to czyni z niego tłumacza, nie?
Kendall Frey
3
Trochę chcę zobaczyć, jak Guido przesyła CPython.
user2357112 obsługuje Monikę

Odpowiedzi:

17

DogeScript

Program 99 butelek piwa:

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

Tłumacz 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;
    }
}
?>

Obecna składnia:

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.

Wypróbuj tutaj .
Wszelkie sugestie dotyczące ulepszeń są mile widziane.

Gareth
źródło
2
prgramming lvl = 100
Antonio Ragagnin
1
Czy wiesz, że już istnieje ?
AL
Nie, nigdy tego nie widziałem. Bummer, myślałem, że jestem oryginalny. :-(
Gareth,
10

BrainBack: skompilowany język oparty na stosie działający na BrainFuck

NB: Specyfikacja została zmieniona z „tworzenie parsera” na „tworzenie interpretera” po opublikowaniu tej odpowiedzi. Ta odpowiedź to kompilator, który również analizuje kod źródłowy.

Nazwa to kalambur na powrót będąc przeciwieństwem znanego języka opartego na stos i mózgu wskazuje, że to ezoteryczny charakter. Wygląda trochę jak BrainFuck (choć nie jest), ale jego kompilator działa na BrainFuck, a skompilowany kod obiektowy kończy się jako pliki binarne BrainFuck.

Język: * == niszczy argumenty

  • "constant" drukuje stałe
  • # drukuje górę stosu jako liczbę
  • > duplikuje górę stosu
  • <num> push stałą liczbę <num>jako wartość na górę stosu
  • < usuń górę stosu
  • - odejmij najwyższą z drugiej najwyższej *
  • + dodaj najwyższą pozycję do drugiej najwyższej pozycji *
  • ! nie przełącza dodatniego / zerowego *
  • [ ... ] robi chwilę na szczycie stosu, a nie zero, bardzo podobny do BrainFuck

99 butelek piwa z poprawnymi tekstami w 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.

"
]

Kompilator BrainBack napisany w Extended 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

Aby skompilować BrainBack:

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

Aby skompilować program 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 

Uruchom plik binarny:

bf 99.bf                        

Tutaj używam bf, który jest dostępny w większości dystrybucji Debiana. beefi inne mogą być również używane. Zarówno kompilator EBF, BrainBack, jak i jego kod obiektowy stają się całkiem kompatybilnymi plikami binarnymi BrainFuck.

Prawdopodobnie należy go rozszerzyć, aby wydrukować komórkę jako ascii ., być w stanie odczytać bajt ,i mieć różne swapoperacje, aby być bardziej użytecznym. Jest to absolutnie potrzebne do stworzenia kompilatora lub interpretera BrainBack w BrainBack.

Sylwester
źródło
6
Łał! Masz teraz 1337 punktów rep ... prawie nie chcesz głosować i zepsuć numeru! :)
luser droog
6

Większość czasu spędzam na skryptach PHP, co przyniosło mi pytanie: dlaczego muszę używać $nazw zmiennych? to moja lokalna waluta, więc użyjmy jej! Ponieważ € jest używane w wielu krajach, użyłem słów kluczowych z języków UE.

€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

Słowa kluczowe:

  • gleichjest równy w języku niemieckim
  • mientrasjest natomiast w języku hiszpańskim
  • topojest większy w języku portugalskim (aktualizacja: zamiast tego powinno być maior , dzięki daHugLenny za wskazówkę)
  • odejmowaniejest odejmowanie w języku polskim
  • afficherjest drukowany w języku francuskim
  • nowe linie są nlczasami wywoływane , a TLD NETHERLANDSjest nl, więc zdefiniowałem stałą NETHERLANDSdo wyświetlania nowych linii

Oszukałem trochę, ponieważ nie ma ifsłowa kluczowego, zdecydowałem się bezpośrednio wydrukować ostatnie dwa wiersze.

Tłumacz w Pythonie

Tłumacz wykona tylko skrypt, aby wyświetlić 99 butelek piwa.

# -*- 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])

Aby go uruchomić, zapisz oba pliki, a następnie uruchom plik Python ze .euskryptem jako argumentem:

python euro.py euro.eu
glin
źródło
4
+1! Przypomina mi „If PHP Were British”: addedbytes.com/blog/if-php-were-british
Pieter Witvoet
Ten język został udokumentowany na Esolang .
AL
1
topojest najlepszy w języku portugalskim
acrolith
@daHugLenny Przepraszam za błąd. Czy maior jest poprawnym tłumaczeniem większego ?
AL
1
@AL tak. ( komentarze muszą mieć co najmniej 15 znaków )
acrolith
5

1Lang

1Lang jest funkcjonalnym językiem przedrostka, takim jak LISP lub Scheme, ale bez nawiasów, co utrudnia czytanie, gdy wszystkie niepotrzebne białe znaki są usuwane. Nawiasy można usunąć, ponieważ wszystkie funkcje i operatory przyjmują znaną liczbę parametrów.

Nawiasy klamrowe są wymagane do rozgraniczenia treści funkcji i warunkowych konsekwencji oraz alternatywnych bloków kodu, które mogą składać się z listy instrukcji.

W LISP, czynnikowe można zdefiniować następująco:

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

w 1 języku to byłoby

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

który można zredukować do

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

1Lang obecnie nie obsługuje żadnych skutków ubocznych.

1Lang jest napisany bash, więc obecnie ma pewne ograniczenia bash, takie jak zakres liczb całkowitych.

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

Uwaga: Listy nie są w pełni zaimplementowane.

A-Z are functions

Liczby całkowite są liczbami całkowitymi typu bash (do -2 ^ 32 do 2 ^ 31-1). Liczb ujemnych nie można użyć bezpośrednio. Aby wprowadzić wartość ujemną, odejmij ją od zera. na przykład. -5 byłoby wprowadzane jako -0 5. To ograniczenie jest spowodowane tym, że 1Lang jest w toku i liczby ujemne nie były potrzebne dla tej aplikacji. Rozważam użycie ~ jako jednoznacznego operatora ujemnego, który pozwoliłby na wprowadzenie -5 jako ~ 5.

Do wyznaczenia liczb całkowitych wymagana jest biała spacja. na przykład. +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}}

Nazwy parametrów funkcji mogą przeciążać zmienne wywołujące. Wszystkie zmienne przypisane w ramach funkcji są lokalne.

Drukowanie nie jest konieczne (chociaż może być przydatne), ponieważ podobnie jak LISP każda instrukcja zwraca wartość, a drukowana jest ostatnia zwracana wartość.

eg. +2 3 prints 5

Nieoczekiwane zachowanie notacji przedrostkowej bez nawiasów polega na tym, że konkatenacja ciągów znaków może być w rzeczywistości łatwa do napisania. Powiedzmy, że chcesz połączyć "a" " quick" " brown" " fox", można napisać:

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

Ale bardziej czytelną i mniej podatną na błędy metodą jest to:

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

lub

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

99 Butelek piwa kod:

: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

Funkcja B zwraca „Brak więcej butelek” lub „1 butelka” lub „butelki” w zależności od x.

Funkcja F zwraca wiersze normalne lub końcowe. Normalny wiersz jest łączony z następnym wierszem przez rekurencyjne wywoływanie F z -x1. Gdy x wynosi 0, F zwraca ostatni wiersz.

To generuje (dla F5 oznacza początek od 5 butelek piwa ...):

> 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 Tłumacz języka (napisany bash) w mniej niż 500 liniach.

#!/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
'
philcolbourn
źródło
Chciałbym jeszcze bardziej, gdyby @Mfxy{fxy}M+3 4działał, ale musisz dołączyć do funkcji i przestrzeni nazw zmiennych. Obliczenie 99 piw zajęło trochę czasu: p
Sylwester
@Sylwester, dziękuję za zainteresowanie. Cieszę się, że spróbowałeś, a także, że zadziałało. Tak, bash jest powolny, a użycie bash do interpretacji innego języka (szczególnie przy użyciu podpowłoki) jest po prostu interesujące, ale nie przydatne. M + 3 4 byłoby niepoprawne, ponieważ +3 4 zostanie ocenione jako pierwsze w zastosowaniu. M \ xy {+ xy} 3 4 może być składnią, która działałaby.
philcolbourn
hmmm. wygląda na to, że mój opis uruchomił reguły języka znaczników i brakuje bitów.
philcolbourn
Tak, aby consmócmap M\x{*x2}C1C2C3C4/ => (2 4 6 8)
Sylwester,
4

Połowa (tłumacz / tłumacz w pakiecie Windows)

Nie wiem, dlaczego odpowiadam na tak wiele zagadek w pakiecie Windows, z jakiegoś chorego powodu, myślę, że mi się to podoba: P W każdym razie, jest to coś podobnego do czegoś, nad czym pracowałem jakiś czas temu, podstawowy język, który przetłumaczone na pakiet Windows za pomocą skryptu, który jest również zapisany w pakiecie Windows. Nie jest to szczególnie niesamowite, ale działa.

99 butelek piwa

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

Składnia

W każdej linii rozpoznawane są tylko trzy żetony, oddzielone spacjami.

# jest komentarzem.

W większości przypadków, gdy potrzebna jest wartość, $w drugim tokenie oznacza, że ​​trzecią należy traktować jako nazwę zmiennej, podczas gdy a ~oznacza literalną wartość. Ogólne instrukcje mają formę <instruction> [$~] <name>. Ustawienie zmiennej ma tę samą formę, ale jest implementowane, gdy nie zostanie rozpoznane.

Zdefiniowane polecenia:

  • printi writeoba zapisują dane wyjściowe, alewrite nie dodają nowego wiersza. Potrzebuje $ lub ~.
  • mark tworzy punkt, który można przeskoczyć lub wywołać jako podprogram.
  • jump odpowiednik goto wsadowo (lub w dowolnym innym języku).
  • procwywołuje podprogram. Odpowiednik call :label.
  • returnzwraca z podprogramu. Wyjdzie z programu, gdy nie będzie w nim.
  • ifinstrukcja warunkowa. Pobiera porównanie z następnego wiersza, w formie <var1> <operator> <var2>. Operatory są takie same jak ifwsadowe, tj. EQU, NEQ, LSS, LEQ, GTR, GEQ. Wykona instrukcje po nim tylko wtedy, gdy porównanie jest prawdziwe.
  • endif kończy instrukcję if.
  • catłączy dwie zmienne. cat a bzapisze wartość ab w a.

Gdy żadne z tych poleceń nie zostanie znalezione, wyrażenie jest traktowane jako przypisanie zmiennej, przy użyciu pierwszego tokena jako nazwy zmiennej. $i ~zachowuj się tak samo jak w print, ale jest też @identyfikator. To traktuje ostatni token jako wyrażenie matematyczne, przekazane doset /a . Obejmuje większość operatorów. Jeśli żaden z trzech identyfikatorów nie zostanie znaleziony, oznacza to błąd składniowy i interpreter zostanie zamknięty.

Tłumacz (partia Windows)

Tłumacz interpretuje kod na pakiet Windows, umieszcza go w pliku tymczasowym i wykonuje. Chociaż rozpoznaje błędy składniowe w języku Half, wynikowy skrypt wsadowy może powodować problemy, szczególnie ze znakami specjalnymi, takimi jak nawiasy, pionowe paski itp.

@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
mackthehobbit
źródło
4

Flex Bison

Przypisz zmienną, jeśli inaczej blok warunków i jakieś inne dodawanie, operacja odejmowania.

Plik leksykalny 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*/;
 %%

Plik analizatora składni 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);
  }

Skompilować

  1. Element listy
  2. flex lex.l
  3. bizon com.y
  4. gcc -o kompilator com.tab.c -lfl

Biegać

kompilator in.txt ou.txt

Plik wejściowy

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

** To jest komentarz zapisz c;

** zapisz c w pliku wydruku c * (a + 32);

Plik wyjściowy 67

Mamun
źródło
2

Interpretator

Aby uzyskać instrukcje dotyczące uruchamiania tego kodu, spójrz na moją inną odpowiedź: /codegolf//a/19935/13186

99 butelek piwa

Program

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

$
tecywiz121
źródło
2

99ISC

99ISC korzysta z pamięci zorientowanej na liczby całkowite o dowolnym rozmiarze. Pamięć jest indeksowana przez nieujemną liczbę całkowitą. Wszystkie wartości w pamięci są inicjowane ich adresem. Na przykład. W czasie wykonywania adres 0 zawiera wartość 0, a adres 9 zawiera wartość 9.

99ISC ma dwie instrukcje. Pierwszy drukuje procedurę 99 butelek piwa na ścianie. Jego składnia to pojedynczy wiersz, jak poniżej. Wykonanie jest kontynuowane od następnego wiersza w programie.

.

Druga instrukcja jest instrukcją „odejmuj i rozgałęziaj, jeśli nie jest równa zero”. Jego składnia to pojedynczy wiersz, jak poniżej.

x y z

xjest adresem liczby, która ma być operowana, yjest adresem liczby odejmowanej i zjest następnym wierszem do wykonania, jeśli wynik odejmowania nie jest równy zero. W przeciwnym razie wykonanie przechodzi do następnego wiersza.

Obecność instrukcji „odejmij-i-rozgałęź-jeśli-nie-zero” powoduje, że 99ISC jest OISC (komputer z zestawem instrukcji) i dlatego Turing jest kompletny.

Oto program, który usuwa pierwsze 10 wartości z pamięci, a następnie drukuje procedurę 99 butelek piwa na ścianie.

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
.

A tu jest interpreter 99ISC w Pythonie.

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
intx13
źródło
1
Myślę, że to łamie zasady „najlepszych praktyk” w przypadku pytań golfowych. Z ogólną instrukcją drukowania zamiast „.” to nadal działałoby, ale niech mnie szlag, jeśli mam napisać program 99BOB!
intx13
Ostatnie 2 wiersze wymagają nieco więcej pracy.
philcolbourn
2

Daję ci:

Interpreter małego zestawu instrukcji (SISI)

Składnia opiera się na języku BASIC i asemblerze. Posiada cztery oświadczenia: set, print, jump(bezwarunkowego goto) orazjumpif (goto warunkowa). Każda instrukcja musi być poprzedzona numerem linii. Obsługiwane typy danych to liczby całkowite i ciągi.

Sam interpreter można znaleźć w Pythonie 3 na Github (sisi.py). Program 99 butelek piwa jest również dostępny, ale odtworzę go tutaj:

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."
DLosc
źródło
1

Pogo

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
nrubin29
źródło
Mam problem z widzeniem, że drukuje tekst 99 butelek.
Sylwester,
Najpierw deklaruję liczbę całkowitą o nazwie ii ustawiam ją na 99. Następnie, gdy i jest większe od 0, wypisuję i bottles of beer on the walli odejmuję jedną z nich i. Jeśli problem polega na tym, że brakuje mi niektórych tekstów, mogę dodać więcej.
nrubin29
3
Podano link do tekstu piosenki (lub teraz jest). Kilka ostatnich wersetów jest nieco bardziej skomplikowanych.
philcolbourn