基于Predictive Parsing的ABNF语法分析器(十二)——alternation、concatenation、group和option

今天一鼓作气再写多点东西吧,这个题目差不多接近尾声了。来看看alternation、concatenation、group和option的解析代码:

/*
    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/>.
 */

//		        alternation    =  concatenation
//		                          *(*c-wsp "/" *c-wsp concatenation)
	protected Alternation alternation() throws IOException, MatchException {
		Alternation alternation = new Alternation();
//              每个alternation至少有一个候选项,这个候选项的类型是concatenation(连结项)
		alternation.addConcatenation(concatenation());
//      从第二个候选项开始,每个候选项都是都是以空格(可选)以及“/”引导的,
//      因此,只要遇到空格或者/号,就认为接下来的又是一个候选项
//      当然,如果遇到空格但后面跟的不是/号,又或者如果/号之后跟的不是候选项,
//      那就只能异常了,因为这个算法不能回溯到空格或者/号之前
        while (match(is.peek(), new int[] { 0x20, ';', '/'})) {
//          如遇到空格或者分号,则进入c_wsp()
            while (match(is.peek(), 0x20) || match(is.peek(), ';')) {
				c_wsp();
			}
//          此处必须是/号了,否则异常,没有办法回溯
            assertMatch(is.peek(), '/');
            is.read();
//          /号后面可以跟若干空格或注释
            while (match(is.peek(), 0x20) || match(is.peek(), ';')) {
	        c_wsp();
	    }
//          空格之后的新的候选项,候选项本身是concatenation,所以进入相应的函数。
	    alternation.addConcatenation(concatenation());
	    }
	    return alternation;
	}

//		        concatenation  =  repetition *(1*c-wsp repetition)
	protected Concatenation concatenation() throws IOException, MatchException {
		Concatenation concatenation = new Concatenation();
//              一个concatenation是由至少一个repetition组成的,
//              这些repetition有先后顺序之分,用若干空格隔开
		concatenation.addRepetition(repetition());
//      后面有空格或分号,则认为会接着一个repetition
//      其实这样是不严谨的,因为空格后面其实不必然是repetition,
//      也可能是其他文法单位,但作为一个手工编写的解析器
//      暂时接受它诸多的缺陷吧。
        while (match(is.peek(), 0x20) || match(is.peek(), ';')) {
            while (match(is.peek(), 0x20) || match(is.peek(), ';')) {
				c_wsp();
			}
			concatenation.addRepetition(repetition());
		}
		return concatenation;
	}

//	        group          =  "(" *c-wsp alternation *c-wsp ")"
	protected Group group() throws IOException, MatchException {
//      一个group以左圆括号引导
        assertMatch(is.peek(), '(');
        is.read();
//      括号后面的若干空格
		while (match(is.peek(), new int[] {0x20, ';', 0x0D})) {
			c_wsp();
		}
//      一个group包含一个alternation
		Alternation alternation = alternation();
        while (match(is.peek(), new int[] {0x20, ';', 0x0D})) {
			c_wsp();
		}
//      以右圆括号结束
        assertMatch(is.peek(), ')');
        is.read();
		return new Group(alternation);
	}

//		        option         =  "[" *c-wsp alternation *c-wsp "]"
//      option与group类似,差别在于是方括号而不是圆括号。
	protected Option option() throws IOException, MatchException {
		assertMatch(is.peek(), '[');
        is.read();
        while (match(is.peek(), new int[] {0x20, ';', 0x0D})) {
			c_wsp();
		}
		Alternation alternation = alternation();
        while (match(is.peek(), new int[] {0x20, ';', 0x0D})) {
			c_wsp();
		}
		assertMatch(is.peek(), ']');
        is.read();
		return new Option(alternation);
	}

测试用例方面,其实没啥好说的,在测试alternation的时候,主要是将一个比较复杂的concatenation复制给input,然后测试input + "/" + input形式的候选项的情况。

/*
    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/>.
 */

    //		        alternation    =  concatenation
