Interpreter written in python

Source: Internet
Author: User
Tags pprint setf

It took me one afternoon to complete a simple language interpreter. I will post all the code at the end, but today I am not going to explain every step of the program in detail, it may take some time to look for internships and papers recently. Once I have time, I will explain each part. Here I will only remind readers that the writing process of a program is different from what it shows, in general, my writing process is to first write an interpreter that contains only one instruction, and then gradually add other instructions.Ps:How much I want to see the process of writing a program by masters, not just the result, but as Graham said, "the process of writing is often lengthy," So there are not many books in this regard. I think similar books include clean code, paip, and software.
Tools. It is a pity that only one and a half of the books have been read.


Idea Source

Yesterday, I was bored when I sat in a lab that couldn't access the internet. Then I remembered that when I learned "Computability and computational complexity", I used an original language containing five instructions. The teacher also asked us to use this language to write programs, so I want to write an interpreter to execute this language and use this interpreter as my own Christmas gift.

Original language description

The book says that it is a simple language in FORTRAN, so I gave it a simple name, metafor, indicating meta FORTRAN. Next, let's take a look at its specific description, and paste it with my more detailed description in the code, I name each command (note that the value assignment statement is named SETF because I recently wrote more Common Lisp statements ).

+ Shards +

Instruction description
X = x + 1 variable X value plus 1
The value of X = x-1 is reduced by 1. If the value of X is 0, the result is still 0.
To a if x = 0 if x = 0, convert the command labeled as a; otherwise, execute the next command.
To a is unconditionally transferred TO the command labeled
Y = x assigns the value of x to the variable y, and the value of x remains unchanged.

+ Shards +

1. metafor has five instructions: name instruction descriptioninc: x = x + 1, Increase by 1 the value of the variable x. dec: x = x-1, If the value of x is 0, leave it unchanged; otherwise decrease by 1 the value of x. con_goto: to a if x! = 0, If the value of x is nonzero, perform the instruction with the label A next; otherwise proceed to the next instruction in the list. goto: to a, Perform the instruction with the label A next. setf: y = x, Change the value variable y to the value of variable x.2. Some specification :( 1) Input variables are represented as: x1, x2, x3 ,... (2) Local variables are represented as: z1, z2, z3 ,... (3) Outpu T variable is represented as: ynote: the num 1 is often omitted (I. e ., x stands for x1 and z standsfor z1 ). 3. labeled instructions: Instructions may or may not have labels. when an instruction is labeled, the label is written to its left in square brackets. for example, [B] Z = Z-l4. A smaple program: "Program to compute y = x1 + x2" y = x1 [B] TO A IF x2! = 0 to e [A] x2 = x2-1 y = y + 1 TO B4. For more information, please refer to Computability and computing complexity, by Zhou Changlin and Li zhanshan.

Overall Thinking

Because the language contains a goto statement, I cannot explain the execution of a sentence. I need to read the entire program and convert it into an internal format for execution as a whole. For example, this is a language program that calculates y = x + x2:

    y = x[B] TO A IF x2 != 0    TO E[A] x2 = x2 - 1    y = y + 1    TO B

After it is converted to an internal format, it is:

[['setf', 'y', 'x'], ['labeled_exp', 'B', ['con_goto', 'A', 'x2']], ['goto', 'E'], ['labeled_exp', 'A', ['dec', 'x2']], ['inc', 'y'], ['goto', 'B']]

Run the demo -- get the program from the file
Or the preceding y = x + x2 program. First, I need to assign values to two input parameters (x, x2). If they are not assigned a value, their values are 0 by default. In addition, we can also view the internal representation structure of the program and perform simple debugging (view the values of other environment variables ). The demo result is as follows:

======================================================*Metafor 1.0, Welecome to Metafor shell environment. **Author: Zhu zhaolong(zzljlu@gmail.com)              *======================================================Metafor> 2 35Metafor> 5 611Metafor> code[['setf', 'y', 'x'], ['labeled_exp', 'B', ['con_goto', 'A', 'x2']], ['goto', 'E'], ['labeled_exp', 'A', ['dec', 'x2']], ['inc', 'y'], ['goto', 'B']]>>> ========================================== RESTART ==========================================>>> ======================================================*Metafor 1.0, Welecome to Metafor shell environment. **Author: Zhu zhaolong(zzljlu@gmail.com)              *======================================================Metafor> 234 5239Metafor> debugdebug> x234debug> x20debug> y239debug> exit>>> 

Run the demo-enter the original language program directly from the End User
I wrote a simple repl interaction environment, so that we can easily test simple original language programs. For example, the following shows a program with y = x + 1, for example:

>>> repl()======================================================*Metafor 1.0, Welecome to Metafor shell environment. **Author: Zhu zhaolong(zzljlu@gmail.com)              *======================================================Input your program:x = x + 1y = xinputs> 5=>6Input your program:

All code
Here I post all the python code:

"Metafor: Meta Fortran, is a small language used in" computabilit and Complexity "course in Jilin University. @ Author: Zhu zhaolong (zzljlu@gmail.com) @ Date: 2011.12.133. metafor has five instructions: Name instruction descriptioninc: x = x + 1, increase by 1 the value of the variable X. dec: x = x-1, if the value of X is 0, leave it unchanged; otherwise decrease by 1 the value of X. con_goto: To a I F x! = 0, if the value of X is nonzero, perform the instruction with the label a next; otherwise proceed to the next instruction in the list. goto: To A, perform the instruction with the label a next. SETF: Y = x, change the value variable Y to the value of variable x.2. some specification :( 1) input variables are represented as: x1, x2, X3 ,... (2) local variables are represented as: Z1, Z2, Z3 ,... (3) outpu T variable is represented as: ynote: the NUM 1 is often omitted (I. E ., X stands for X1 and Z standsfor Z1 ). 3. labeled instructions: Instructions may or may not have labels. when an instruction is labeled, the label is written to its left in square brackets. for example, [B] Z = z-l4. A smaple program: "program to compute y = X1 + x2" Y = x1 [B] to a if X2! = 0 to E [a] X2 = x2-1 y = Y + 1 to B4. For more information, please refer to Computability and computing complexity, by Zhou Changlin and Li zhanshan. "###======================================== ================================== import refrom pprint import pprint ###============== ======================= parse ================================== = def parse (Program): return [Read (e) For E in program] def read (s): "" read a metafor insctruction from a string. and change it to internal represt Ation. "Return read_from (tokenize (s) def tokenize (s):" convert a string into alist of tokens. "Return S. split () def read_from (tokens): "read an exp from a sequence of tokens. "If Len (tokens) = 0: Raise syntaxerror (" uncexpected EOF while reading. ") if is_setf (tokens): Return make_setf (tokens [0], tokens [2]) Elif is_inc (tokens): Return make_inc (tokens [0]) Elif is_dec (tokens): Return make_dec (tokens [0]) Elif is_goto (tokens): Return make_goto (tokens [1]) Elif is_con_goto (tokens): Return make_con_goto (tokens [1], tokens [3]) elif is_labeled_exp (tokens): Return make_labeled_exp (get_label (tokens [0]), read_from (tokens [1:]) else: Raise syntaxerror ("unexpected instructions: % s "% "". join (tokens )) #===================================================== ==================== def is_variable (token): If token. startswith ("X ") Or \ token. startswith ("Z") or \ token = "Y": Return true else: Return falsedef get_label (token): "token is like [a1]. we want get A1. "return Token. replace ('[',''). replace (']', '') # SETF def is_setf (tokens): If tokens [1] =" = "and Len (tokens) = 3: if is_variable (tokens [0]) and is_variable (tokens [2]): Return true else: Raise syntaxerror ("unexpected SETF instruction: % s" % "". join (tokens) els E: Return falsedef make_setf (des_var, src_var): return ["SETF", des_var, src_var] # Inc def is_inc (tokens): If Len (tokens) = 5 and tokens [1] = "=" \ and tokens [3] = "+" and tokens [4] = "1 ": if tokens [0] = tokens [2] and is_variable (tokens [0]): Return true else: Raise syntaxerror ("unexpected Inc instruction: % s" % "". join (tokens) else: Return falsedef make_inc (VAR): return ["Inc", VAR] # decd EF is_dec (tokens): If Len (tokens) = 5 and tokens [1] = "=" \ and tokens [3] = "-" And tokens [4] = "1 ": if tokens [0] = tokens [2] and is_variable (tokens [0]): Return true else: Raise syntaxerror ("unexpected dec instruction: % s" % "". join (tokens) else: Return falsedef make_dec (VAR): return ["dec", VAR] # gotodef is_goto (tokens): If Len (tokens) = 2 and tokens [0] = "to": Return true else: Return Falsedef make_goto (lable): return ["Goto", lable] # con_gotodef is_con_goto (tokens): If Len (tokens) = 6 and tokens [0] = "to" \ and tokens [2] = "if" and is_variable (tokens [3]) \ and tokens [4] = "! = "And tokens [5] =" 0 ": Return true else: Return falsedef make_con_goto (lable, VAR): return [" con_goto ", lable, vaR] # labeled expdef is_labeled_exp (tokens): Return tokens [0]. startswith ('[') def make_labeled_exp (Label, exp): return ["labeled_exp", label, exp] ####========================== codeseg ======== ================== def is_label (s): Return S = "labeled_exp" class codeseg: "to store internal Inst Ructions (exps ). n: The number of instructions. exps: the list of instructions. label_2_exps: A dict of {'label': num} pairs. "def _ init _ (self, exps): Self. N = Len (exps) self. exps = [] self. label_2_exp = {} for (I, e) in enumerate (exps): If is_label (E [0]): (_, label, exp) = E self. label_2_exp [label] = I self. exps. append (exp) else: Self. exps. append (e) def get_instruction_num (self, label): "retur N instruction num with the label. "If label in self. label_2_exp.keys (): return self. label_2_exp [label] # if there is no instruction with that label, # Return a instruction num that doesn't exit. else: return self. N def get_instruction (self, PC): return self. exps [PC] ###============================ env ==== ============================= class ENV (): "An enviromnet: A dict of {'var': Val} Paris, VaR's default Val UE is 0. "def _ init _ (self, argS): Self. pairs ={} for (I, V) in enumerate (ARGs): If I = 0: Self. pairs ['X'] = int (v) else: Self. pairs ['X' + STR (I + 1)] = int (v) def get_v (self, VAR): If VaR in self. pairs. keys (): return self. pairs [Var] else: Return 0 def set_v (self, VAR, value): Self. pairs [Var] = value ###============================ mainloop ====== ======================== def mainloop (codeseg, ENV): "PC refers The current instruction. "PC = 0 while Pc <codeseg. n: E = codeseg. get_instruction (PC) if E [0] = 'inc': (_, v) = E Env. set_v (v, Env. get_v (v) + 1) PC + = 1 Elif E [0] = 'dec ': (_, v) = E Env. set_v (v, max (Env. get_v (V)-1, 0) PC + = 1 Elif E [0] = 'setf': (_, x, y) = E Env. set_v (x, Env. get_v (y) PC + = 1 Elif E [0] = 'goto': (_, label) = e pc = codeseg. get_instruction_num (Label) Elif E [0] = "con_go To ": (_, label, VAR) = e val = env. get_v (VAR) If Val! = 0: Pc = codeseg. get_instruction_num (Label) else: PC + = 1 else: Raise syntaxerror ("unexpected instructions: % s" % "". join (E) return Env. get_v ('y ') ###===================================== repl ==================== ============================ def repl (input_prompt = 'inpututs> '): "A prompt-read-eval-print loop. "print_info () While true: program = get_prog_from_shell () If program = []: Return" Return successfully! "Codes = codeseg (PARSE (Program) Inputs = raw_input (input_prompt) ENV = ENV (inputs. split () print ("=>" + STR (mainloop (codes, ENV) def get_prog_from_shell (): program = [] exp = raw_input ("\ n \ ninput your program: \ n") while Exp: program. append (exp) exp = raw_input () return programdef print_info (): print ("============================================ =========================\ N "" * metafor 1.0, welecome to metafor sh Ell environment. * \ n "" * Author: Zhu zhaolong (zzljlu@gmail.com) * \ n "" ======================================== =================================\ N ") ###==================================== run ================ ====================== def run (filepath, prompt = 'metafor> '): "This function can run metafor program from file. "print_info () program = get_prog_from_file (filepath) parsed_prog = parse (Program) Codes = codeseg (parsed_prog) Inputs = raw_ I Nput (prompt) While true: ENV = ENV (inputs. split () print (mainloop (codes, ENV) Inputs = raw_input (prompt) If inputs = "exit": Return "Return successfully! "If inputs =" debug ": While true: Var = raw_input ('debug> ') If Var =" exit ": Return none print (Env. get_v (VAR) If inputs = "code": pprint (parsed_prog) return nonedef get_prog_from_file (filepath): F = open (filepath, "R") program = f. readlines () F. close () return program ###============================== test ======== =====================# y = x + x2test_file_1 = "metafor_test.mf" # Y = 2 * xtest_file_2 = "metafor_test2.mf" If _ name _ = "_ main __": run (test_file_1)


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.