Tạo một trình thông dịch ngôn ngữ lập trình [đã đóng]


19

Bài tập:

Bạn phải tạo một trình thông dịch có thể phân tích các đoạn của ngôn ngữ lập trình. Ngôn ngữ không cần phức tạp, nhưng nó phải bao gồm các yếu tố cú pháp sau:

  • Khả năng gán và đọc các biến (có thể đơn giản như a- zlà biến tiền tố)
  • Nếu câu lệnh (otherif và khác không được yêu cầu)
  • Vòng lặp (đếm đến một số tùy ý, không cần truy cập người dùng vào bộ đếm)
  • Toán đơn giản với các biến (cộng, trừ, nhân, chia, lớn hơn / nhỏ hơn, bằng)
  • Báo cáo in

Quy tắc:

  • Bạn không thể sao chép cú pháp của một ngôn ngữ phổ biến khác.
  • Bạn cần viết trình thông dịch của riêng bạn, không sửa đổi trình thông dịch khác.
  • Bạn có thể viết thông dịch viên của bạn bằng bất kỳ ngôn ngữ nào.
  • Viết chương trình ví dụ 99 chai bia bằng ngôn ngữ của bạn (xem tại đây )
  • Đây là một , vì vậy câu trả lời được đánh giá cao nhất sẽ thắng.

3
Các yêu cầu của trình phân tích cú pháp là gì? Có cần phải xuất một số loại cú pháp cây?
Kendall Frey

1
Là có thể đẩy và bật từ một ngăn xếp đủ để đáp ứng yêu cầu biến?
tecywiz121

1
@Dennis - nó phải có khả năng lặp một số lần nhất định, được xác định trong thời gian chạy
TheDoctor

2
Tôi tin rằng làm cho nó một thông dịch viên, không?
Kendall Frey

3
Kinda muốn xem Guido nộp CPython.
user2357112 hỗ trợ Monica

Câu trả lời:


17

DogeScript

Chương trình 99 chai bia:

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

Trình thông dịch 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;
    }
}
?>

Cú pháp như hiện tại là:

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.

Hãy thử nó ở đây .
Bất kỳ đề xuất cải tiến đều được chào đón.


2
lập trình lvl = 100
Antonio Ragagnin

1
Bạn có biết rằng nó đã tồn tại ?
AL

Không, tôi chưa bao giờ thấy điều đó. Bummer, tôi nghĩ rằng tôi là bản gốc. :-(
Gareth

10

BrainBack: Một ngôn ngữ được biên dịch dựa trên ngăn xếp chạy trên BrainFuck

NB: Spec đã được thay đổi từ "tạo trình phân tích cú pháp" thành "tạo trình thông dịch" sau khi tôi đăng câu trả lời này. Câu trả lời này là một trình biên dịch cũng phân tích mã nguồn.

Tên này là một cách chơi chữ của Back trái ngược với ngôn ngữ dựa trên ngăn xếp nổi tiếng và Brain cho thấy bản chất bí truyền của nó. Nó trông hơi giống BrainFuck (mặc dù không phải), nhưng trình biên dịch của nó chạy trên BrainFuck và mã đối tượng được biên dịch của nó kết thúc dưới dạng nhị phân BrainFuck.

Ngôn ngữ: * == phá hủy các đối số của nó

  • "constant" in không đổi
  • # in đầu ngăn xếp dưới dạng số
  • > nhân đôi đỉnh ngăn xếp
  • <num> đẩy số không đổi <num>làm giá trị lên trên cùng của ngăn xếp
  • < loại bỏ đầu ngăn xếp
  • - trừ trên cùng từ đỉnh thứ hai *
  • + thêm trên cùng đến trên cùng thứ hai *
  • ! không bật / dương *
  • [ ... ] một thời gian trên cùng của ngăn xếp không bằng 0, rất giống với BrainFuck

99 chai bia với lời bài hát chính xác trong 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.

"
]

Trình biên dịch BrainBack, được viết bằng 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

Để biên dịch BrainBack:

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

Để biên dịch chương trình 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 

Chạy nhị phân:

bf 99.bf                        

Ở đây tôi sử dụng bf có sẵn trong hầu hết các distro debian.beefvà những người khác có thể được sử dụng là tốt. Cả trình biên dịch EBF, BrainBack và mã đối tượng của nó đều trở thành các nhị phân BrainFuck khá tương thích.

Có lẽ nên mở rộng để in một ô dưới dạng ascii ., có thể đọc một byte trong ,và có các swaphoạt động khác nhau để hữu ích hơn. Nó hoàn toàn cần thiết để tạo trình biên dịch hoặc trình thông dịch BrainBack trong BrainBack.


6
Ồ Bạn đang ở 1337 điểm đại diện ngay bây giờ ... gần như không muốn nâng cấp và làm hỏng số! :)
kẻ lừa đảo rủ rê

6

Tôi dành phần lớn thời gian cho các tập lệnh PHP và nó mang lại cho tôi một câu hỏi: tại sao tôi buộc phải sử dụng $cho tên biến của mình? là tiền địa phương của tôi, vì vậy hãy sử dụng nó! Vì € được sử dụng ở nhiều quốc gia, tôi đã sử dụng một số từ trong các ngôn ngữ EU làm từ khóa.

€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

Từ khóa:

  • gleichbình đẳng trong Đức
  • mientrastrong khi ở Tây Ban Nha
  • topolà tiếng Bồ Đào Nha lớn hơn (cập nhật: thay vào đó là maior , nhờ daHugLenny cho tiền boa)
  • odejmowaniephép trừ trong tiếng Ba Lan
  • afficherin bằng tiếng Pháp
  • dòng mới nlđôi khi được gọi và TLD NETHERLANDSnl, vì vậy tôi đã xác định một hằng số NETHERLANDSđể hiển thị dòng mới

Tôi đã lừa dối một chút vì không có if từ khóa, tôi đã chọn in trực tiếp hai dòng cuối cùng.

Thông dịch viên trong Python

Thông dịch viên sẽ không làm gì hơn là thực thi tập lệnh để hiển thị 99 chai bia.

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

Để chạy nó, lưu cả hai tệp sau đó chạy tệp Python với .eutập lệnh làm đối số:

python euro.py euro.eu

4
+1! Nhắc nhở tôi về 'Nếu PHP là người Anh': addbytes.com/blog/if-php-were-british
Pieter Witvoet

Ngôn ngữ này đã được ghi nhận trên Esolang .
AL

1
topohàng đầu trong tiếng Bồ Đào Nha
acrolith

@daHugLenny Tôi xin lỗi vì sai lầm. Là maior bản dịch chính xác của lớn hơn ?
AL

1
@AL có. ( bình luận cần ít nhất 15 ký tự )
acrolith

5

1Lang

1Lang là ngôn ngữ tiền tố chức năng như LISP hoặc Scheme nhưng không có dấu ngoặc đơn khiến cho việc đọc khó hơn một chút khi tất cả khoảng trắng không cần thiết bị xóa. Dấu ngoặc đơn có thể được loại bỏ vì tất cả các hàm và toán tử có một số tham số đã biết.

Niềng răng được yêu cầu để phân định thân hàm và hệ quả có điều kiện và các khối mã thay thế có thể bao gồm một danh sách các câu lệnh.

Trong LISP, Factorial có thể được định nghĩa như thế này:

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

trong 1Lang này sẽ là

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

có thể giảm xuống

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

1Lang hiện không hỗ trợ tác dụng phụ.

1Lang được viết bằng bash nên hiện tại nó chia sẻ một số hạn chế bash như phạm vi số nguyên.

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

NB: Danh sách không được thực hiện đầy đủ.

A-Z are functions

Số nguyên là số nguyên bash (tôi nghĩ lên tới -2 ^ 32 đến 2 ^ 31-1). Số âm không thể được sử dụng trực tiếp. Để nhập âm, trừ nó từ 0. ví dụ. -5 sẽ được nhập là -0 5. Hạn chế này là do 1Lang là một công việc đang tiến hành và không cần số âm cho ứng dụng này. Tôi đang xem xét sử dụng ~ như một toán tử phủ định đơn nhất cho phép -5 được nhập là ~ 5.

Không gian trắng là cần thiết để phân định số nguyên. ví dụ. +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}}

Tên tham số chức năng có thể quá tải các biến người gọi. Tất cả các biến được gán trong một hàm là cục bộ.

In ấn là không cần thiết (mặc dù nó có thể hữu ích) vì giống như LISP, mọi câu lệnh đều trả về một giá trị và giá trị cuối cùng được trả về được in.

eg. +2 3 prints 5

Một hành vi bất ngờ của ký hiệu tiền tố không có dấu ngoặc đơn là nối chuỗi thực sự có thể dễ viết. Nói rằng bạn muốn nối "a" " quick" " brown" " fox", người ta có thể viết:

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

