设计了一门编程语言,说来惭愧,解释器相当简陋低效。这东西有什么用我也不知道,总之先设计出来再说。语法是极其简单的。
示例程序
RULE.TXT
规定了所有宏替换规则,规则十分简单,替换的进行顺序是从上至下的。现在实现了四位整数的加法,两位整数的前缀和运算,以及相关的一些其他运算。
$ AND ( 1 , #VAR ) : #VAR
$ AND ( 0 , #VAR ) : 0
$ OR ( 0 , #VAR ) : #VAR
$ OR ( 1 , #VAR ) : 1
$ IF ( 1 , #VAR ) : #VAR
$ IF ( 0 , #VAR ) :
$ IF ( 1 , #VAR1 , #VAR2 ) : #VAR1
$ IF ( 0 , #VAR1 , #VAR2 ) : #VAR2
$ IF ( 1 , ( #T1 , #T2 ) , ( #F1 , #F2 ) ) : ( #T1 , #T2 )
$ IF ( 0 , ( #T1 , #T2 ) , ( #F1 , #F2 ) ) : ( #F1 , #F2 )
$ INC ( 0 ) : 1
$ INC ( 1 ) : 2
$ INC ( 2 ) : 3
$ INC ( 3 ) : 4
$ INC ( 4 ) : 5
$ INC ( 5 ) : 6
$ INC ( 6 ) : 7
$ INC ( 7 ) : 8
$ INC ( 8 ) : 9
$ INC ( 9 ) : 0
$ INC ( #V , 9 ) : INC ( #V ) , 0
$ INC ( #V1 , #V2 ) : #V1 , INC ( #V2 )
$ DEC ( 9 ) : 8
$ DEC ( 8 ) : 7
$ DEC ( 7 ) : 6
$ DEC ( 6 ) : 5
$ DEC ( 5 ) : 4
$ DEC ( 4 ) : 3
$ DEC ( 3 ) : 2
$ DEC ( 2 ) : 1
$ DEC ( 1 ) : 0
$ DEC ( 0 ) : 9
$ DEC ( #V , 0 ) : DEC ( #V ) , 9
$ DEC ( #V1 , #V2 ) : #V1 , DEC ( #V2 )
$ NOT ( 0 ) : 1
$ NOT ( #VAR ) : 0
$ LEQ ( 0 , 0 ) : 1
$ LEQ ( 0 , #_ ) : 1
$ LEQ ( 1 , 0 ) : 0
$ LEQ ( #VAR1 , #VAR2 ) : LEQ ( DEC ( #VAR1 ) , DEC ( #VAR2 ) )
$ EQU ( 0 , 0 ) : 1
$ EQU ( 0 , #VAR ) : 0
$ EQU ( #VAR , 0 ) : 0
$ EQU ( #VAR1 , #VAR2 ) : EQU ( DEC ( #VAR1 ) , DEC ( #VAR2 ) )
$ EQU ( ( #A1 , #A2 ) , ( #B1 , #B2 ) ) : AND ( EQU ( #A1 , #B1 ) , EQU ( #A2 , #B2 ) )
$ MIN ( #A , #B ) : IF ( LEQ ( #A , #B ) , #A , #B )
$ MAX ( #A , #B ) : IF ( LEQ ( #A , #B ) , #B , #A )
$ ADD ( 0 , #A ) : 0 , #A
$ ADD ( #A , 0 ) : 0 , #A
$ ADD ( #A , 9 ) : 1 , DEC ( #A )
$ ADD ( 9 , #A ) : 1 , DEC ( #A )
$ ADD ( #A , #B ) : ADD ( DEC ( #A ) , INC ( #B ) )
% warning : this version of "ADD" is without carry in
$ SECOND ( #A , #B ) : #B
$ ADD ( ( #A1 , #A2 ) , ( #B1 , #B2 ) ) : ADDTOP ( SECOND ( ADD ( #A1 , #B1 ) ) , ADD ( #A2 , #B2 ) )
$ ADDTOP ( #H1 , #H2 , #L ) : SECOND ( ADD ( #H1 , #H2 ) ) , #L
$ REPEAT ( #VAL , 0 ) :
$ REPEAT ( #VAL , 1 ) : #VAL
$ REPEAT ( #VAL , #TIME ) : #VAL , REPEAT ( #VAL , DEC ( #TIME ) )
$ REPEAT ( ( #V1 , #V2 ) , 0 ) :
$ REPEAT ( ( #V1 , #V2 ) , 1 ) : ( #V1 , #V2 )
$ REPEAT ( ( #V1 , #V2 ) , #TIME ) : ( #V1 , #V2 ) , REPEAT ( ( #V1 , #V2 ) , DEC ( #TIME ) )
$ DELETE ( 0 ) :
$ DELETE ( #CNT ) #A , : DELETE ( DEC ( #CNT ) )
% deprecated : MAXLIST
$ MAXLIST #A , #B : MAXLIST MAX ( #A , #B )
$ MAXLIST #A ; : #A
% warning : Pay attention to the char ";"
% $ TO_END ( #VAL ) , #A : #A , TO_END ( #VAL )
% $ , TO_END ( #VAL ) ; : ; #VAL
% $ TO_END ( #VAL ) ; : #VAL
% warning : You must ban the OPTIMIZE for "REVERSE"
% $ REVERSE ; : ;
% $ REVERSE , #A ; : ; #A
% $ REVERSE , #A , : TO_END ( #A ) , REVERSE ,
$ DELETE_FIRST ( #1 , #2 , #3 , #4 , #5 ) : #2 , #3 , #4 , #5
$ SUM ( 0 ) : 0 , 0 , 0 , 0
$ SUM ( 1 ) : 0 , 0 , 0 , 1
$ SUM ( #V ) : DELETE_FIRST ( ADD4 ( ( SUM ( DEC ( #V ) ) ) , ( 0 , 0 , 0 , #V ) ) )
$ SUM ( 0 , #L ) : SUM ( #L )
$ SUM ( #H , #L ) : DELETE_FIRST ( ADD4 ( ( SUM ( DEC ( #H , #L ) ) ) , ( 0 , 0 , #H , #L ) ) )
$ ADD3 ( ( #A2 , #A1 , #A0 ) , ( #B2 , #B1 , #B0 ) ) : MERGE_SUM ( ADD ( #A2 , #B2 ) , ADD ( #A1 , #B1 ) , ADD ( #A0 , #B0 ) )
$ MERGE_SUM ( #B6 , #B5 , #B4 , #B3 , #B2 , #B1 ) : MERGE_SUM ( #B6 , #B5 , #B4 , ADD ( #B3 , #B2 ) ) , #B1
$ MERGE_SUM ( #B6 , #B5 , #B4 , #B3 , #B2 ) : MERGE_SUM ( #B6 , ADD ( ( ADD ( ( 0 , #B5 ) , ( 0 , #B4 ) ) ) , ( 0 , #B3 ) ) ) , #B2
$ MERGE_SUM ( #B6 , #B5 , #B4 ) : SECOND ( ADD ( #B6 , #B5 ) ) , #B4
$ ADD4 ( ( #1 , #2 , #3 , #4 ) , ( #5 , #6 , #7 , #8 ) ) : MERGE_SUM_4 ( ADD ( #1 , #5 ) , ADD3 ( ( #2 , #3 , #4 ) , ( #6 , #7 , #8 ) ) )
$ MERGE_SUM_4 ( #1 , #2 , #3 , #4 , #5 , #6 ) : ADD ( ( #1 , #2 ) , ( 0 , #3 ) ) , #4 , #5 , #6
PROGRAM.TXT
程序中计算了两个数的加法。
ADD ( ( 4 , 3 ) , ( 1 , 7 ) ) ;
运行效果:
PROGRAM = ADD ( ( 4 , 3 ) , ( 1 , 7 ) ) ;
PROGRAM = ADDTOP ( SECOND ( ADD ( 4 , 1 ) ) , ADD ( 3 , 7 ) ) ;
PROGRAM = ADDTOP ( SECOND ( ADD ( DEC ( 4 ) , INC ( 1 ) ) ) , ADD ( DEC ( 3 ) , INC ( 7 ) ) ) ;
PROGRAM = ADDTOP ( SECOND ( ADD ( DEC ( 3 ) , INC ( 2 ) ) ) , ADD ( DEC ( 2 ) , INC ( 8 ) ) ) ;
PROGRAM = ADDTOP ( SECOND ( ADD ( DEC ( 2 ) , INC ( 3 ) ) ) , 1 , DEC ( 1 ) ) ;
PROGRAM = ADDTOP ( SECOND ( ADD ( DEC ( 1 ) , INC ( 4 ) ) ) , 1 , 0 ) ;
PROGRAM = SECOND ( ADD ( 5 , 1 ) ) , 0 ;
PROGRAM = SECOND ( ADD ( DEC ( 5 ) , INC ( 1 ) ) ) , 0 ;
PROGRAM = SECOND ( ADD ( DEC ( 4 ) , INC ( 2 ) ) ) , 0 ;
PROGRAM = SECOND ( ADD ( DEC ( 3 ) , INC ( 3 ) ) ) , 0 ;
PROGRAM = SECOND ( ADD ( DEC ( 2 ) , INC ( 4 ) ) ) , 0 ;
PROGRAM = SECOND ( ADD ( DEC ( 1 ) , INC ( 5 ) ) ) , 0 ;
PROGRAM = 6 , 0 ;
PROGRAM = 6 , 0 ; AFTER 13 ITERATION
解释器 RUN.PY
import traceback
import json
import os
def LOAD_RULES(FILE_NAME = 'RULE.TXT'): # INPUT RULE.TXT
FPIN = open(FILE_NAME, "r")
RULES_RAW = FPIN.readlines() # READ BY LINES
FPIN.close()
RULES = [] # RULES OF THE PROGRAM
LINE_ID = 1
for LINE in RULES_RAW:
LINE_LIST = LINE.split() # SPLIT INTO ELEMENTS
if len(LINE_LIST) != 0:
if(LINE_LIST[0] == '$'): # THIS IS A RULE
if ":" not in LINE_LIST:
raise Exception("ERROR ':' NOT FOUND IN LINE %d IN RULE.TXT" % LINE_ID)
LEFT = []
RIGHT = []
LEFT_FLAG = True
for STR in LINE_LIST[1:]: # DO NOT CARE ABOUT '$'
if STR == ":":
LEFT_FLAG = False
elif LEFT_FLAG:
LEFT.append(STR) # APPEND ON LEFT SIDE
else:
RIGHT.append(STR) # APPEND ON RIGHT SIDE
RULES.append((LEFT, RIGHT)) # ADD A RULE
pass
elif(LINE_LIST[0] == '%'): # THIS IS A COMMENT
pass
LINE_ID += 1
return RULES
def LOAD_PROGRAM(FILE_NAME = "PROGRAM.TXT"): # LOAD PROGRAM FROM FILE
FPIN = open(FILE_NAME, "r")
PROGRAM = FPIN.read().split() # MAKE STR
FPIN.close()
return PROGRAM
def MATCH(OLD_PROGRAM, POS, LEFT): # CHECK IF IT IS MATCH
for OFFSET in range(0, len(LEFT)):
if POS + OFFSET >= len(OLD_PROGRAM): # CAN NOT MATCH
return False
if LEFT[OFFSET][0] != '#' and LEFT[OFFSET] != OLD_PROGRAM[POS + OFFSET]:
return False
return True
def LOAD_VAR(OLD_PROGRAM, POS, LEFT): # LOAD '#' VAR FROM OLD_PROGRAM
MESSAGE = {}
for OFFSET in range(0, len(LEFT)):
if LEFT[OFFSET][0] == '#': # FIND A #VAR
MESSAGE[LEFT[OFFSET]] = OLD_PROGRAM[POS + OFFSET] # SAVE TO DICT
return MESSAGE
def WRITE_PROGRAM(OLD_PROGRAM, POS, LEFT, RIGHT, MESSAGE):
SEGMENT = []
for OFFSET in range(0, len(RIGHT)):
if RIGHT[OFFSET][0] == '#':
SEGMENT.append(MESSAGE[RIGHT[OFFSET]]) # APPEND VAR VALUE
else:
SEGMENT.append(RIGHT[OFFSET]) # APPEND STR
return OLD_PROGRAM[:POS] + SEGMENT + OLD_PROGRAM[POS + len(LEFT):]
def REPLACE(OLD_PROGRAM, RULES): # REPLACE BY RULES
CNT = 0
for RULE in RULES:
LEFT, RIGHT = RULE # SEPERATE INTO TWO PARTS
FLAG = True
while FLAG: # FLAG = True MEANS FIND A MATCH POSITION
FLAG = False
NEW_PROGRAM = []
for POS in range(0, len(OLD_PROGRAM)):
if MATCH(OLD_PROGRAM, POS, LEFT):
FLAG = True
CNT += 1
MESSAGE = LOAD_VAR(OLD_PROGRAM, POS, LEFT)
NEW_PROGRAM = WRITE_PROGRAM(OLD_PROGRAM, POS, LEFT, RIGHT, MESSAGE)
break
if FLAG:
OLD_PROGRAM = NEW_PROGRAM
return OLD_PROGRAM
if __name__ == "__main__":
RULES = LOAD_RULES()
# print(json.dumps(RULES, indent = 4)) # OUTPUT TO CHECK
PROGRAM = LOAD_PROGRAM()
print("PROGRAM = " + " ".join(PROGRAM))
CNT = 1
while True:
TMP_PROGRAM = REPLACE(PROGRAM, RULES) # MAKE AN ITERATION
if TMP_PROGRAM == PROGRAM:
break
else:
PROGRAM = TMP_PROGRAM
print("PROGRAM = " + " ".join(PROGRAM))
CNT += 1
print("PROGRAM = " + " ".join(PROGRAM) + " AFTER %d ITERATION" % CNT)
图灵完备
闲的无聊,证明一下这种替换算法是图灵完备的,因为可以模拟图灵机的运行(其实实质上就是一个图灵机的强化版而已)。在PROGRAM.TXT
中构造一条“纸带:”,最开始存放的是初始的数据:
; Value[1] , Value[2] , ... , Value[i] , ... Value[n] ;
将定位器 PTR \text{PTR} PTR 放在纸带上:
; PTR ( id , Value[1] ) , Value[2] , ... , Value[i] , ... Value[n] ;
其中 i d id id 表示当前图灵机控制部分的 D F A DFA DFA 中所在结点的编号/名称。针对 i d id id 进行对 PTR \text{PTR} PTR 替换的设计即可模拟图灵机的全部功能。