2014-11-04 29 views
1

在我写下我的问题之前,只是提供一些背景信息。我正在用Java编写玩具编程语言,因为我已经对编译器/解释器等感兴趣。我已经掌握了这个小语言的基础知识,它的沿线是:在解释性编程语言中实现函数

ADD 5, 6 -> c 
PRINT c 
# will store 11 into c 

这是非常基本的,但它是一个开始。因为我只有16岁,所以我不能阅读关于技术方面的书籍,他们对我来说非常沉闷/平淡,我喜欢阅读互联网上的文章,或者在HN上发布的小教程(例如用C编写计划) 。总之,我真的很困惑如何在语言实现的功能,e.g

# only integers since that's easier than multiple data types 
FUNC whatever(a, b) -> return a + b 
# used like 
PRINT whatever(5, 6) 

我可以实现的功能将是真正破解-Y,变成面条的一个混乱的烂摊子的唯一途径。我想知道在编程语言中实现函数的“适当”方法。关于该语言的一些信息:我还没有实现AST,因为我还没有学会它,我为这种语言编写了一个词法分析器,分析器非常简单,只是从上到下,从左到右分析(忘记了这个递归下降解析器的技术术语?)。

对不起,如果这是一个坏问题,模糊,类似的东西。之前从未发布任何有关堆栈溢出的内容,而且我已经编写了一些代码来尝试实现函数,但由于它没有太好(这是几天前),所以删除了它,并且我问这个,因为我想有一套完整的实施计划,而且我相信它会起作用。

谢谢!

回答

2

我建议你从Shunting-yard algorithm开始进行表情评估。使用1或2堆栈很容易实现(取决于您是输出RPN符号还是立即执行)。

对于数学表达式(discussion),我使用了shunting-yard算法severallittleinterpreters

对于函数,当然需要定义一个结构来保存所有函数的信息,如变量数量,局部变量名称以及代码代码的一些表示,这些代码可以执行。

如果您使用调用堆栈,则可以将本地参数压入堆栈。然后您需要“编译”可执行表示,以便使用堆栈偏移量而不是变量名称。或者,您可以使用一堆散列表作为名称空间堆栈。然后,您需要从上到下在每个散列表中查找变量,直到找到变量。使用这两种方法之一,局部变量将会掩盖全局变量的名称(这是您想要的)。

使用分流码算法时,您需要对括号进行一些记录。所以,你的榜样

PRINT whatever(5, 6) 

PRINT大概是公认的语句类型的执行下面的表达式,然后打印出结果。所以你会看到这个表达式是几个不同的标记。

whatever ( 5 , 6 ) 

whatever可以被发现是一个函数名,如果它是以前定义的。但是,如果你想允许一等公民的功能,这可能不是一个函数调用,直到你看到的parens。 (也许你只想打印该函数的代码。)

但是,一个标识符跟一个左paren (显然是函数调用的开始。然后,我们需要递归地评估每个以逗号分隔的表达式,并将这些结果安排为函数的参数。使用调用堆栈方法,只需推送两个结果即可。使用名称空间堆栈,定义两个变量并推送散列表。

然后致电函数调用处理函数来评估函数的代码。并将结果用作评估整个表达式的结果,并将其打印出来。

+0

这是完美的,谢谢!是否有任何资源可以向我推荐我可以学习语言如何在堆栈级别上工作的资源? – dean 2014-11-07 12:21:45

+0

这似乎是一个很好的起点:http://en.wikipedia.org/wiki/X86_calling_conventions – 2014-11-07 20:48:52

+0

非常感谢! – dean 2014-11-07 23:14:26

0

该代码试图通过使用自顶向下的递归下降方法来解释一种非常简单的编程语言。它使用split()方法分离令牌。用Python编写。

stmt-list = stmt | stmt stmt-list 

stmt =  id ":=" expr ";" |  print expr ";" 

expr = term {("+"|"-") term} . 

term = factor {("*"|"/") factor} . 

factor =  id  | intnum  | floatnum  | "(" expr ")" . 

import sys 
from sets import Set 
parsed = [] 
words = [] 
token_set = Set(['+', '-', '*', '/', '(', ')']) 
token_map={'+':'SUM','-':'SUM','*':'DIV','/':'DIV','(':'LEFT_PAR', ')':'RIGHT_PAR'} 

def stmt(line): 
    for word in line.split(): 
     if word == 'SUM': 
      expr(line) 
     elif word == 'DIV': 
      term(line) 
     elif word == 'LEFT_PAR': 
      checker = False 
      wordgrp = words(line.split()) 
      for word in wordgrp: 
       if word!='LEFT_PAR' and not checker: 
        break 
       elif word == 'LEFT_PAR' and not checker: 
        checker = True 
       elif checker and word != 'RIGHT_PAR': 
        parsed.append(word) 
       elif checker and word == 'RIGHT_PAR': 
        stmt(parsed)  
     else: 
      break 

def expr(line): 
    for word in line.split(): 
     if (word == '+'): 
      factor(line); 
     elif word == '-': 
      factor(line); 
     else: 
      break 

def term(line): 
    for word in line.split(): 
     if (word == '*'): 
      factor(line); 
     elif word == '/': 
      factor(line); 
     else: 
      break 

def factor(line): 
    syntax_checker = True 
    if (syntax_checker): 
     print(line) 
     syntax_checker = False 
    else: 
     print("Syntax Error"); 

file = open(sys.argv[-1], "r") 
lines = file.readlines() 
for line in lines: 
    stmt(line) 

file.close() 
0

我这知道一个古老的线程,但前一段时间我实现了对语言使用JavaScript(有更多的限制)类似的,代码在https://github.com/guilhermelabigalini/interpreter发表在Github上的一个小解释

但它支持IF/CASE /回路/功能,见下图:

function factorial(n) { 
    if (n == 1) 
    return 1; 

    return n * factorial(n - 1); 
} 

var x = factorial(6);