Nhưng một phương pháp dễ đọc hơn và ít lỗi hơn là:

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

hoặc là

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

99 chai bia mã:

: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

Hàm B trả về "Không còn chai" hoặc "1 chai" hoặc "chai" tùy theo x.

Hàm F trả về những câu thơ bình thường hoặc câu cuối cùng. Một câu thơ bình thường được nối với câu sau bằng cách gọi đệ quy F với -x1. Khi x bằng 0, F trả về câu cuối cùng.

Điều này tạo ra (đối với F5 có nghĩa là bắt đầu từ 5 chai bia ...):

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

Thông dịch viên 1Lang (viết bằng bash) dưới 500 dòng.

#!/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
'

Tôi sẽ thích nó hơn nữa nếu @Mfxy{fxy}M+3 4làm việc nhưng sau đó bạn cần tham gia hàm và không gian tên biến. Phải mất một lúc để tính 99 loại bia: p
Sylwester

@Sylwester, cảm ơn bạn đã quan tâm. Tôi rất vui vì bạn đã thử nó và nó cũng hoạt động. Đúng, bash rất chậm và sử dụng bash để diễn giải một ngôn ngữ khác (đặc biệt là sử dụng các subshells) chỉ thú vị, nhưng không hữu ích. M + 3 4 sẽ không chính xác vì +3 4 sẽ được đánh giá đầu tiên khi áp dụng. M \ xy {+ xy} 3 4 có thể là một cú pháp sẽ hoạt động.
philcolbourn

hừm có vẻ như mô tả của tôi đã kích hoạt các quy tắc ngôn ngữ đánh dấu và các bit bị thiếu.
philcolbourn

Vâng, để khi nào consbạn có thểmap M\x{*x2}C1C2C3C4/ => (2 4 6 8)
Sylwester

4

Một nửa (trình thông dịch / trình dịch trong Windows Batch)

Tôi không biết tại sao tôi lại trả lời nhiều câu đố trong windows, vì một số lý do bệnh hoạn, tôi nghĩ rằng tôi rất thích nó: P Dù sao, điều này cũng giống với thứ mà tôi đã làm để giải trí trước đây, một ngôn ngữ cơ bản được dịch sang đợt windows bởi một đoạn script cũng được viết trong đợt windows. Nó không đặc biệt tuyệt vời, nhưng nó hoạt động.

99 chai bia

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

Cú pháp

Chỉ có ba mã thông báo được nhận dạng trên mỗi dòng, cách nhau bằng khoảng trắng.

# là một bình luận.

Trong hầu hết các trường hợp cần một giá trị, $mã thông báo thứ hai biểu thị rằng giá trị thứ ba phải được coi là tên biến, trong khi đó ~biểu thị giá trị bằng chữ. Hướng dẫn chung có hình thức<instruction> [$~] <name> . Đặt một biến có dạng tương tự, nhưng được thực hiện bất cứ khi nào không được nhận ra.

Các lệnh được xác định:

  • printwrite cả hai đầu ra ghi, nhưng writekhông thêm một dòng mới. Cần $ hoặc ~.
  • mark tạo một điểm có thể được nhảy tới hoặc được gọi là chương trình con.
  • jump tương đương với goto trong đợt (hoặc bất kỳ ngôn ngữ nào cho vấn đề đó).
  • procgọi một chương trình con. Tương đương vớicall :label .
  • returntrả về từ một chương trình con. Sẽ thoát khỏi chương trình khi không ở trong một.
  • ifhướng dẫn có điều kiện. Đưa ra so sánh từ dòng tiếp theo, trong mẫu <var1> <operator> <var2>. Các toán tử giống như ifcác lô, tức là.EQU, NEQ, LSS, LEQ, GTR, GEQ. Sẽ thực hiện các hướng dẫn sau khi nó chỉ khi so sánh là đúng.
  • endif kết thúc một câu lệnh if.
  • catnối hai biến. cat a bsẽ lưu trữ giá trị của ab trong a.

Khi không tìm thấy lệnh nào trong số các lệnh này, biểu thức được coi là phép gán biến, sử dụng mã thông báo đầu tiên làm tên biến. $~hành xử giống như trong print, nhưng cũng có một @định danh. Điều này coi mã thông báo cuối cùng là một biểu thức toán học, được truyền choset /a . Nó bao gồm hầu hết các nhà khai thác. Nếu không có một trong ba định danh được tìm thấy, đây là lỗi cú pháp và trình thông dịch thoát.

Thông dịch viên (Windows Batch)

Trình thông dịch thực sự dịch mã thành các lô windows, đặt nó vào một tệp tạm thời và thực thi nó. Mặc dù nhận ra lỗi cú pháp trong ngôn ngữ Half, tập lệnh bó kết quả có thể gây ra sự cố, đặc biệt là với các ký tự đặc biệt như dấu ngoặc đơn, thanh dọc, v.v.

@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

Bò rừng

Gán biến, nếu khối điều kiện khác và một số phép cộng, phép trừ khác.

Tập tin nhuận tràng 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*/;
 %%

Trình phân tích cú pháp 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);
  }

Biên dịch

  1. Danh sách mục
  2. flex lex.l
  3. bò rừng
  4. trình biên dịch gcc -o com.tab.c -lfl

Chạy

trình biên dịch in.txt ou.txt

Tập tin đầu vào

a = 3 + (4 * 7) -9; in một; c = a + 45; in c;

** Đây là bình luận lưu c;

** lưu c trong tệp in c * (a + 32);

Tập tin đầu ra 67


2

Thông dịch viên

Để được hướng dẫn về cách chạy mã này, hãy xem câu trả lời khác của tôi: /codegolf//a/19935/13186

99 chai bia

Chương trình

 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 sử dụng bộ nhớ định hướng nguyên có kích thước tùy ý. Bộ nhớ được lập chỉ mục bởi một số nguyên không âm. Tất cả các giá trị trong bộ nhớ được khởi tạo với địa chỉ của chúng. Ví dụ. Trong thời gian chạy, địa chỉ 0 chứa giá trị 0 và địa chỉ 9 chứa giá trị 9.

99ISC có hai hướng dẫn. Lần đầu tiên in ra 99 chai bia trên tường. Cú pháp của nó là một dòng duy nhất, như dưới đây. Thực hiện tiếp tục với dòng tiếp theo trong chương trình.

.

Lệnh thứ hai là lệnh "trừ và rẽ nhánh nếu không bằng không". Cú pháp của nó là một dòng duy nhất, như dưới đây.

x y z

xlà địa chỉ của số được vận hành trên, ylà địa chỉ của số bị trừ và zlà dòng tiếp theo để thực hiện nếu kết quả của phép trừ không bằng không. Nếu không, thực hiện tiến hành với dòng tiếp theo.

Sự hiện diện của lệnh "trừ-và-nhánh-nếu-không-không" làm cho 99ISC trở thành một OISC (Máy tính một tập lệnh) và do đó Turing hoàn tất.

Dưới đây là một chương trình xóa 10 giá trị đầu tiên trong bộ nhớ và sau đó in 99 Chai bia trên thói quen trên tường.

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
.

Và đây là một trình thông dịch 99ISC, bằng 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
Tôi đoán điều này phá vỡ các quy tắc "thực hành tốt nhất" cho các câu hỏi golf. Với một tuyên bố in chung chung thay cho "." nó vẫn hoạt động, nhưng tôi sẽ bị nguyền rủa nếu tôi viết chương trình 99BOB!
intx13

2 câu thơ cuối cần thêm một chút công việc.
philcolbourn

2

Tôi tặng bạn:

Thông dịch viên tập lệnh nhỏ (SISI)

Cú pháp dựa trên BASIC và lắp ráp. Nó có bốn câu: set, print, jump(vô điều kiện goto), và jumpif(goto có điều kiện). Mỗi câu lệnh phải được đi trước bởi một số dòng. Các loại dữ liệu được hỗ trợ là số nguyên và chuỗi.

Bản thân trình thông dịch có thể được tìm thấy trong Python 3 trên Github (sisi.py). Chương trình 99 Chai Bia cũng có ở đó, nhưng tôi sẽ sao chép nó ở đây:

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

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

Tôi gặp vấn đề khi thấy điều này in lời bài hát 99 chai.
Sylwester

Đầu tiên, tôi khai báo một số nguyên có tên ivà đặt nó bằng 99. Sau đó, trong khi tôi lớn hơn 0, tôi in i bottles of beer on the wallvà trừ một số nguyên từ đó i. Nếu vấn đề là tôi thiếu một số lời bài hát, tôi có thể thêm nhiều hơn nữa.
nrubin29

3
Một liên kết đến lời bài hát đã được (hoặc bây giờ là) được cung cấp. Vài câu thơ cuối thì phức tạp hơn một chút.
philcolbourn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.