مترجم Befunge في Python

تحضيراً لدورة "أساسيات المترجمين" لطلاب السنة الرابعة ، درست لغات برمجة مقصور على فئة مختلفة. هنا مقال جيد حول هذا الموضوع . بدا لي أن لغة Befunge (كريس برس ، 1993) هي الأكثر إثارة للاهتمام في المقالة ، وألاحظ بشكل خاص ثلاثة من ميزاتها:

  1. مجال البرنامج هو حيد ثنائي الأبعاد ، أي ماديًا ، هذه مصفوفة مستطيلة لأوامر الرمز مغلقة على طول الحد العلوي (السفلي) وعلى طول العمود الأيسر (الأيمن). يتحرك مؤشر الأمر حول الحقل (كل أمر هو حرف معين بإحداثيات س ، ص) ، وينفذ الأمر ، وينتقل. يمكن أن تكون الحركة في جميع الاتجاهات الأربعة (بشكل افتراضي ، مباشرة من النقطة 0،0) ، وعندما تتجاوز "الحقل" ، يظهر المؤشر على الجانب المقابل.
  2. هناك أمران (p ، g) في اللغة يغيران المجال نفسه ، أي البرنامج "إعادة كتابة ذاتية" أثناء التنفيذ. قد لا يكون رمز البرنامج في البداية مساويًا للرمز في النهاية. بدأ برنامج "123pgpg ## @" ، وانتهى البرنامج "ABC @ 1 @ 2 @ 3.14" (ليس مثالاً صحيحًا).
  3. أشار كريس برسى إلى أنه يريد إنشاء لغة معقدة قدر الإمكان للترجمة. في الواقع ، هذا صحيح ، إنشاء مترجم يجعل ملفات exe صعبة للغاية بالنسبة للبرنامج ، وجدت معلومات تفيد بأن شخصًا ما يمكنه القيام بذلك في لغة C ... من الأفضل إنشاء مترجم من اللغة إلى رمز Python ، والذي ما زلت أسميه مترجم البساطة.


يتكون مجال البرنامج لعام 1993 من 25 سطرا من 80 حرفا لكل منهما. هناك 36 فريقًا في اللغة ، كل منها هو حرف جدول ASCII. لمزيد من المعلومات ، راجع ويكيبيديا ، سأقدم وصفًا موجزًا ​​من هناك:

أوامر النقل (9):

> تحريك لليمين
<تحريك لليسار
^ تحريك لأعلى
v تحريك لأسفل
_ تحريك لليمين إذا كان الجزء العلوي من المكدس 0 ، وإلا غادر.
| انتقل لأسفل إذا كان فوق المكدس 0 ، وإلا لأعلى.
؟؟؟ التحرك في اتجاه عشوائي
# تخطي الخلية التالية ("نقطة الانطلاق")
@

أوامر معالجة

التكدس في نهاية البرنامج (3) :: ضع نسخة من الرأس على المكدس
\ Swap vertex and vertex
$ Delete vertex

أوامر تعديل كود البرنامج (2):
p "PUT": يتم استحداث إحداثيات الخلية ورمز ASCII للحرف الذي يتم وضعه في هذه الإحداثيات
من المكدس g "GET": يتم استخراج إحداثيات الخلية من المكدس ؛ يتم دفع كود ASCII لرمز عند هذه الإحداثيات إلى المكدس.

الأوامر الثابتة (2):

0-9 ضع رقمًا في
بداية / نهاية مكدس وضع الرمز ، حيث يتم

دفع رموز ASCII لجميع أحرف البرنامج الحالية إلى المكدس . العمليات الحسابية (5):

+ إضافة قمة و قمة
- طرح قمة و قمة
* ضرب رأس و
قسمة رأس / عدد صحيح
٪ التقسيم

أوامر المكدس والعمليات المنطقية (2)

:! النفي: يتم استبدال الصفر في الرأس بالرقم 1 ، ويتم استبدال القيمة غير الصفرية بـ 0
"مقارنة" أكبر من ": إذا كان الرأس أكبر من الرأس ، يتم وضع 1 على المكدس ، وإلا فإن

أوامر الإدخال / الإخراج (4):

& طلب المستخدم لرقم ووضعه على المكدس
~ اطلب من المستخدم حرفًا ووضع على المكدس رمز ASCII الخاص به
. قم بطباعة الجزء العلوي من المكدس كعدد صحيح
، وطباعة الحرف المقابل لرمز ASCII في الجزء العلوي من المكدس

قررت كتابة مترجم Befunge (مترجم) في Python وفقًا لقواعد عام 1993 مع بعض القيود: 1) الحقل ليس 25 × 80 حرفًا ، ولكن الحد الأدنى للعرض والارتفاع لكتلة النص ، 2) الحقل غير مرتبط بالحيد ، أي لا تتم معالجة تجاوز الحدود مع القفز إلى الجانب الآخر. هذا ليس الكسل (على الرغم من ، أنا أمزح؟) ، بالنسبة للأمثلة الصغيرة ، كل شيء يعمل بشكل جيد ، وإنهاء المجال إلى حيد حقيقي أمر بسيط للغاية ، ستكون هناك رغبة.

ظهرت الشفرة في بعض الأماكن دون داعٍ "على الجبهة" ، ولكن هذا يرجع إلى حقيقة أنها مخصصة للطلاب ومهمتها أن تكون واضحة قدر الإمكان ، ولا يتم اختصارها إلى بضعة أسطر باللغة الصينية.

الجزء الأول


يتم توفير الرمز من البداية إلى النهاية مع استثناء واحد (سيتم تحديده) ، ويمكن نسخه إلى ملف وتشغيله. النص الكامل متاح على الرابط rentry.co/ivansedov-befunge ، من السابق لأوانه تقديم أفضل ما لدي على GitHub. بالمناسبة ، هناك حوالي 20 تطبيق لغة Befunge هناك ، ولكن الرمز إما باللغة C (وليس لغتي) أو Python ، ولكنه معقد للغاية لدرجة أنني لم أجرؤ على الغوص. ومع ذلك ، هناك يمكنك أخذ برامج عينة للاختبارات ، على سبيل المثال ، هنا github.com/causal-agent/befungee

from sys import *
import time
import random

إستيراد المكتبات:

  1. مكتبة sys مطلوبة للحصول على اسم ملف البرنامج. كان برنامج التحويل البرمجي الخاص بي يسمى bbb.py ، وهو مثال اختباري في نفس الدليل 1.bf ، Python الإصدار 3.7 نفسه ، وهكذا بدا استدعاء البرنامج في وحدة التحكم كما يلي: python3 bbb.py 1.bf
  2. time , , 0,5-1,0 .
  3. random «?» ( ), . -, Befunge - , « » (1 , 2 , 3 , 4 ). « » .

class Pointer:
    def __init__(self, x=0, y=0, vector=2, value=None):
        self.x = x
        self.y = y
        self.vector = vector
        self.value = value
        self.stack = []
        self.stack_sf = 0

    def __str__(self):
        return 'Point ({},{}) vektor:{} value:{} stack_sf:{} stack:{}'.format(self.x, self.y, self.vector, self.value, self.stack_sf, self.stack)

    def step(self):
        if self.vector == 1:
            self.x -= 1
        elif self.vector == 2:
            self.y += 1
        elif self.vector == 3:
            self.x += 1
        elif self.vector == 4:
            self.y -= 1

    def action(self):
	#   ,   

الفئة الرئيسية المستخدمة في البرنامج: المؤشر (المؤشر) ، لديه 6 خصائص وطريقتين. الخواص: 1) إحداثيات x (مبدئيًا = 0) ، 2) إحداثيات y (مبدئيًا = 0) ، 3) متجه (اتجاه الحركة ، مبدئيًا = 2 إلى اليمين) ، 4) القيمة (قيمة المجال ، التي تقع في إحداثيات س ، ص ، مبدئيًا = بلا) ، هذا في الواقع ، الأمر الذي سيتم تنفيذه ، 5) مكدس (مكدس برنامج ، مبدئيًا = []) و 6) stack_st (علامة لإدخال الأسطر ، مبدئيًا = 0).

