当前位置: 首页 > 工具软件 > PEG.js > 使用案例 >

使用pegjs解析java代码

贝浩歌
2023-12-01

使用pegjs解析java代码

pegjs是什么

pegjs是peg文法的一种实现,peg文法是一种解析表达式文法,其具体的解析公式和常用的正则表达式很像,需要注意的是peg不允许解析存在二义性。

pegjs官网 https://pegjs.org/

pegjs的作用

在正则匹配不能实现或困难时可以选择pegjs来处理解析,如sql语句的解析,在构造dsl时编写自定义规则也非常方便。

pegjs的简单应用

1.这里以一段java代码的解析为例,准备一段需要解析的java代码

class Test {
  @tag(1)
  @label("名字")
  String name;

  @tag(2)
  @label("性别 0-男 1-女")
  Int sex;
}

2.定义根节点,包含了类型、版本和代码块数组,使用*号表示多个

CodeBlock = blocks:IdlBlock* {
    return {
        type: 'javaSchema',
        version: '1.0.0',
        blocks
    }
} 

3.使用_表示空白符,匹配class关键字,使用Identifier这条规则匹配类名并赋值给className后返回,
_ '{' children:Children* '}'解析空白符后两个花括号中间的子节点

IdlBlock =
    _ 'class'
    _ className:Identifier
    _ '{' children:Children* '}'
    _ {
        return {
            className,
            children
        }
    }
    
    
_ "whitespace" = [ \t\r\n]*

Identifier = $([a-zA-Z_])+

4.在子节点中解析变量

Children =
    _ variable:Variable';'
    _ {
    	return {
            variable
        }
    }

5.定义变量解析规则

Variable = 
	_ tag:Tag?
    _ label:Label?
    _ type:DataType?
    _ name:Identifier?
    _ {
    	return  {
        	tag,
            label,
            type,
            name
        }
    }

6.解析@tag(1)并返回其中的参数

Tag = '@tag('tagColumn:TagColumn')' {
	return tagColumn
}

TagColumn = $([0-9])*

7.解析@label("名字")并返回参数中的描述信息

Label = '@label("'labelColumn:LabelColumn'")' {
	return labelColumn
}

LabelColumn = $([^\r\n\t\"\)])*

8.解析变量的类型,这里仅定义了代码块中用到的两种类型,也可以扩展更多类型

DataType = 'String' / 'Int'

完整的实例

CodeBlock = blocks:IdlBlock* {
    return {
        type: 'javaSchema',
        version: '1.0.0',
        blocks
    }
} 

IdlBlock =
    _ 'class'
    _ className:Identifier
    _ '{' children:Children* '}'
    _ {
        return {
            className,
            children
        }
    }
    
_ "whitespace" = [ \t\r\n]*

Identifier = $([a-zA-Z_])+

Children =
    _ variable:Variable';'
    _ {
    	return {
            variable
        }
    }

Variable = 
	_ tag:Tag?
    _ label:Label?
    _ type:DataType?
    _ name:Identifier?
    _ {
    	return  {
        	tag,
            label,
            type,
            name
        }
    }
    
    
Tag = '@tag('tagColumn:TagColumn')' {
	return tagColumn
}

TagColumn = $([0-9])*

Label = '@label("'labelColumn:LabelColumn'")' {
	return labelColumn
}

LabelColumn = $([^\r\n\t\"\)])*

DataType = 'String' / 'Int'

解析结果

{
   "type": "javaSchema",
   "version": "1.0.0",
   "blocks": [
      {
         "className": "Test",
         "children": [
            {
               "variable": {
                  "tag": "1",
                  "label": "名字",
                  "type": "String",
                  "name": "name"
               }
            },
            {
               "variable": {
                  "tag": "2",
                  "label": "性别 0-男 1-女",
                  "type": "Int",
                  "name": "sex"
               }
            }
         ]
      }
   ]
}

上面的规则可以直接在pegjs官网的网页版中验证,pegjs也提供了npm包,pegjs的js api比较简单可以参考pegjs官方文档

 类似资料: