【问题标题】:small language in pythonpython中的小语言
【发布时间】:2011-09-14 08:54:12
【问题描述】:

我正在编写一种在 python 中甚至可能不被称为语言的东西。我目前有几个运营商:+-*^fac@!!fac 计算阶乘,@ 返回变量的值,!! 设置变量。代码如下。我将如何编写一种方法来用这种简单的语言定义函数?

编辑:我更新了代码!

import sys, shlex, readline, os, string
List, assign, call, add, sub, div, Pow, mul, mod, fac, duf, read,\
kill, clr, STO, RET, fib, curs = {}, "set", "get", "+", "-", "/", "^", "*",\
"%", "fact", "func", "read", "kill", "clear", ">", "@", "fib", "vars"
def fact(num):
    if num == 1: return 1
    else: return num*fact(num-1)
def Simp(op, num2, num1):
    global List
    try: num1, num2 = float(num1), float(num2)
    except:
        try: num1 = float(num1)
        except:
            try: num2 = float(num2)
            except: pass
    if op == mul: return num1*num2
    elif op == div: return num1/num2
    elif op == sub: return num1-num2
    elif op == add: return num1+num2
    elif op == Pow: return num1**num2
    elif op == assign: List[num1] = num2; return "ok"
    elif op == call: return List[num1]
    elif op == fac: return fact(num1)
    elif op == duf: return "%s %s %s"%(duf, num1, num2)
    elif op == mod: return num1%num2
    elif op == kill: del List[num1]; return "ok"
    elif op == clr: os.system("clear")
    elif op == STO: List[num2] = num1; return "ok"
    elif op == RET: return List[num1]
    elif op == curs: return List
    elif op == read: List[num1] = Eval(raw_input("%s "%num1)); return "ok"
def Eval(expr):
    ops = "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s"%(mul, add, sub, div, Pow, assign, call, fac, duf, mod, read, kill, clr, STO, RET, curs)
    stack, expr, ops = [], shlex.split(string.lower(expr)), ops.split()
    for i in expr:
        if i[0] != ';':
            if i not in ops: stack.append(i)
            elif i in ops: stack.append(Simp(i, stack.pop(), stack.pop()))
        else: stack.append("ok")
    return stack[0]
def shell():
    try:
        x = ""
        while x != "quit":
            x = raw_input("star>   ")
            try: l = Eval(x)
            except KeyError: l = "does not exist"
            except: l = "parse error!"
            if l != None: print "   =>",l,"\n"
    except (EOFError, KeyboardInterrupt): print
if len(sys.argv) > 1:
    x = open(sys.argv[1], 'r'); l = x.readlines(); x.close()
    for i in l:
        if i[0] != ";":
            i = ' '.join(i.split())
            x = Eval(i)
            if x != None: print i,"\n   =>",x,"\n"
        else: pass
    shell()
else: shell()

【问题讨论】:

  • 你为什么不使用一个合适的解析模块而不是自己重新发明轮子(以一种非常糟糕的方式)?
  • @tekknolagi pyparsing 是此级别解析的标准模块
  • 有人可以帮忙解决我的实际问题,而不是建议吗?
  • @tekknolagi:每种语言都有一种文化。有一些标准和方法可以写出被认为适合该语言设施的表达式。你的程序看起来......很奇怪。它看起来不像其他 Python 程序。它不遵循大多数其他 Python 程序遵循的惯用语和潜规则。
  • @tekknolagi:我会解决的。但我想向你解释为什么你得到如此冷淡的回应和糟糕的答案。我的诱惑是将您的代码完全重写为惯用的 Python。

标签: python parsing programming-languages operators postfix-notation


【解决方案1】:

您需要将符号序列(数字、数字运算、括号)转换为树形结构,表示您的符号序列表示的计算。这样的事情正是“解析器”的工作你可能想看看像这样的简单解析器http://en.wikipedia.org/wiki/LL_parser 这些代码很简单,您可以用铅笔和纸计算解析表。

【讨论】:

  • 我唯一的问题是弄清楚如何定义函数......我知道这与lambda
  • 不仅如此,您将如何定义参数并映射这些参数?你想要只接受 1 个参数的函数,还是变量参数等等。
  • 像这样x x * square def
  • @Warren 只是接受两个参数之一的函数。
  • 我试着给你写一个,让你写“xx * square def”或“def square %1 %1 *”,但我只进入了一点点,它太毛茸茸了。
【解决方案2】:

看起来您正在尝试在 python 中编写类似 Forth 的内容。

【讨论】:

  • 只是一点 :) 我不确定我在做什么
  • 好吧,我尝试扩展您的示例,并且没有制作解析树,即编写解析器,我被您的简单堆栈操作的限制所困。距离解析器远不止 1 个 lambda。
【解决方案3】:

你的程序很混乱,需要先修复它才能修改它以支持定义函数。我将分几个步骤执行此操作,当我完成它们时,我会将它们添加到答案中。这个答案会很长。

另外,您显然还没有决定您的语言定义应该是什么。你决定让你的语言定义有点像你的实现技术,这有点坏了,会带来很多痛苦。

首先,您的Simp 函数的定义确实被破坏了。它要求所有东西都从堆栈中取出两个值,然后又放回一个值。这已破了。阶乘函数不能以这种方式工作,斐波那契函数也不能,因此您不得不使用从未使用过的“虚拟”参数。此外,诸如分配给全局列表或字典的元素之类的事情没有理由将值推送到堆栈上,因此您只能按下“确定”。这已损坏,需要修复。

这是修复了这个问题的版本。请注意,我已将 Simp 重命名为 builtin_op 以更准确地反映其用途:

import sys, shlex, readline, os, string
List, assign, call, add, sub, div, Pow, mul, mod, fac, duf, read,\
kill, clr, STO, RET, fib, curs = {}, "set", "get", "+", "-", "/", "^", "*",\
"%", "fact", "func", "read", "kill", "clear", ">", "@", "fib", "vars"
def fact(num):
    if num == 1: return 1
    else: return num*fact(num-1)
def builtin_op(op, stack):
    global List
    if op == mul: stack.append(float(stack.pop())*float(stack.pop()))
    elif op == div: stack.append(float(stack.pop())/float(stack.pop()))
    elif op == sub: stack.append(float(stack.pop())-float(stack.pop()))
    elif op == add: stack.append(float(stack.pop())+float(stack.pop()))
    elif op == Pow: stack.append(float(stack.pop())**float(stack.pop()))
    elif op == assign: val = List[stack.pop()] = stack.pop(); stack.append(val)
    elif op == call: stack.append(List[stack.pop()])
    elif op == fac: stack.append(fact(stack.pop()))
    elif op == duf: stack.append("%s %s %s" % (duf, stack.pop(), stack.pop()))
    elif op == mod: stack.append(float(stack.pop())%float(stack.pop()))
    elif op == kill: del List[stack.pop()]
    elif op == clr: os.system("clear")
    elif op == STO: val = List[stack.pop()] = stack.pop(); stack.append(val)
    elif op == RET: stack.append(List[stack.pop()])
    elif op == curs: stack.append(List)
    elif op == read: prompt = stack.pop(); List[prompt] = Eval(raw_input("%s "%prompt)); stack.append(List[prompt])
def Eval(expr):
    ops = "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s"%(mul, add, sub, div, Pow, assign, call, fac, duf, mod, read, kill, clr, STO, RET, curs)
    stack, expr, ops = [], shlex.split(string.lower(expr)), ops.split()
    for i in expr:
        if i[0] != ';':
            if i not in ops: stack.append(i)
            elif i in ops: builtin_op(i, stack)
        else: stack.append("ok")
    return stack[0]
def shell():
    try:
        x = ""
        while x != "quit":
            x = raw_input("star>   ")
            try: l = Eval(x)
            except KeyError: l = "does not exist"
            except: l = "parse error!"
            if l != None: print "   =>",l,"\n"
    except (EOFError, KeyboardInterrupt): print
if len(sys.argv) > 1:
    x = open(sys.argv[1], 'r'); l = x.readlines(); x.close()
    for i in l:
        if i[0] != ";":
            i = ' '.join(i.split())
            x = Eval(i)
            if x != None: print i,"\n   =>",x,"\n"
        else: pass
    shell()
else: shell()

这里还有很多问题没有解决,我不会在以后的任何版本中解决。例如,堆栈上的值可能无法解释为浮点数。这将导致一个异常,并且这个异常可能在另一个值被从堆栈中读取之前被抛出。这意味着如果堆栈上存在错误的“类型”,则堆栈可能在“解析错误”之后处于模棱两可的状态。通常,您希望避免在语言中出现这种情况。

