程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 使用ANTLR進行命令行參數解析

使用ANTLR進行命令行參數解析

編輯:關於.NET

關於命令行參數的解析沒有特定的規則,目前比較流行的有unix風格和微軟風格。其實除了unix風格 的比較一致外,微軟自己提供的命令行參數解析就有很多種風格。在.net平台下的main函數中,僅僅把參 數分解為以空格分割的數組,這對需要加開關,並且有的開關有自己的參數的情況是不夠的,而且為了解 析這些參數需要學習部分詞法分析的知識,這對用處不是很大的命令行參數顯得有些“雞肋”,當然用 Antlr來處理命令行參數更顯得有些雞肋,並且是大才小用,因為Antlr的語法規則比較復雜,學習起來有 一定的難度。但對於已經使用Antlr進行DSL開發的開發人員來說,解決命令行參數解析的問題是舉手之勞 。

我們需要先定義命令行參數的輸入規則,參考.Net framework提供的命令行工具,制定如下的規則:

1、以空格分割參數,與.net命令行參數保持一致。

2、選項(option)或者開關(switch)用/ 或\ 或 - 作為標志。

3、選項可以有參數,使用冒號:分割,選項的參數如果是多個使用逗號(,)或者分號(;)分隔。

4、選項之後是命令行自身的參數。

5、選項名稱以英文字母開頭。

6、選項的參數和命令行自身的參數可以使用英文字母和數字型、下劃線,如果包含雙字節碼或者特殊 字符,需要使用雙引號。

規則制定好以後,開始進入正題:

第一步,需要從Antlr網站(http://www.antlr.org)上下載Antlr類庫及相關的學習資料及工具,工 具中比較重要的是Antlr works。

第二步,使用Antlr works或者文本編輯器編輯詞法和語法規則:

grammar CmdPara;
options{
language=CSharp2;
output=AST;
ASTLabelType=CommonTree;
}
tokens{
Option;
}
cmdLine : String option* para* EOF!;
option
: swt ((':' para)((','|';')para)*)? ->^(Option swt para*);
swt : ('/'|'-'|'\\') ID -> ID;
para : String|INT|ID;
ID : ('a'..'z'|'A'..'Z')(('a'..'z')
|('A'..'Z')
|'0'..'9'
|'&'
|'/'
|'\\'
|'.'
|'_'
)*; //don't support chinese
String : ('"' .+ '"')|('\'' .+ '\'');
INT : ('1'..'9')('0'..'9')*
;
WS
: (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;}
;

第三步:定義命令行參數解析實體類

namespace Rz.CmdLine
{

    //命令行對象
    public class CmdLine {

        //可執行文件的文件名

         public string ExeFile { get; set; }

        private List<Switch> _cmdSwitchs = new List<Switch>();

        //開關對象列表

         public List<Switch> CmdSwitchs
        {
            get { return _cmdSwitchs; }
        }

        private List<string> _parameters = new List<string>();

        //命令行參數

        public List<string> Parameters
        {
            get { return _parameters; }
        }

    }

    //開關實體類

    public class Switch {

        //開關名稱

        public string SwitchName { get; set; }

       //開關參數

        private List<string> _parameters = new List<string>();

        public List<string> Parameters
        {
            get { return _parameters; }
        }
    }
}

第四步:使用Antlr定義語法樹遍歷器

tree grammar CmdWalker;
options{
    language=CSharp2;
    tokenVocab=CmdPara;
        ASTLabelType=CommonTree;
}
@header{
using Rz.CmdLine;
}
@members{

}
cmdLine    returns[CmdLine r = new CmdLine()]
    :    String
    {
        r.ExeFile=$String.Text;
    }
    (option{r.CmdSwitchs.Add($option.r);})*
    (para{r.Parameters.Add($para.r);})*
    ;

option    returns[Switch r = new Switch()]
    :
    ^(Option
    swt{r.SwitchName=$swt.r;}
    (para{r.Parameters.Add($para.r);})*
    )
    ;

swt    returns[string r]
    :    ID{r=$ID.Text;}
    ;

para    returns[string r]
    :
    String{r=$String.Text;}
    |INT{r=$INT.Text;}
    |ID{r=$ID.Text;}
    ;

第 五 步:定義解析命令行的靜態類,把命令行轉變為前面定義的實體類。

    public class CmdEngine
    {

        public static CmdLine Parse(string cmdLine) {

             ANTLRStringStream input = new ANTLRStringStream(cmdLine);

             CmdParaLexer lex = new CmdParaLexer(input);

            CommonTokenStream token = new CommonTokenStream(lex);

            CmdParaParser pars = new CmdParaParser(token);

            CommonTreeNodeStream tree = new CommonTreeNodeStream(pars.cmdLine().Tree);

             CmdWalker walker = new CmdWalker(tree);

            return walker.cmdLine();

        }

    }

第六步:編寫測試程序

static void Main(string[] args)
{

    Console.WriteLine(string.Join(" ",args));

    CmdLine cmd = CmdEngine.Parse(Environment.CommandLine);

    Console.WriteLine (cmd.ExeFile);

    foreach (Switch s in cmd.CmdSwitchs) {
        Console.WriteLine("Switch /{0}:{1}",s.SwitchName,string.Join (",",s.Parameters.ToArray()));
    }

    foreach (string s in cmd.Parameters) {
        Console.WriteLine("Command Parameter [{0}]:{1}",cmd.Parameters.IndexOf (s),s);
    }

    Console.ReadLine();
}

第七步:查看程序運行結果

源代碼稍後會放到google開源庫中,由於codeplex的速度太慢,實在無法忍受,希望有一天微軟在 Internet上跟上google的腳步。

參考:

CodePlex上一個開源參數解析類庫

以-標明選項

短選項,-sHello,其中-是標志位,s是選項,Hello是參數。或者-s Hello,這個差別在於選項與參 數之間使用空格分割。

多個短選項:-x -y -z -w 或者-xyzw 或者-xy -zw

長選項:--long Hello 或者--long=hello

一個開源的Unix風格的參數解析:

http://blog.pumacode.org/2006/07/24/csharp-getopts-mono-getoptions/

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved