2014-11-04 31 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);