定义函数是一个有趣的问题。在您的语言中,评估是即时的。您没有将评估延迟到以后的机制。但是,您正在使用 shlex 模块进行解析。它有一种说法,一整组字符(包括空格等)是一个实体的一部分。这为我们提供了一种快速简便的方法来实现功能。你可以这样做:

star>   "3 +" add3 func

创建你的函数,并且:

star>   2 add3 get

调用它。我使用了get,因为这是您在程序中分配给call 的内容。

唯一的问题是函数需要访问堆栈的当前状态才能工作。您可以轻松地将函数的字符串返回到Eval,但Eval 每次调用时总是会创建一个全新的堆栈。为了实现功能,这需要修复。所以我在Eval 函数中添加了一个默认的stack 参数。如果此参数保留其默认值,Eval 仍将创建一个新堆栈,就像以前一样。但如果传入一个现有堆栈,Eval 将使用它。

这里是修改后的代码:

import sys, shlex, readline, os, string
List, assign, call, add, sub, div, Pow, mul, mod, fac, duf, read,\
kill, clr, STO, RET, fib, curs = {}, "set", "get", "+", "-", "/", "^", "*",\
"%", "fact", "func", "read", "kill", "clear", ">", "@", "fib", "vars"
funcdict = {}
def fact(num):
    if num == 1: return 1
    else: return num*fact(num-1)
def builtin_op(op, stack):
    global List
    global funcdict
    if op == mul: stack.append(float(stack.pop())*float(stack.pop()))
    elif op == div: stack.append(float(stack.pop())/float(stack.pop()))
    elif op == sub: stack.append(float(stack.pop())-float(stack.pop()))
    elif op == add: stack.append(float(stack.pop())+float(stack.pop()))
    elif op == Pow: stack.append(float(stack.pop())**float(stack.pop()))
    elif op == assign: val = List[stack.pop()] = stack.pop(); stack.append(val)
    elif op == call: Eval(funcdict[stack.pop()], stack)
    elif op == fac: stack.append(fact(stack.pop()))
    elif op == duf: name = stack.pop(); funcdict[name] = stack.pop(); stack.append(name)
    elif op == mod: stack.append(float(stack.pop())%float(stack.pop()))
    elif op == kill: del List[stack.pop()]
    elif op == clr: os.system("clear")
    elif op == STO: val = List[stack.pop()] = stack.pop(); stack.append(val)
    elif op == RET: stack.append(List[stack.pop()])
    elif op == curs: stack.append(List)
    elif op == read: prompt = stack.pop(); List[prompt] = Eval(raw_input("%s "%prompt)); stack.append(List[prompt])
def Eval(expr, stack=None):
    ops = "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s"%(mul, add, sub, div, Pow, assign, call, fac, duf, mod, read, kill, clr, STO, RET, curs)
    if stack is None:
        stack = []
    expr, ops = shlex.split(string.lower(expr)), ops.split()
    for i in expr:
        if i[0] != ';':
            if i not in ops: stack.append(i)
            elif i in ops: builtin_op(i, stack)
        else: stack.append("ok")
    return stack[0]
def shell():
    try:
        x = ""
        while x != "quit":
            x = raw_input("star>   ")
            try: l = Eval(x)
            except KeyError: l = "does not exist"
            except: l = "parse error!"
            if l != None: print "   =>",l,"\n"
    except (EOFError, KeyboardInterrupt): print
if len(sys.argv) > 1:
    x = open(sys.argv[1], 'r'); l = x.readlines(); x.close()
    for i in l:
        if i[0] != ";":
            i = ' '.join(i.split())
            x = Eval(i)
            if x != None: print i,"\n   =>",x,"\n"
        else: pass
    shell()
else: shell()

在基于堆栈的语言中,两个非常有用的内置运算符是dupswapdup 获取顶部堆栈元素并复制它。 swap 交换栈顶的两个元素。

如果您有dup,您可以像这样实现square 函数:

star>   "dup *" square func

这是您实现了dupswap 的程序:

import sys, shlex, readline, os, string
List, assign, call, add, sub, div, Pow, mul, mod, fac, duf, read,\
kill, clr, STO, RET, fib, curs, dup, swap = {}, "set", "get", "+", "-", "/", "^", "*",\
"%", "fact", "func", "read", "kill", "clear", ">", "@", "fib", "vars", "dup", "swap"
funcdict = {}
def fact(num):
    if num == 1: return 1
    else: return num*fact(num-1)
def builtin_op(op, stack):
    global List
    global funcdict
    if op == mul: stack.append(float(stack.pop())*float(stack.pop()))
    elif op == div: stack.append(float(stack.pop())/float(stack.pop()))
    elif op == sub: stack.append(float(stack.pop())-float(stack.pop()))
    elif op == add: stack.append(float(stack.pop())+float(stack.pop()))
    elif op == Pow: stack.append(float(stack.pop())**float(stack.pop()))
    elif op == assign: val = List[stack.pop()] = stack.pop(); stack.append(val)
    elif op == call: Eval(funcdict[stack.pop()], stack)
    elif op == fac: stack.append(fact(stack.pop()))
    elif op == duf: name = stack.pop(); funcdict[name] = stack.pop(); stack.append(name)
    elif op == mod: stack.append(float(stack.pop())%float(stack.pop()))
    elif op == kill: del List[stack.pop()]
    elif op == clr: os.system("clear")
    elif op == STO: val = List[stack.pop()] = stack.pop(); stack.append(val)
    elif op == RET: stack.append(List[stack.pop()])
    elif op == curs: stack.append(List)
    elif op == dup: val = stack.pop(); stack.append(val); stack.append(val)
    elif op == swap: val1 = stack.pop(); val2 = stack.pop(); stack.append(val1); stack.append(val2)
    elif op == read: prompt = stack.pop(); List[prompt] = Eval(raw_input("%s "%prompt)); stack.append(List[prompt])
def Eval(expr, stack=None):
    ops = "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s"%(mul, add, sub, div, Pow, assign, call, fac, duf, mod, read, kill, clr, STO, RET, curs, dup, swap)
    if stack is None:
        stack = []
    expr, ops = shlex.split(string.lower(expr)), ops.split()
    for i in expr:
        if i[0] != ';':
            if i not in ops: stack.append(i)
            elif i in ops: builtin_op(i, stack)
        else: stack.append("ok")
    return stack[0]
def shell():
    try:
        x = ""
        while x != "quit":
            x = raw_input("star>   ")
            try: l = Eval(x)
            except KeyError: l = "does not exist"
            except: l = "parse error!"
            if l != None: print "   =>",l,"\n"
    except (EOFError, KeyboardInterrupt): print
if len(sys.argv) > 1:
    x = open(sys.argv[1], 'r'); l = x.readlines(); x.close()
    for i in l:
        if i[0] != ";":
            i = ' '.join(i.split())
            x = Eval(i)
            if x != None: print i,"\n   =>",x,"\n"
        else: pass
    shell()
else: shell()

最后,这是我的 Python 版本,它比您编写的 Python 更清晰(无论如何我认为):

import shlex, functools, sys, StringIO

def bin_numeric_op(func):
    @functools.wraps(func)
    def execute(self):
        n2, n1 = self._stack.pop(), self._stack.pop()
        n1 = float(n1)
        n2 = float(n2)
        self._stack.append(func(n1, n2))
    return execute

def relational_op(func):
    @functools.wraps(func)
    def execute(self):
        n2, n1 = self._stack.pop(), self._stack.pop()
        self._stack.append(bool(func(n1, n2)))
    return execute

def bin_bool_op(func):
    @functools.wraps(func)
    def execute(self):
        n2, n1 = self._stack.pop(), self._stack.pop()
        n1 = bool(n1)
        n2 = bool(n2)
        self._stack.append(bool(func(n1, n2)))
    return execute

class Interpreter(object):
    def __init__(self):
        self._stack = []
        self._vars = {}
        self._squarestack = []

    def processToken(self, token):
        if token == '[':
            self._squarestack.append(len(self._stack))
        # Currently inside square brackets, don't execute
        elif len(self._squarestack) > 0:
            if token == ']':
                startlist = self._squarestack.pop()
                lst = self._stack[startlist:]
                self._stack[startlist:] = [tuple(lst)]
            else:
                self._stack.append(token)
        # Not current inside list and close square token, something's wrong.
        elif token == ']':
            raise ValueError("Unmatched ']'")
        elif token in self.builtin_ops:
            self.builtin_ops[token](self)
        else:
            self._stack.append(token)
    def get_stack(self):
        return self._stack
    def get_vars(self):
        return self._vars
    @bin_numeric_op
    def add(n1, n2):
        return n1 + n2
    @bin_numeric_op
    def mul(n1, n2):
        return n1 * n2
    @bin_numeric_op
    def div(n1, n2):
        return n1 / n2
    @bin_numeric_op
    def sub(n1, n2):
        return n1 - n2
    @bin_numeric_op
    def mod(n1, n2):
        return n1 % n2
    @bin_numeric_op
    def Pow(n1, n2):
        return n1**n2
    @relational_op
    def less(v1, v2):
        return v1 < v2
    @relational_op
    def lesseq(v1, v2):
        return v1 <= v2
    @relational_op
    def greater(v1, v2):
        return v1 > v2
    @relational_op
    def greatereq(v1, v2):
        return v1 > v2
    @relational_op
    def isequal(v1, v2):
        return v1 == v2
    @relational_op
    def isnotequal(v1, v2):
        return v1 != v2
    @bin_bool_op
    def bool_and(v1, v2):
        return v1 and v2
    @bin_bool_op
    def bool_or(v1, v2):
        return v1 or v2
    def bool_not(self):
        stack = self._stack
        v1 = stack.pop()
        stack.append(not v1)
    def if_func(self):
        stack = self._stack
        pred = stack.pop()
        code = stack.pop()
        if pred:
            self.run(code)
    def ifelse_func(self):
        stack = self._stack
        pred = stack.pop()
        nocode = stack.pop()
        yescode = stack.pop()
        code = yescode if pred else nocode
        self.run(code)
    def store(self):
        stack = self._stack
        value = stack.pop()
        varname = stack.pop()
        self._vars[varname] = value
    def fetch(self):
        stack = self._stack
        varname = stack.pop()
        stack.append(self._vars[varname])
    def remove(self):
        varname = self._stack.pop()
        del self._vars[varname]
    # The default argument is because this is used internally as well.
    def run(self, code=None):
        if code is None:
            code = self._stack.pop()
        for tok in code:
            self.processToken(tok)
    def dup(self):
        self._stack.append(self._stack[-1])
    def swap(self):
        self._stack[-2:] = self._stack[-1:-3:-1]
    def pop(self):
        self._stack.pop()
    def showstack(self):
        print"%r" % (self._stack,)
    def showvars(self):
        print "%r" % (self._vars,)
    builtin_ops = {
        '+': add,
        '*': mul,
        '/': div,
        '-': sub,
        '%': mod,
        '^': Pow,
        '<': less,
        '<=': lesseq,
        '>': greater,
        '>=': greatereq,
        '==': isequal,
        '!=': isnotequal,
        '&&': bool_and,
        '||': bool_or,
        'not': bool_not,
        'if': if_func,
        'ifelse': ifelse_func,
        '!': store,
        '@': fetch,
        'del': remove,
        'call': run,
        'dup': dup,
        'swap': swap,
        'pop': pop,
        'stack': showstack,
        'vars': showvars
        }

def shell(interp):
    try:
        while True:
            x = raw_input("star>   ")
            msg = None
            try:
                interp.run(shlex.split(x))
            except KeyError:
                msg = "does not exist"
            except:
                sys.excepthook(*sys.exc_info())
                msg = "parse error!"
            if msg != None:
                print "   =>",msg,"\n"
            else:
                print "   => %r\n" % (interp.get_stack(),)
    except (EOFError, KeyboardInterrupt):
        print

interp = Interpreter()
if len(sys.argv) > 1:
    lex = shlex.shlex(open(sys.argv[1], 'r'), sys.argv[1])
    tok = shlex.get_token()
    while tok is not None:
        interp.processToken(tok)
        tok = lex.get_token()
shell(interp)

这个新版本支持ififelse 语句。通过 this 和函数调用,可以在语言中实现 fibfact 函数。稍后我将添加您将如何定义这些内容。

下面是定义fib 函数的方法:

star>   fib [ dup [ pop 1 0 + ] swap [ dup 1 - fib @ call swap 2 - fib @ call + ] swap 0 + 2 0 + < ifelse ] !
   => []

star>   15 fib @ call
   => [987.0]