يحتوي الفصل على طريقتين: 1) الخطوة () خطوة المؤشر ، دون أي اختبارات واختبارات ، يغير إحداثيات س ، ص اعتمادًا على الاتجاه في المتجه و 2) الإجراء () هو قلب المترجم ، تنفيذ أمر البرنامج الحالي. سأعطي كود العمل () في الجزء الثاني ، بحيث لا يصرف عن المنطق.

# ===============================
# =                      =
# ===============================

def open_file(name):
    data = open(name, 'r').read()
    return data

def field_print():
    for row in A:
        for elem in row:
            print(elem, end='')
        print()  

وظيفتان إضافيتان: 1) يفتح ملف open_file (الاسم) الملف بالاسم المرسل ، ويقرأه ويعيد المحتويات ، و 2) print_print () تطبع محتويات المصفوفة A ، حيث توجد أحرف البرنامج. يتم إنشاء إنشاء الصفيف A أدناه.

# ===========================================
# =                       =
# ===========================================

numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
operators = ['+', '-', '*', '/', '%']
point = Pointer()                           #  
text = open_file(argv[1]).split("\n")       #  
n = len(text)                               # n =  
m = 0                                       # m =  

#    (   m)
for line in text:
    if len(line) > m:
        m = len(line)

#   ( n  m )
A = [' '] * n
for i in range(n):
    A[i] = [' '] * m

#    
for i in range(len(text)):
    for j in range(len(text[i])):
        A[i][j] = text[i][j]

إعدادات البرنامج الأساسية. في قائمة الأرقام ، نضع جميع الأرقام من 0 إلى 9 ، والتي يمكن كتابتها في البرنامج (لن يصلح 10 بعد الآن ، حرفان). في قائمة عوامل التشغيل ، نضع عوامل الحساب الأساسية. إنشاء نقطة = كائن المؤشر (الإعدادات الافتراضية) ، والذي سنعمل معه طوال الوقت ...

في النص المتغير نضع النص المقروء للبرنامج القابل للتنفيذ ، مقسمًا برمز "السطر الجديد". ونتيجة لذلك ، يتكون النص من عدة أسطر من النص بأطوال مختلفة ، والتي يجب وضعها في مجموعة مستطيلة من المساحات في أماكنها. من السهل العثور على عدد الأسطر n = len (text) ، ولكن يجب حساب عدد الأعمدة بناءً على الحد الأقصى لطول الأسطر المضمنة في النص. لم أجد طريقة أخرى للقيام بهذا الجبين: تمر عبر جميع الخطوط والعثور على واحد مع الحد الأقصى للطول. باستخدام n و m (عدد الصفوف وعدد أعمدة الحقل المستقبلي) ، يمكنك إنشاء مصفوفة ثنائية الأبعاد ، وملئها بمسافات ، ثم الانتقال فوق النص لوضع الأحرف في أماكنها.

والنتيجة هي مستطيل من الحروف بين المسافات وكل هذا هو مصفوفة ثنائية الأبعاد ن م. بعد هذه الإعدادات ، يمكنك استدعاء وظيفة field_print () والتأكد من أن كل شيء يبدو جميلًا ، ولم يطفو شيء ولم ينتهك الموقف.

# ==========================================
# =                       =
# ==========================================

# field_print()

while point.value != '@':
    try:
        point.value = A[point.x][point.y]       # 1)    point
        point.action()                          # 2)  
        # print(point)                            # 3) :  
        # time.sleep(0.5)                         # 4) :  0.5 c
    except IndexError:                          #     =  
        print('     ')
        break

# field_print()
print()

كل شيء ينتهي بالبرنامج الرئيسي (الدورة) ، وبعده يمكنك عرض الحقل (مفيد في بعض الأحيان). تدور الدورة حتى يشير المؤشر إلى الرمز "@" (علامة العطف ، الكلب ، نهاية البرنامج). داخل الدورة ، يتم تنفيذ 4 إجراءات في كل مرة:

  1. في الخاصية point.value ، تتم قراءة الحرف الموجود في الصفيف A عند إحداثيات point.x ، point.y
  2. يتم استدعاء الأسلوب point.action () ، حيث يتم تنفيذ الأمر الحالي (قراءة فقط)
  3. يتم عرض مؤشر على الشاشة (جميع الخصائص)
  4. يتم التأخير قبل التكرار التالي (0.1 ثانية - 0.5 ثانية)

يعتبر العنصران 3 و 4 اختياريين تمامًا (حتى يتم التعليق عليهما) ، لكنني أوصي باستخدامهما للاختبار. تحدث جميع الإجراءات داخل الحلقة مع التقاط خطأ IndexError (خطأ يتجاوز حدود الفهرس) ، وهذا يسمح لك باعتراض خطأين رئيسيين في المترجم:

  1. التفت إلى المكدس ، ولا توجد قيم
  2. لقد تجاوزنا عن غير قصد البرنامج (الصفيف) في العرض أو الارتفاع

يلزم وجود آخر طباعة فارغة () بحيث تعمل وحدة التحكم من سطر جديد بعد عرض الإخراج.

الجزء 2


حان الوقت الآن لأهم رمز - محتويات طريقة point.action () لفئة المؤشر. يجب إدراج كل شيء أدناه حيث تم كتابته:

    def action(self):
	#   ,   

انتبه إلى المسافة البادئة:

        if self.value == '"' and self.stack_sf == 0:                # ,  "
            self.stack_sf = 1
        elif self.value == '"' and self.stack_sf == 1:
            self.stack_sf = 0
        elif self.stack_sf == 1:                                    # "Hello"   
            self.stack.append(ord(self.value))
        elif self.value in numbers and self.stack_sf == 0:
            # 123   
            self.stack.append(int(self.value))

في الواقع ، فإن التعليمات البرمجية داخل الإجراء () هي الكثير من الشروط ، ويتم تنفيذ كل منها عندما يكون هذا الأمر تحت المؤشر. يبدأ كل شيء بالشرط "إذا كان الأمر الحالي = علامة اقتباس وعلم بداية السطر stack_sf = 0" ، في هذه الحالة يتم رفع العلم إلى 1. أدخلنا السطر.

(خلاف ذلك) إذا كان الأمر الحالي = علامة اقتباس ورفع العلم إلى 1 ، فهذا يعني أنه تم العثور على علامة الاقتباس مرة ثانية ويجب عليك التوقف عن إدخال السلسلة (يتم خفض علامة stack_sf إلى 0). نحن خارج الخط.

(بخلاف ذلك) إذا لم يعمل الشرطان الأولين والعلم stack_sf = 1 ، فإننا "موجودون داخل السطر" ونحتاج إلى إضافة رمز الرمز الحالي إلى المكدس. ليس الحرف نفسه ، ولكن رمز ASCII الخاص به.

(خلاف ذلك) إذا كان الحرف الحالي من بين عناصر الأرقام والعلم هو stack_sf = 0 ، فهذا أولاً رقم ، وثانيًا ، لسنا داخل السطر ، نحتاج إلى إضافة الحرف الحالي = رقم إلى المكدس. لا تضيف رمز الحرف ، ولكن الحرف نفسه. ما زلت تذكر أن هناك رقمًا واحدًا ، ولديها رمز = 49. لذا ، إذا كنا داخل السطر ، فعندئذٍ نحتاج إلى إضافة 49 إلى المكدس ، وإذا كان موجودًا فقط في البرنامج ، فيجب أن يضيف الأمر 1 إلى المكدس 1.

فيما يلي سوف تكون جميع الشروط متباعدة (وإلا ، إذا ...) ، لذا سأكتبها فقط "إذا". بالإضافة إلى ذلك ، جميع الشروط مزدوجة ، تحتاج إلى التحقق من الحرف الحالي للتساوي مع الأمر وحقيقة أننا لسنا داخل السلسلة (داخل السلسلة ، تتم معالجة جميع الأحرف بشكل مختلف). يمكنك كتابة كل هذا بطريقة أفضل ، ولكن هذا الحل يسمح لك بتركيز الانتباه على هذه الجبهة.

        elif self.value in operators and self.stack_sf == 0:
            b = self.stack.pop()
            a = self.stack.pop()
            if self.value == '+':
                res = a + b                                         # a+b  
            elif self.value == '-':
                res = a - b                                         # a-b  
            elif self.value == '*':
                res = a * b                                         # a*b  
            elif self.value == '/':
                if b == 0:
                    res = 0
                else:
                    res = a // b                                    # a//b  
            elif self.value == '%':
                res = a % b                                         # a%b  
            self.stack.append(res)

إذا كان الحرف الحالي من بين عوامل التشغيل (و stack_sf = 0) ، فهذا يعني أننا دخلنا في عملية حسابية. جميعها متشابهة تمامًا: 1) تتم إزالة الرقم ب (مع الحذف) ، 2) الرقم أزال (مع الحذف) ، 3) الدقة = قيمة العملية بين أ و ب ، 4) يتم دفع الدقة إلى المكدس. عند القسمة على 0 ، تكون الإجابة 0 ، على الرغم من أن مؤلف اللغة متاح لاختيار 0 أو 1.

        elif self.value == '!' and self.stack_sf == 0:
            a = self.stack.pop()
            if a == 0:
                a = 1
            else:
                a = 0
            # 0->1, 1->0
            self.stack.append(a)

        elif self.value == '`' and self.stack_sf == 0:
            a = self.stack.pop()        # 
            b = self.stack.pop()        # 
            if b > a:
                res = 1
            else:
                res = 0
            # b>a -> 1|0
            self.stack.append(res)

إذا كان الرمز الحالي هو "!" ، فأنت بحاجة إلى استبدال رأس (قمة) المكدس: كان 0 - سيصبح 1 ، كان هناك شيء مختلف عن 0 - سيكون 1. إذا كان الرمز الحالي "» "(الفاصلة العليا) ، فأنت بحاجة إلى التحقق من القمة والعمود الفقري : 1) إذا كان الرأس أكبر من القمة ، ثم 1 ، 2) إذا كان الرأس أقل من (أو يساوي) الرأس ، ثم يتم وضع 0 على المكدس. يرجى ملاحظة أنه عند إزالة العناصر للمقارنة ، تتم إزالتها (حذف) ، وليس يتم نسخها.

        elif self.value == '?' and self.stack_sf == 0:
            # ? ( )
            a = random.randint(1, 4)
            self.vector = a

        elif self.value == ':' and self.stack_sf == 0:              #  
            last = self.stack.pop()
            self.stack.append(last)
            self.stack.append(last)

        elif self.value == '\\' and self.stack_sf == 0:             # ab => ba
            a = self.stack.pop()
            b = self.stack.pop()
            self.stack.append(a)
            self.stack.append(b)

إذا كان الحرف الحالي هو "؟" ، فأنت بحاجة إلى اختيار اتجاه عشوائي ومتابعة ذلك. نستخدم الدالة random.randint (1 ، 4) ، التي تولد الأرقام 1،2،3،4 وتضع القيمة الجديدة في point.vector.

إذا كان الحرف الحالي هو ":" ، فإننا نضع على المكدس نسخة من الجزء العلوي من المكدس ، أي قراءتها ، ثم إضافتها إلى المكدس مرتين.

إذا كان الحرف الحالي هو "\\" (الشرطة المائلة للخلف) ، فأنت بحاجة إلى تبديل قمة الرأس والرأس الفرعي. نحصل على رقمين ، نضعهما على المكدس بالترتيب العكسي.

        elif self.value == '#' and self.stack_sf == 0:              #  ""
            self.step()

        elif self.value == ',' and self.stack_sf == 0:              # =65=A
            value = self.stack.pop()
            print(chr(value), end='')

        elif self.value == '.' and self.stack_sf == 0:              # Print 
            a = self.stack.pop()
            print(a, end='')

إذا كان الرمز الحالي هو "#" (الجنيه) ، فيجب عليك القفز فوق الأمر التالي (في الاتجاه). لاحظ أنه في نهاية الإجراء () ، هناك قفزة غير مشروطة للأمام self.step () ، تسمح لك بالمضي قدمًا إلى الأمر التالي. بعد كتابة self.step () في معالجة "#" ، فإننا في الواقع نقوم بعمل قفزتين و "تخطي" الأمر التالي بعد "#".

إذا كان الحرف الحالي "،" (فاصلة) ، فأنت بحاجة إلى طباعة حرف يكون رمز ASCII أعلى المكدس. إذا كان الرقم 65 موجودًا ، فيجب عرض "A".

