1. 程式人生 > >程式語言試驗之Antlr4+JavaScript實現"圈4"

程式語言試驗之Antlr4+JavaScript實現"圈4"

參考: ANTLR4: Making a compiler with the JavaScript runtime

演示效果雖弱, 還是先上圖吧:
2017_12_02_圈4

線上演示: 地址.

原始碼庫: program-in-chinese/quan4

下載到本地後在瀏覽器中開啟"圈4.html"就可以在本地試驗.

以後設計實現好語言後可以直接用靜態網頁作線上程式設計的演示, 覺得還蠻有用.

注: JS程式碼中各種不良操作(比如全域性函式定義). 請勿作為JS學習材料使用. 與前文一樣, 此文的目標不是一個實用的程式語言.

語法非常簡單(圈4.g4), 只為演示之用. 前文程式語言試驗之Antlr4+Java實現"圈2"

有更多格式的解釋:

grammar 圈4;
程式   : 求約數;

求約數    : '求約數' T數 ;

T數 : [0-9]+ ;
T空白     : [ \n\t]+ -> skip;

下面命令生成詞法語法分析器相關JavaScript檔案(圈4.tokens, 圈4Lexer.js, 圈4Lexer.tokens, 圈4Listener.js, 圈4Parser.js):

$ java -cp "antlr-4.7-complete.jar:$CLASSPATH" org.antlr.v4.Tool -Dlanguage=JavaScript 圈4.g4

作為直譯器的"定製監聽器.js":

var antlr4 = require('antlr4/index');
const4Listener = require('./圈4Listener.js').4Listener

定製監聽器 = function () {4Listener.call(this);
  return this;
}

定製監聽器.prototype = Object.create(4Listener.prototype);
定製監聽器.prototype.constructor = 定製監聽器;
/*
無需介面定義: enter程式/exit程式/enter求約數
*/
定製監聽器.prototype.
exit求約數 = function(上下文) { var 原數 = parseInt(上下文.getChild(1).getText()); document.getElementById("輸出").innerHTML = 原數 + "的約數: " + 求約數(原數); }; function 求約數(原數) { var 約數 = []; for (var i = 1; i < 原數 - 1; i++) { if (原數 % i == 0) { 約數.push(i); } } return 約數; } exports.定製監聽器 = 定製監聽器;

讀取檔案輸入, 呼叫附著了定製監聽器的分析器"程式碼分析.js":

const antlr4 = require("antlr4/index")
const4Lexer = require("./圈4Lexer.js")
const4Parser = require("./圈4Parser.js")
const 定製監聽器 = require("./定製監聽器.js").定製監聽器

執行();

// TODO: 需改進-現為全域性, 由於browserify
function 執行() {
  var 程式碼 = document.getElementById('輸入程式碼').value;
  var 輸入流 = new antlr4.InputStream(程式碼)
  var 詞法分析器 = new4Lexer.圈4Lexer(輸入流)
  var= new antlr4.CommonTokenStream(詞法分析器)
  var 語法分析器 = new4Parser.圈4Parser()
  語法分析器.buildParseTrees = true

  antlr4.tree.ParseTreeWalker.DEFAULT.walk(new 定製監聽器(), 語法分析器.程式())
}

window.執行 = 執行;

HTML介面"圈4.html":

<html>
  <head>
    <!-- defer原因: https://stackoverflow.com/a/26077148/1536803 不然需要document.ready判斷 -->
    <script src="圈4.js" defer></script>
  </head>
  <body>
    <textarea id="輸入程式碼">求約數50
    </textarea>
    <button onclick="執行()">執行</button> 
    <span id="輸出"></span>
  </body>
</html>

是的, 上面的"圈4.js"需要另行生成. 安裝Browserify後執行:

$ browserify 程式碼分析.js > 圈4.js