&lt; 之前的0 + 2 0 + 序列是强制比较为数字比较。

还要注意[] 单个字符是如何引用运算符的。它们导致它们之间的所有内容都不会被执行,而是作为单个项目列表存储在堆栈中。这是定义功能的关键。函数是可以使用call 运算符执行的标记序列。它们也可以用于“匿名块”,这是lambda 表达式和标准 Python 块之间的交叉。这些在fib 函数中用于ifelse 语句的两个可能路径。

解析器非常简单。而shlex 作为这种简单语言的词法分析器已经足够强大了。其他项目将从列表中获取单个项目。创建仅包含先前列表的一部分的新列表。 “列出”堆栈上的单个标记。 while 原语的实现。对整数进行操作的数字运算符(在实际的 Forth 中,默认情况下,数字操作对整数进行操作,您需要指定 +. 之类的内容才能获得浮点版本)。以及允许字符串操作的符号标记的一些操作。或许“拆分”和“加入”操作将标记转换为字符的单个标记列表或将列表连接到单个标记中就足够了。

【讨论】:

  • @tekknolagi:我现在已经添加了那部分。正如我所说,我正在分几个步骤来解决这个问题。
  • @tekknolagi:您需要实现一个复制顶部堆栈条目的dup 内置操作。那么square可以定义为"dup *" square func。或者,您可以实现 swap 交换顶部的两个堆栈元素并执行以下操作:"square:x swap &gt; square:x @ *" square func
  • @tekknolagi:更新了我的重写。
  • @tekknolagi:到了,我的回答就结束了。功能齐全的语言不需要复杂的解析器。毕竟是 Forth 的变种。
  • 是的。 Forth 万岁。我尝试了 fib 示例,但对我不起作用。在第 7 场比赛之后我会再玩一些......去温哥华!
【解决方案4】:

正确的答案取决于您担心什么。如果您担心语言复杂性会增加的可扩展解决方案,您可能应该开始学习/使用其中一个解析器模块。如果您担心性能,这可能是一个答案,因为某些模块可能比您可以轻松手动生成的模块得到更好的优化。

另一方面,如果您对学习感兴趣,请查看shunting yard algorithm。您可能可以使用以下操作创建一个函数字典(这将比您的 if 语句更快):

funcs = {}
funcs["+"] = lambda x, y: x + y
funcs["*"] = lambda x, y: y * y

然后在你的 Simp 函数中你可以调用

func = funcs.get[Op]
if func is not None:
    func[Op](num1,num2)
else:
    #whatever you want to do here

【讨论】:

  • 在这种情况下,Shunting Yard 算法是比 LL 语法更好的答案,我认为 ^^
  • @Monkey - OPs 语言是一种后缀语言。它是 Forth 的一个实现。它真的不需要任何注释的解析器。
【解决方案5】:

您可以有一个字典来存储变量并将它们与函数名称相关联。

例如,假设您正在逐行阅读代码:

a = 1
b = 2
c = a + b
function x() 
   d = 4
   e = 5
   f = d + e 
end

当您发现变量( a,b,c )时,您将它们存储在 a 列表中,并且该列表位于范围内,这可能是全局范围:

variables = scopes["global"]
variables.append( "a" ) 

你可以有一个类似的函数数据结构,所以当你发现一个函数时,你把它添加到那个结构中:

fs = functions["global"]
fs.append("x")

而且你还在范围字典中添加了一个新的“范围”

scopes["x"] = [] // the function x doesn't have any var 

当你找到一个新的 var 并且如果你在一个函数定义中,你将这个新的 var 存储在那个“范围”中

variables = scopes["x"]
variables.append("d")

有意义吗?

所有这些都应该在您当前的实现中是可行的。如果你想做更严肃的事情,我强烈建议你买这本书

http://pragprog.com/titles/tpdsl/language-implementation-patterns

尽管它是使用 Java 作为示例编写的,但它会为您提供坚实的语言应用程序基础,并且非常易于阅读。

那么你应该拥有以下工具:

  1. 创建 Lexer(将输入拆分为标记)
  2. 解析(验证令牌是否符合您的语言规则)
  3. 一个 AST(根据您的输入)
  4. 识别程序符号(如变量和函数)
  5. 构建解释器。

希望对你有帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-29
    • 2016-09-25
    相关资源
    最近更新 更多