إذا كان الحرف الحالي هو "." (نقطة) ، فأنت بحاجة إلى طباعة الرقم الموجود في الجزء العلوي من المكدس ، تمامًا مثل الرقم. إذا كان هناك 65 ، فأنت بحاجة إلى عرض "65". في كلتا الحالتين ، يتم تعيين المعلمة end = '' أثناء الإخراج بحيث لا يكون هناك فاصل أسطر جديد.

        elif self.value == '_' and self.stack_sf == 0:              #  "_"
            test = self.stack.pop()
            if test == 0:
                #  = 0, (2)
                self.vector = 2
            else:
                #  !=0, (4)
                self.vector = 4

        elif self.value == '|' and self.stack_sf == 0:              #  "|"
            test = self.stack.pop()
            if test == 0:
                self.vector = 3
            else:
                self.vector = 1

إذا كان الحرف الحالي هو "_" (الشرطة السفلية) ، فقم بالتحقق أفقيًا. نزيل من المكدس الرقم للتحقق (الاختبار) ، إذا كان = 0 ، ثم ننتقل إلى اليمين (المتجه = 2) ، إذا كان! = 0 ، فإننا ننتقل إلى اليسار (المتجه = 4).

إذا كان الحرف الحالي = "|" (شريط عمودي) ، فأنت بحاجة إلى إجراء فحص عمودي. نزيل الرقم (اختبار) من المكدس ، إذا كان = 0 ، ثم ننزل لأسفل (المتجه = 3) ، وإلا فإننا نتحرك لأعلى (المتجه = 1).

        elif self.value == '$' and self.stack_sf == 0:              #  
            self.stack.pop()

        elif self.value == '~' and self.stack_sf == 0:              # Input: A => 65
            val = input(' : ')
            self.stack.append(ord(val[0]))

        elif self.value == '&' and self.stack_sf == 0:              # Input: 65 => 65
            val = int(input(' : '))
            self.stack.append((val))

        elif self.value == 'p' and self.stack_sf == 0:              # x, y, symcode
            x = self.stack.pop()                                    # A(x,y) = symcode
            y = self.stack.pop()
            symcode = self.stack.pop()
            A[x][y] = chr(symcode)

        # x, y, value=A(x,y)
        elif self.value == 'g' and self.stack_sf == 0:
            x = self.stack.pop()                                    # ord(value) => 
            y = self.stack.pop()
            value = A[x][y]
            self.stack.append(ord(value))

إذا كان الحرف الحالي = "$" ، فأنت بحاجة إلى إزالة الرأس. جعل البوب ​​بسيط ().

إذا كان الحرف الحالي = "~" (التلدة) ، فإننا نطلب من المستخدم حرفًا ووضع رمز ASCII على المكدس. تم إرسال المستخدم "أ" (الإنجليزية) ، يجب أن نضع 65 على المكدس. فقط في حالة ، سنضع فال [0] ، وإلا يمكن للمستخدم إدخال "آبل" وترجمته إلى رمز لا يعمل.

إذا كان الحرف الحالي = "&" (علامة العطف) ، فإننا نطلب من المستخدم رقمًا ونضع الرقم على المكدس. لقد دخلت 65 ، وتحتاج إلى وضع 65 على المكدس ،

والآن أصعب فريقين.

إذا كان الحرف الحالي = "p" ، فأنت بحاجة إلى استخراج إحداثيات الخلية ورمز ASCII للحرف من المكدس ، ثم وضع هذا الحرف في هذه الإحداثيات في الحقل A. افترض أن 1.2.65 على المكدس وحصلنا على (1.2) و 65 ، يجب أن نضع الرمز "A" في الخلية (1.2). مرة أخرى ، ألاحظ: حصلنا على ثلاثة أرقام ، ووضعنا رمزًا في الإحداثيات.

