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

本文探讨了如何通过单元测试策略解析ABNF文法,并提供了具体实现的示例代码,包括针对WSP、c-nl和element三个部分的解析过程。详细解释了每个部分的解析逻辑和相应的单元测试代码,旨在确保解析器正确处理各种输入情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现在来看看对于产生式有多个选项的情形,例如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: panjunbiao@gmail.com)

    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: panjunbiao@gmail.com)

    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);

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

本系列文章索引:基于预测的ABNF文法分析器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值