基于Predictive Parsing的ABNF语法分析器(十一)——AbnfParser文法解析器之重复文法(repetition)

今天写的是关于重复文法的解析,ABNF和BNF相比,一个明显的差异就是引入了重复语法,使得我们可以方便的让一个文法元素重复若干次。

例如30"B"表示30个字母B,30*60表示最少30个,最多60个字母B,等等。

先来看看解析部分的代码:

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

//		        repetition     =  [repeat] element
//    DIGIT          =  %x30-39
	protected Repetition repetition() throws IOException, MatchException {
		Repeat repeat = null;
//      若以数字或者星号开头,则进入repeat
        if (match(is.peek(), 0x30, 0x39) || match(is.peek(), '*')) {
			repeat = repeat();
		}
//      element是必须的
		Element element = element();
		return new Repetition(repeat, element);
	}

//		        repeat         =  1*DIGIT / (*DIGIT "*" *DIGIT)
	protected Repeat repeat() throws IOException, MatchException {
		int min = 0, max = 0;
//      如果repeat是以星号开头,则重复的最小次数为0次,即repeat后面的element可以不出现。
        if (match(is.peek(), '*')) {
            is.read();
//          如果星号后面有数字,则重复的最大次数是该数字所表示的次数,否则最大次数没有限制
            if (match(is.peek(), 0x30, 0x39)) {
                while (match(is.peek(), 0x30, 0x39)) {
                    max = max * 10 + Integer.valueOf(String.valueOf((char)is.read()));
                }
            }
            return new Repeat(min, max);
        } else if (match(is.peek(), 0x30, 0x39)) {
//      repeat是以数字开头,其值表示重复的最小次数
			while (match(is.peek(), 0x30, 0x39)) {
				min = min * 10 + Integer.valueOf(String.valueOf((char)is.read()));
			}
//          如果有星号,则表示有范围
            if (match(is.peek(), '*')) {
                is.read();
//              星号后面接着数字,表示重复的最大次数,否则最大次数没有限制
                if (match(is.peek(), 0x30, 0x39)) {
                    while (match(is.peek(), 0x30, 0x39)) {
                        max = max * 10 + Integer.valueOf(String.valueOf((char)is.read()));
                    }
                }
                return new Repeat(min, max);
            } else {
//          没有星号,表示固定的重复次数
                return new Repeat(min, min);
            }
		} else {
            throw new MatchException("['0'-'9', '*']", 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/>.
 */

    //		        repeat         =  1*DIGIT / (*DIGIT "*" *DIGIT)
    @Test
    public void testRepeat() throws Exception {
        Tester<Repeat> tester = new Tester<Repeat>() {
            @Override
            public Repeat test(AbnfParser parser) throws MatchException, IOException {
                return parser.repeat();
            }
        };

        String input;
        Assert.assertEquals(new Repeat(0,0), AbnfParserFactory.newInstance("*").repeat());
        Assert.assertEquals(new Repeat(0,0), AbnfParserFactory.newInstance("**").repeat());
        Assert.assertEquals(new Repeat(0,0), AbnfParserFactory.newInstance("*C").repeat());
        Assert.assertEquals(new Repeat(1,1), AbnfParserFactory.newInstance("1").repeat());
        Assert.assertEquals(new Repeat(1,1), AbnfParserFactory.newInstance("1M").repeat());
        Assert.assertEquals(new Repeat(2,0), AbnfParserFactory.newInstance("2*").repeat());
        Assert.assertEquals(new Repeat(2,0), AbnfParserFactory.newInstance("2*_").repeat());
        Assert.assertEquals(new Repeat(0,3), AbnfParserFactory.newInstance("*3").repeat());
        Assert.assertEquals(new Repeat(0,3), AbnfParserFactory.newInstance("*3").repeat());
        Assert.assertEquals(new Repeat(0,3), AbnfParserFactory.newInstance("*3J").repeat());
        Assert.assertEquals(new Repeat(4,9), AbnfParserFactory.newInstance("4*9").repeat());
        Assert.assertEquals(new Repeat(4,9), AbnfParserFactory.newInstance("4*9#").repeat());
        Assert.assertEquals(new Repeat(5,0), AbnfParserFactory.newInstance("5**").repeat());
        Assert.assertEquals(new Repeat(6, 0), AbnfParserFactory.newInstance("6*B").repeat());
        Assertion.assertMatchException("", tester, 1, 1);
        Assertion.assertMatchException("#", tester, 1, 1);
    }

    //		        element        =  rulename / group / option /
//		                          char-val / num-val / prose-val
    //		        repetition     =  [repeat] element
//    DIGIT          =  %x30-39
    @Test
    public void testRepetition() throws Exception {
        Tester<Repetition> tester = new Tester<Repetition>() {
            @Override
            public Repetition test(AbnfParser parser) throws MatchException, IOException {
                return parser.repetition();
            }
        };
        Assertion.assertMatch(
                "B", tester,
                new Repetition(new RuleName("", "B")),
                2, 1);
        Assertion.assertMatch("1B", tester,
                new Repetition(new Repeat(1, 1), new RuleName("", "B")),
                3, 1);
        Assertion.assertMatch("2*6B", tester,
                new Repetition(new Repeat(2, 6), new RuleName("", "B")),
                5, 1);

        Assertion.assertMatch("3*B", tester,
                new Repetition(new Repeat(3, 0), new RuleName("", "B")),
                4, 1);

        Assertion.assertMatch("*8B", tester,
                new Repetition(new Repeat(0, 8), new RuleName("", "B")),
                4, 1);

        Assertion.assertMatch("*B", tester,
                new Repetition(new Repeat(0, 0), new RuleName("", "B")),
                3, 1);


        Option option = AbnfParserFactory.newInstance("[B]").option();

        Assertion.assertMatch(
                "[B]", tester,
                new Repetition(option),
                4, 1);
        Assertion.assertMatch("1[B]", tester,
                new Repetition(new Repeat(1, 1), option),
                5, 1);
        Assertion.assertMatch("2*6[B]", tester,
                new Repetition(new Repeat(2, 6), option),
                7, 1);

        Assertion.assertMatch("3*[B]", tester,
                new Repetition(new Repeat(3, 0), option),
                6, 1);

        Assertion.assertMatch("*8[B]", tester,
                new Repetition(new Repeat(0, 8), option),
                6, 1);

        Assertion.assertMatch("*[B]", tester,
                new Repetition(new Repeat(0, 0), option),
                5, 1);


        Group group = AbnfParserFactory.newInstance("(B)").group();

        Assertion.assertMatch(
                "(B)", tester,
                new Repetition(group),
                4, 1);
        Assertion.assertMatch("1(B)", tester,
                new Repetition(new Repeat(1, 1), group),
                5, 1);
        Assertion.assertMatch("2*6(B)", tester,
                new Repetition(new Repeat(2, 6), group),
                7, 1);

        Assertion.assertMatch("3*(B)", tester,
                new Repetition(new Repeat(3, 0), group),
                6, 1);

        Assertion.assertMatch("*8(B)", tester,
                new Repetition(new Repeat(0, 8), group),
                6, 1);

        Assertion.assertMatch("*(B)", tester,
                new Repetition(new Repeat(0, 0), group),
                5, 1);


        CharVal charVal = AbnfParserFactory.newInstance("\"ABC\"").char_val();

        Assertion.assertMatch(
                "\"ABC\"", tester,
                new Repetition(charVal),
                6, 1);
        Assertion.assertMatch("1\"ABC\"", tester,
                new Repetition(new Repeat(1, 1), charVal),
                7, 1);
        Assertion.assertMatch("2*6\"ABC\"", tester,
                new Repetition(new Repeat(2, 6), charVal),
                9, 1);

        Assertion.assertMatch("3*\"ABC\"", tester,
                new Repetition(new Repeat(3, 0), charVal),
                8, 1);

        Assertion.assertMatch("*8\"ABC\"", tester,
                new Repetition(new Repeat(0, 8), charVal),
                8, 1);

        Assertion.assertMatch("*\"ABC\"", tester,
                new Repetition(new Repeat(0, 0), charVal),
                7, 1);


        Element numVal = AbnfParserFactory.newInstance("%x00-FF").num_val();

        Assertion.assertMatch(
                "%x00-FF", tester,
                new Repetition(numVal),
                8, 1);
        Assertion.assertMatch("1%x00-FF", tester,
                new Repetition(new Repeat(1, 1), numVal),
                9, 1);
        Assertion.assertMatch("2*6%x00-FF", tester,
                new Repetition(new Repeat(2, 6), numVal),
                11, 1);

        Assertion.assertMatch("3*%x00-FF", tester,
                new Repetition(new Repeat(3, 0), numVal),
                10, 1);

        Assertion.assertMatch("*8%x00-FF", tester,
                new Repetition(new Repeat(0, 8), numVal),
                10, 1);

        Assertion.assertMatch("*%x00-FF", tester,
                new Repetition(new Repeat(0, 0), numVal),
                9, 1);

        ProseVal proseVal = AbnfParserFactory.newInstance("<ABC>").prose_val();

        Assertion.assertMatch(
                "<ABC>", tester,
                new Repetition(proseVal),
                6, 1);

        Assertion.assertMatch("1<ABC>", tester,
                new Repetition(new Repeat(1, 1), proseVal),
                7, 1);

        Assertion.assertMatch("2*6<ABC>", tester,
                new Repetition(new Repeat(2, 6), proseVal),
                9, 1);

        Assertion.assertMatch("3*<ABC>", tester,
                new Repetition(new Repeat(3, 0), proseVal),
                8, 1);

        Assertion.assertMatch("*8<ABC>", tester,
                new Repetition(new Repeat(0, 8), proseVal),
                8, 1);

        Assertion.assertMatch("*<ABC>", tester,
                new Repetition(new Repeat(0, 0), proseVal),
                7, 1);


        Assertion.assertMatchException("**", tester, 2, 1);
        Assertion.assertMatchException("1", tester, 2, 1);
        Assertion.assertMatchException("*1", tester, 3, 1);
        Assertion.assertMatchException("*(", tester, 3, 1);
        Assertion.assertMatchException("*[", tester, 3, 1);
        Assertion.assertMatchException("1*", tester, 3, 1);
        Assertion.assertMatchException(".", tester, 1, 1);

    }



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