إذا كان الحرف الحالي = "g" ، فسيتم استرداد إحداثيات الخلية من المكدس ، ويتم البحث عن الخلية في الحقل ، ويتم أخذ الحرف من هناك ويتم دفع رمز ASCII الخاص بها إلى المكدس. لنفترض أن الرمز "B" كان ملقى على الحقل في الخلية (2،3) ، وحصل الفريق الحالي على "g" وحصلنا على 2،3 من المكدس. في هذه الحالة ، نذهب على طول الإحداثيات (2،3) ، ونحصل على الرمز "B" من هناك ، ونترجمه إلى الرقم 66 (رمز الرمز B) ونضع 66 على المكدس.

        elif self.value == '>' and self.stack_sf == 0:              # >
            self.vector = 2
        elif self.value == '<' and self.stack_sf == 0:              # <
            self.vector = 4
        elif self.value == '^' and self.stack_sf == 0:              # ^
            self.vector = 1
        elif self.value == 'v' and self.stack_sf == 0:              # v
            self.vector = 3
        self.step()                                                 #  

حسنًا ، وآخر أسطر من التعليمات البرمجية: تنظيم تحريك المؤشر عبر الحقل. كل شيء بسيط هنا: ننظر إلى الرمز ونغير الاتجاه (متجه). في نهاية وظيفة action () هي self.step () ، التي تأخذ خطوة واحدة في الاتجاه الحالي. وبالتالي ، فإن الإجراء () هو تنفيذ الإجراء وخطوة الحرف التالي.

استنتاج


كتابة هذا المترجم كان من دواعي سروري. وكم فرح جلب لحظات عندما رمي كود معين في البرنامج ، ويتم تنفيذه (بشكل صحيح!) وتلاحظه! ساعد موقع befungius.aurlien.net كثيرًا عند العمل ، حيث نشر المؤلف مترجم Befunge عبر الإنترنت (في JavaScript). إليك مقطع الفيديو الخاص به من بعض المؤتمرات www.youtube.com/watch؟v=oCPT3L33848 ، الذي يتحدث فيه عن اللغة.

للاختبار ، يمكنك استخدام أي برنامج تقريبًا على Befunge ، باستثناء تلك التي تتطلب مجالًا كحيد ، أي لديها تحولات في اتجاهات مختلفة من العالم. بالنسبة لبعض البرامج ، تحتاج إلى رؤية الحقل نفسه (على سبيل المثال ، يقوم برنامج العداد بتغيير الإحداثيات A [0] [1]) ، لذا قم إما بإخراج إخراج هذا الإحداثيات على الشاشة أو عرض المصفوفة بأكملها بعد كل خطوة.

على أي حال ، هذا ليس برنامجًا يمسح للتألق ، بل هو رمز تدريب يمكن إضافته وتحريره. الأخطاء المطبعية ممكنة ، على الرغم من أنني اختبرتها عدة مرات. النقد ليس موضع ترحيب ، ولكن ليس ممنوعًا. حظ سعيد للجميع ورمز جيد

مرحبا بالعالم!

0"!dlrow olleH">:#,_@

الباز

0> 1+:3%v
>^  v%5:_:5% v
,v.:_v     v0_0"zzub"v
"v         #
     >0"zzub"v
"   v"fizz"<         <
^<         $<>:#,_v
    >      #^^#   <

فيبوناتشي

62*1+v>01p001>+v>\:02p\:02gv
     0       ^             <
     .         :p
     "         .1
        v 0," "<0
     "  >1g12-+:|
     ,          @
     >^

العد

>91+:9`v
p   v  _v
    >$0 v
^ 01+*68<

لكن هذا لا يعمل ، الخروج من الميدان

0>:00p58*`#@_0>:01p78vv$$<
@^+1g00,+55_v# !`\+*9<>4v$
@v30p20"?~^"< ^+1g10,+*8<$
@>p0\>\::*::882**02g*0v >^
`*:*" d":+*:-*"[Z"+g3 < |<
v-*"[Z"+g30*g20**288\--\<#
>2**5#>8*:*/00g"P"*58*:*v^
v*288 p20/**288:+*"[Z"+-<:
>*%03 p58*:*/01g"3"* v>::^
   \_^#!:-1\+-*2*:*85<^

روابط ومواد إضافية:

  1. كود كامل
  2. نسخة عبر الإنترنت
  3. انها في جافا سكريبت
  4. التوثيق (الإنجليزية)
  5. مقالة ويكي (الإنجليزية)

All Articles