//		                          *(*c-wsp "/" *c-wsp concatenation)
    @Test
    public void testAlternation() throws Exception {
        Tester<Alternation> tester = new Tester<Alternation>() {
            @Override
            public Alternation test(AbnfParser parser) throws MatchException, IOException {
                return parser.alternation();
            }
        };

        Alternation alternation;
        String input;
        input = "A B C %xff \"abc\" <12-34>";
        alternation = new Alternation();
        alternation.addConcatenation(AbnfParserFactory.newInstance(input).concatenation());
        alternation.addConcatenation(AbnfParserFactory.newInstance(input).concatenation());
        Assertion.assertMatch(input + "/" + input, tester, alternation, 50, 1);

        input = "A";
        alternation = new Alternation();
        alternation.addConcatenation(AbnfParserFactory.newInstance(input).concatenation());
        alternation.addConcatenation(AbnfParserFactory.newInstance(input).concatenation());
        Assertion.assertMatch(input + "/" + input, tester, alternation, 4, 1);

        input = "A";
        alternation = new Alternation();
        alternation.addConcatenation(AbnfParserFactory.newInstance(input).concatenation());
        alternation.addConcatenation(AbnfParserFactory.newInstance(input).concatenation());
//        TODO
//        Does not support currently
        Assertion.assertMatchException(input + " / " + input, tester, 3, 1);

        input = "(A B C D E)";
        alternation = new Alternation();
        alternation.addConcatenation(AbnfParserFactory.newInstance(input).concatenation());
        alternation.addConcatenation(AbnfParserFactory.newInstance(input).concatenation());
        Assertion.assertMatch(input + "/" + input, tester, alternation, 24, 1);

        input = "[A B C D E]";
        alternation = new Alternation();
        alternation.addConcatenation(AbnfParserFactory.newInstance(input).concatenation());
        alternation.addConcatenation(AbnfParserFactory.newInstance(input).concatenation());
        Assertion.assertMatch(input + "/" + input, tester, alternation, 24, 1);

        input = "*(A B C)";
        alternation = new Alternation();
        alternation.addConcatenation(AbnfParserFactory.newInstance(input).concatenation());
        alternation.addConcatenation(AbnfParserFactory.newInstance(input).concatenation());
        Assertion.assertMatch(input + "/" + input, tester, alternation, 18, 1);

        input = "1*2(A B C)";
        alternation = new Alternation();
        alternation.addConcatenation(AbnfParserFactory.newInstance(input).concatenation());
        alternation.addConcatenation(AbnfParserFactory.newInstance(input).concatenation());
        Assertion.assertMatch(input + "/" + input, tester, alternation, 22, 1);

    }

    //		        concatenation  =  repetition *(1*c-wsp repetition)
    @Test
    public void testConcatenation() throws Exception {
        Tester<Concatenation> tester = new Tester<Concatenation>() {
            @Override
            public Concatenation test(AbnfParser parser) throws MatchException, IOException {
                return parser.concatenation();
            }
        };

        String input;
        input = "a b c *a 1*b 1*2c *3d %d88 %x11.22.33 %b00-1111 *(aa bb) *2[a b c] 5*(a/b)";
        Assertion.assertMatch(input, tester, AbnfParserFactory.newInstance(input).concatenation(), 75, 1);
        input = "a b  c  d    e";
        Assertion.assertMatch(input, tester, AbnfParserFactory.newInstance(input).concatenation(), 15, 1);

//        TODO
//        Does not support currently
        input = " a ";
        Assertion.assertMatchException(input, tester, 1, 1);
    }

    //		        group          =  "(" *c-wsp alternation *c-wsp ")"
    @Test
    public void testGroup() throws Exception {
        Tester<Group> tester = new Tester<Group>() {
            @Override
            public Group test(AbnfParser parser) throws MatchException, IOException {
                return parser.group();
            }
        };
        Alternation alternation = AbnfParserFactory.newInstance("A/B").alternation();
        Assertion.assertMatch("(A/B)", tester, new Group(alternation), 6, 1);
//        TODO
//        Does not support this case
        Assertion.assertMatchException("(  A/B  )", tester, 9, 1);
    }

    //		        option         =  "[" *c-wsp alternation *c-wsp "]"
    @Test
    public void testOption() throws Exception {
        Tester<Option> tester = new Tester<Option>() {
            @Override
            public Option test(AbnfParser parser) throws MatchException, IOException {
                return parser.option();
            }
        };
        Alternation alternation = AbnfParserFactory.newInstance("A/B").alternation();
        Assertion.assertMatch("[A/B]", tester, new Option(alternation), 6, 1);
//        TODO
//        Does not support this case
        Assertion.assertMatchException("[  A/B  ]", tester, 9, 1);

    }


你可能感兴趣的:(编译原理,SIP,ABNF,自顶向下,上下文无关文法)