1. 程式人生 > 其它 >在Linux下建立ANTLR3.4的C語言環境--詳細

在Linux下建立ANTLR3.4的C語言環境--詳細

技術標籤:antlr

在Linux下建立ANTLR3.4C的環境


基於https://www.coder4.com/archives/4016,補充一些細節和我個人的理解

因為最近要做這方面的專案,但一直找不到一個詳細的、直接的教程,所以總結了一下,給大家做個參考

我的開發環境是WSL2–Ubuntu 20.04 LTS

一、編譯安裝 antlr c 庫

建議全程儘量科學上網,不然網速太慢了。。。

wget http://www.antlr3.org/download/C/libantlr3c-3.4.tar.gz
tar
-xzvf ./libantlr3c-3.4.tar.gz cd libantlr3c-3.4 ./configure --enable-64bit make sudo make install

二、下載 antlr 3.4 jar包

注意:必須要用3.4的jar包,我又試了3.5.2,也不行。。。

cd  /usr/local/lib
wget http://www.antlr3.org/download/antlr-3.4-complete.jar

為jar包建立一個永久的環境變數

sudo vim ~/.bashrc

在最後加一行

export CLASSPATH=/usr/local/lib/antlr-3.4-complete.jar:$CLASSPATH

儲存後

source ~/.bashrc

然後用下面的程式碼驗證,需要自己安裝java

java org.antlr.Tool

三、編寫語法檔案(ExprCppTree.g)

cd ~
vim ExprCppTree.g

程式碼直接照搬的

grammar ExprCppTree;

options {
    language = C;
    output = AST;
    ASTLabelType=pANTLR3_BASE_TREE;
}

@header {
    #include <assert.h>
}

// The suffix '^' means make it a root.
// The suffix '!' means ignore it. expr: multExpr ((PLUS^ | MINUS^) multExpr)* ; PLUS: '+'; MINUS: '-'; multExpr : atom (TIMES^ atom)* ; TIMES: '*'; atom: INT | ID | '('! expr ')'! ; stmt: expr NEWLINE -> expr // tree rewrite syntax | ID ASSIGN expr NEWLINE -> ^(ASSIGN ID expr) // tree notation | NEWLINE -> // ignore ; ASSIGN: '='; prog : (stmt {pANTLR3_STRING s = $stmt.tree->toStringTree($stmt.tree); assert(s->chars); printf(" tree \%s\n", s->chars); } )+ ; ID: ('a'..'z'|'A'..'Z')+ ; INT: '~'? '0'..'9'+ ; NEWLINE: '\r'? '\n' ; WS : (' '|'\t')+ {$channel = HIDDEN;};

編譯

java org.antlr.Tool ExprCppTree.g 

看一下檔案,應該有這些
ExprCppTree.g ExprCppTreeLexer.c ExprCppTreeLexer.h ExprCppTreeParser.c ExprCppTreeParser.h ExprCppTree.tokens

四、編寫驅動檔案(main.cpp)

vim main.cpp
#include "ExprCppTreeLexer.h"
#include "ExprCppTreeParser.h"
#include <cassert>
#include <map>
#include <string>
#include <iostream>

using std::map;
using std::string;
using std::cout;

class ExprTreeEvaluator {
    map<string,int> memory;
public:
    int run(pANTLR3_BASE_TREE);
};

pANTLR3_BASE_TREE getChild(pANTLR3_BASE_TREE, unsigned);
const char* getText(pANTLR3_BASE_TREE tree);

int main(int argc, char* argv[])
{
  pANTLR3_INPUT_STREAM input;
  pExprCppTreeLexer lex;
  pANTLR3_COMMON_TOKEN_STREAM tokens;
  pExprCppTreeParser parser;

  assert(argc > 1);
  input = antlr3FileStreamNew((pANTLR3_UINT8)argv[1],ANTLR3_ENC_8BIT);
  lex = ExprCppTreeLexerNew(input);

  tokens = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT,
                                            TOKENSOURCE(lex));
  parser = ExprCppTreeParserNew(tokens);

  ExprCppTreeParser_prog_return r = parser->prog(parser);

  pANTLR3_BASE_TREE tree = r.tree;

  ExprTreeEvaluator eval;
  int rr = eval.run(tree);
  cout << "Evaluator result: " << rr << '\n';

  parser->free(parser);
  tokens->free(tokens);
  lex->free(lex);
  input->close(input);

  return 0;
}

int ExprTreeEvaluator::run(pANTLR3_BASE_TREE tree)
{
    pANTLR3_COMMON_TOKEN tok = tree->getToken(tree);
    if(tok) {
        switch(tok->type) {
        case INT: {
            const char* s = getText(tree);
            if(s[0] == '~') {
                return -atoi(s+1);
            }
            else {
                return atoi(s);
            }
        }
        case ID: {
            string var(getText(tree));
            return memory[var];
        }
        case PLUS:
            return run(getChild(tree,0)) + run(getChild(tree,1));
        case MINUS:
            return run(getChild(tree,0)) - run(getChild(tree,1));
        case TIMES:
            return run(getChild(tree,0)) * run(getChild(tree,1));
        case ASSIGN: {
            string var(getText(getChild(tree,0)));
            int val = run(getChild(tree,1));
            memory[var] = val;
            return val;
        }
        default:
            cout << "Unhandled token: #" << tok->type << '\n';
            return -1;
        }
    }
    else {
        int k = tree->getChildCount(tree);
        int r = 0;
        for(int i = 0; i < k; i++) {
            r = run(getChild(tree, i));
        }
        return r;
    }
}

pANTLR3_BASE_TREE getChild(pANTLR3_BASE_TREE tree, unsigned i)
{
    assert(i < tree->getChildCount(tree));
    return (pANTLR3_BASE_TREE) tree->getChild(tree, i);
}

const char* getText(pANTLR3_BASE_TREE tree)
{
    return (const char*) tree->getText(tree)->chars;
}

五、編譯,測試

需要安裝g++,然後用下面的程式碼編譯,生成的可執行檔案是test

g++ -g -Wall *.cpp *.c /usr/local/lib/libantlr3c.a -o test -I. -I /usr/local/include/

忽略一堆warning。。。

建立測試檔案data

vim data

寫入
1+2*(3+4)
儲存退出

用test分析data

./test ./data

得到輸出結果

tree (+ 1 (* 2 (+ 3 4)))
Evaluator result: 15