基于Predictive Parsing的ABNF语法分析器(七)——AbnfParser文法解析器之多个选项的情形(如WSP、c-nl和element)

现在来看看对于产生式有多个选项的情形,例如WSP可以是空格SP或者跳格HTAB。对于这种情况,一般是向前看一个字符,根据这个字符来选择产生式。当然,如果两个产生式的起始字符都一样,那么只向前看一个字符就不够了,这种情况下需要向前看2个或者更多。

WSP、c-nl和element的文法解析程序:

 

/*

    This file is one of the component a Context-free Grammar Parser Generator,

    which accept a piece of text as the input, and generates a parser

    for the inputted context-free grammar.

    Copyright (C) 2013, Junbiao Pan (Email: [email protected])



    This program is free software: you can redistribute it and/or modify

    it under the terms of the GNU General Public License as published by

    the Free Software Foundation, either version 3 of the License, or

    any later version.



    This program is distributed in the hope that it will be useful,

    but WITHOUT ANY WARRANTY; without even the implied warranty of

    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

    GNU General Public License for more details.



    You should have received a copy of the GNU General Public License

    along with this program.  If not, see <http://www.gnu.org/licenses/>.

 */



//WSP            =  SP / HTAB

	protected String WSP() throws IOException, MatchException {

//              向前看一个字符

		switch (is.peek()) {

//              如果这个字符是0x20,则是SP(空格),调用SP()方法

		case 0x20: return SP();

//              如果这个字符是0x09,则是HTAB(跳格),调用HTAB()方法

		case 0x09: return HTAB();

//              否则抛出匹配异常MatchException

		default: throw new MatchException("[0x20, 0x09]", is.peek(), is.getPos(), is.getLine());

		}

	}



//		        c-nl           =  comment / CRLF

	protected String c_nl() throws IOException, MatchException {

//              向前看一个字符

		switch (is.peek()) {

//              如果是分号,则是注释,调用comment()方法进行解析

		case ';': return comment();

//              如果是0x0D,则是回车,调用CRLF()方法进行解析

		case 0x0D: return CRLF();

//              否则抛出异常

		default: throw new MatchException("[';', 0x0D]", is.peek(), is.getPos(), is.getLine());

		}

	}

//		        element        =  rulename / group / option /

//		                          char-val / num-val / prose-val

	protected Element element() throws IOException, MatchException {

//      向前看一个字符,如果在0x41~0x5A或0x61~0x7A之间(即大小写英文字母),则是规则名,调用rulename()方法进行解析

        if (match(is.peek(), 0x41, 0x5A) || match(is.peek(), 0x61, 0x7A)) {

            return rulename();

        }



//      否则再检查这个字符

        switch (is.peek()) {

//          如果是左括号,则是group,调用group()

            case '(': return  group();

//          如果是左方括号,则调用option()

            case '[': return option();

//          如果是双引号,则调用char_var()

            case 0x22: return char_val();

//          如果是百分号,则调用num_val()

            case '%': return num_val();

//          如果是左尖括号(小于号),则调用prose_val()

            case '<': return prose_val();

//          否则抛出匹配异常

            default: throw new MatchException("['(', '[', 0x22, '%', '<']", is.peek(), is.getPos(), is.getLine());

        }

	}

相应的单元测试代码也不复杂,如果有不清查的地方麻烦看看前面的帖子:

/*

    This file is one of the component a Context-free Grammar Parser Generator,

    which accept a piece of text as the input, and generates a parser

    for the inputted context-free grammar.

    Copyright (C) 2013, Junbiao Pan (Email: [email protected])



    This program is free software: you can redistribute it and/or modify

    it under the terms of the GNU General Public License as published by

    the Free Software Foundation, either version 3 of the License, or

    any later version.



    This program is distributed in the hope that it will be useful,

    but WITHOUT ANY WARRANTY; without even the implied warranty of

    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

    GNU General Public License for more details.



    You should have received a copy of the GNU General Public License

    along with this program.  If not, see <http://www.gnu.org/licenses/>.

 */



    //WSP            =  SP / HTAB

    @Test

    public void testWSP() throws Exception {

        Tester<String> tester = new Tester<String>() {

            @Override

            public String test(AbnfParser parser) throws MatchException, IOException {

                return parser.WSP();

            }

        };

        Assert.assertEquals(String.valueOf((char)0x09), AbnfParserFactory.newInstance(new char[] {0x09}).WSP());

        Assert.assertEquals(String.valueOf((char)0x20), AbnfParserFactory.newInstance(new char[] {0x20}).WSP());

        Assert.assertEquals(String.valueOf((char)0x09), AbnfParserFactory.newInstance(new char[] {0x09, 0x09}).WSP());

        Assert.assertEquals(String.valueOf((char)0x09), AbnfParserFactory.newInstance(new char[] {0x09, 0x20}).WSP());

        Assert.assertEquals(String.valueOf((char)0x20), AbnfParserFactory.newInstance(new char[] {0x20, 0x20}).WSP());

        Assert.assertEquals(String.valueOf((char)0x20), AbnfParserFactory.newInstance(new char[] {0x20, 0x09}).WSP());

        Assert.assertEquals(String.valueOf((char)0x20), AbnfParserFactory.newInstance(new char[] {0x20, 0x30}).WSP());

        Assertion.assertMatchException("", tester, 1, 1);

        Assertion.assertMatchException("" + (char)0x08, tester, 1, 1);

    }

    //		        c-nl           =  comment / CRLF

    @Test

    public void testC_nl() throws Exception {

        Tester<String> tester = new Tester() {

            public String test(AbnfParser parser) throws MatchException, IOException {

                return parser.c_nl();

            }

        };

        Assertion.assertMatch("" + (char)0x0D + (char)0x0A, tester, 1, 2);

        Assertion.assertMatch(";" + (char)0x0D + (char)0x0A, tester, 1, 2);

        Assertion.assertMatch(";" + (char)0x21 + (char)0x0D + (char)0x0A, tester, 1, 2);

        Assertion.assertMatch(";" + (char)0x20 + (char)0x0D + (char)0x0A, tester, 1, 2);

    }



    //		        element        =  rulename / group / option /

//		                          char-val / num-val / prose-val

    @Test

    public void testElement() throws Exception {

        Tester<Element> tester = new Tester<Element>() {

            @Override

            public Element test(AbnfParser parser) throws MatchException, IOException {

                return parser.element();

            }

        };



        String input;

        input = "aBcD1234";

        RuleName ruleName = AbnfParserFactory.newInstance(input).rulename();

        Assertion.assertMatch(input, tester, ruleName, 9, 1);



        input = "(aBcD1234/%d88)";

        Group group = AbnfParserFactory.newInstance(input).group();

        Assertion.assertMatch(input, tester, group, 16, 1);



        input = "[aBcD1234/%d88]";

        Option option = AbnfParserFactory.newInstance(input).option();

        Assertion.assertMatch(input, tester, option, 16, 1);



        input = "\"#$%^\"";

        CharVal charVal = AbnfParserFactory.newInstance(input).char_val();

        Assertion.assertMatch(input, tester, charVal, 7, 1);



        input = "%b0101.1010.1111";

        Element numVal = AbnfParserFactory.newInstance(input).num_val();

        Assertion.assertMatch(input, tester, numVal, 17, 1);



        input = "<aBcD1234/%d88>";

        ProseVal proseVal = AbnfParserFactory.newInstance(input).prose_val();

        Assertion.assertMatch(input, tester, proseVal, 16, 1);



    }

总之单元测试的目标就是想尽办法“虐”你的代码吧,不过我发现这些代码真的经不起虐。。。


 

你可能感兴趣的:(element)