在JavaCC中如何测试一个令牌

huangapple go评论71阅读模式
英文:

How to test a token in JavaCC

问题

TOKEN: // 我想让这个令牌只接受偶数
{
<TOKENPARANUMEROSPARES: (["0"-"9"])* ("0"|"2"|"4"|"6"|"8") > {System.out.println("Soy un numero par");}
}

void llamarNumeroPar ():
{}
{
// 我想让我的程序能够从主程序中发出下面显示的消息
< TOKENPARANUMEROSPARES > {System.out.println ("soy un numeroPar&quot);}
}


<details>
<summary>英文:</summary>

I want to create a token that accepts only even numbers, and I need to test it in javacc, I&#39;m just starting to use it and I can&#39;t think of any way to test this token, can anyone help me, thanks!

    TOKEN: //I want this token to only accept even numbers
    {
      &lt;TOKENPARANUMEROSPARES: ([&quot;0&quot;-&quot;9&quot;])* (&quot;0&quot;|&quot;2&quot;|&quot;4&quot;|&quot;6&quot;|&quot;8&quot;) &gt; {System.out.println(&quot;Soy un numero par&quot;);}
    }
    
    void llamarNumeroPar (): 
    {}
    {
    //I want my program to be able to launch a message from my main with the message shown below
      &lt; TOKENPARANUMEROSPARES &gt; {System.out.println (&quot;soy un numeroPar&quot;);}
    }

To print something, what do you recommend? Do I do it from the main or what could I correct in this part of my code?

</details>


# 答案1
**得分**: 2

让我们假设你有以下的 `parser.jj` 文件:

```java
options {
    STATIC = false;
    IGNORE_CASE = false;
}

PARSER_BEGIN(Parser)
package test14;
public class Parser {
}
PARSER_END(Parser)

TOKEN:
{
  <EVEN: ([&quot;0&quot;-&quot;9&quot;])* (&quot;0&quot;|&quot;2&quot;|&quot;4&quot;|&quot;6&quot;|&quot;8&quot;) >
}

void llamarNumeroPar (): 
{}
{
  < EVEN > {System.out.println (&quot;soy un numeroPar&quot;);}
}

现在你可以编写一个主类:

package test14;

import java.io.StringReader;

public class Test14 {
    public static void main(String[] args) {
        Parser parser = new Parser(new StringReader(&quot;1234567&quot;));
        Token token = parser.getNextToken();
        if (token.kind == Parser.EVEN) {
            System.out.println(&quot;Even&quot;);
        } else {
            System.out.println(&quot;Something else&quot;);
        }
    }
}

然后... 惊喜:输出结果是 "Even"。这是因为它已经读取了 "123456",这确实是一个偶数。

现在添加第二个标记 ODD

TOKEN:
{
  <EVEN: ([&quot;0&quot;-&quot;9&quot;])* (&quot;0&quot;|&quot;2&quot;|&quot;4&quot;|&quot;6&quot;|&quot;8&quot;) >
|  <ODD: ([&quot;0&quot;-&quot;9&quot;])* (&quot;1&quot;|&quot;3&quot;|&quot;5&quot;|&quot;7&quot;|&quot;9&quot;) >
}

并且修改主类如下:

if (token.kind == Parser.EVEN) {
    System.out.println(&quot;Even: &quot; + token.image);
} else if (token.kind == Parser.ODD) {
    System.println(&quot;Odd: &quot; + token.image);
} else {
    System.out.println(&quot;Something else: &quot; + token.image);
}

这次,输出结果是预期的:

Odd: 1234567

考虑定义一个标记 NUMBER 并在 Java 代码中处理它的奇偶性。

英文:

Let's say you have the following parser.jj file:

options {
    STATIC = false;
    IGNORE_CASE = false;
}

PARSER_BEGIN(Parser)
package test14;
public class Parser {
}
PARSER_END(Parser)

TOKEN:
{
  &lt;EVEN: ([&quot;0&quot;-&quot;9&quot;])* (&quot;0&quot;|&quot;2&quot;|&quot;4&quot;|&quot;6&quot;|&quot;8&quot;) &gt;
}

void llamarNumeroPar (): 
{}
{
  &lt; EVEN &gt; {System.out.println (&quot;soy un numeroPar&quot;);}
}

You can now write a main class:

package test14;

import java.io.StringReader;

public class Test14 {
    public static void main(String[] args) {
        Parser parser = new Parser(new StringReader(&quot;1234567&quot;));
        Token token = parser.getNextToken();
        if (token.kind == Parser.EVEN) {
            System.out.println(&quot;Even&quot;);
        } else {
            System.out.println(&quot;Something else&quot;);
        }
    }
}

And... surprise: the output is "Even". This is because it has read "123456" which is indeed an even number.

Now add a second token ODD:

TOKEN:
{
  &lt;EVEN: ([&quot;0&quot;-&quot;9&quot;])* (&quot;0&quot;|&quot;2&quot;|&quot;4&quot;|&quot;6&quot;|&quot;8&quot;) &gt;
|  &lt;ODD: ([&quot;0&quot;-&quot;9&quot;])* (&quot;1&quot;|&quot;3&quot;|&quot;5&quot;|&quot;7&quot;|&quot;9&quot;) &gt;
}

And modify the main class as follows:

    if (token.kind == Parser.EVEN) {
        System.out.println(&quot;Even: &quot; + token.image);
    } else if (token.kind == Parser.ODD) {
        System.out.println(&quot;Odd: &quot; + token.image);
    } else {
        System.out.println(&quot;Something else: &quot; + token.image);
    }

This time, the output is as expected:

Odd: 1234567

Consider defining a token NUMBER and dealing with its parity in the Java code.

答案2

得分: 2

以下是翻译好的部分:

"Maurice's answer is excellent. I'm going to come at it from a slightly different angle by answering a slightly broader question.
我认为莫里斯的回答很出色。我将从略微不同的角度回答一个略微广泛的问题。

I don't think it makes a lot of sense to test one token definition at a time. This is because the tricky part of writing token managers is usually not the individual regular expressions, but rather the interactions between them, especially when there are multiple states. So the broader question is how to test a token manager as a whole.
我不认为逐个测试令牌定义有多大意义。这是因为编写令牌管理器的棘手部分通常不是单个正则表达式,而是它们之间的相互作用,特别是当存在多个状态时。因此,更广泛的问题是如何测试整个令牌管理器。

I think something like the following could be quite useful.
我认为类似以下内容可能非常有用。

import your.favourite.test.framework ;
导入您喜欢的测试框架;

class TokenTests implements XYZConstants {
TokenTests类,实现XYZConstants接口:

private final int TME = -99 ; // -99 because this should not be already in use as a token kind.
私有常量TME等于-99;-99是因为不应该已经用作令牌种类。

private void doOneTokenTest( String input, int[] expectation ) {
执行一个令牌测试的私有方法,传入输入字符串和期望的令牌数组;

XYZ parser = new XYZ(new StringReader(input));
创建XYZ解析器并传入输入字符串;

for( int k = 0 ; k < expectation.length; ++k ) {
循环遍历期望的令牌数组;

int state = parser.token_source.curLexState ;
获取解析器的当前状态;

try {
尝试执行以下操作:

Token token = parser.getNextToken();
获取下一个令牌;

checkThat( expectation[k] != TME,
检查期望值是否不等于TME;

"Expected a TokenMgrErr, but got a" +
"Expected a TokenMgrErr, but got a" +

tokenImage[ token.kind ] + " at token " +
tokenImage[token.kind]在令牌处的字符串表示 + " at token " +

k + " of input <<" + input + ">>" +
k在输入中的位置 + " of input <<" + input + ">>" +

" state is " + state ) ;
" state is " + state ) ;

checkThat( token.kind == expectation[k],
检查令牌的种类是否等于期望的种类;

"Expected a " +
"Expected a " +

tokenImage[ expectation[k] ] +
tokenImage[期望的种类] +

" but got a " +
" but got a " +

tokenImage[ token.kind ] + " at token " +
tokenImage[令牌的种类] + " at token " +

k + " of input <<" + input + ">>" +
k在输入中的位置 + " of input <<" + input + ">>" +

" state is " + state ) ;
" state is " + state ) ;

} catch( TokenMgrErr e ) {
捕获TokenMgrErr异常,执行以下操作:

checkThat( expectation[k] == TME,
检查期望值是否等于TME;

"Expected a " +
"Expected a " +

tokenImage[ expectation[k] ] +
tokenImage[期望的种类] +

" but got a TokenMgrErr at token " +
" but got a TokenMgrErr at token " +

k + " of input <<" + input + ">>" +
k在输入中的位置 + " of input <<" + input + ">>" +

" state is " + state ) ; } } }
" state is " + state ) ; } } }

So now you can create and run a bunch of tests
现在,您可以创建并运行一系列测试:

@Test
@Test注解,表示下面是一个测试方法;

public void testTokenMatching() {
public void testTokenMatching()方法:

record Pair( String input, int[] expectation ) ;
定义一个记录类型Pair,包含输入字符串和期望的令牌数组;

Pair[] tests = {
Pair[] tests数组,包含多个测试:

new Pair( "1234", int[]{ EVEN, EOF } ),
new Pair( "1233", int[]{ ODD, EOF } ),
new Pair( "". int[] { EOF },
new Pair( "123.3", int[]{ ODD, TME } }
new Pair( "1234", int[]{ EVEN, EOF } ),
new Pair( "1233", int[]{ ODD, EOF } ),
new Pair( "". int[] { EOF },
new Pair( "123.3", int[]{ ODD, TME } }

for( Pair t : tests ) {
遍历测试数组,执行以下操作:

doOneTokenTest( t.input(), t.expectation() ) ; } }
doOneTokenTest方法,传入输入和期望的令牌数组;

这部分已经完成了对代码的翻译。

英文:

Maurice's answer is excellent. I'm going to come at it from a slightly different angle by answering a slightly broader question.

I don't think it makes a lot of sense to test one token definition at a time. This is because the tricky part of writing token managers is usually not the individual regular expressions, but rather the interactions between them, especially when there are multiple states. So the broader question is how to test a token manager as a whole.

I think something like the following could be quite useful.

import your.favourite.test.framework ;

class TokenTests implements XYZConstants {

    private final int TME = -99 ; // -99 because this should not be already in use as a token kind.

    private void doOneTokenTest( String input, int[] expectation ) {
        XYZ parser = new XYZ(new StringReader(input));
        for( int k = 0 ; k &lt; expectation.length; ++k ) {
            int state = parser.token_source.curLexState ;
            try {
                Token token = parser.getNextToken();
                checkThat( expectation[k] != TME,
                       &quot;Expected a TokenMgrErr, but got a&quot; +
                       tokenImage[ token.kind ] + &quot; at token &quot; +
                       k + &quot; of input &lt;&lt;&quot; + input + &quot;&gt;&gt;&quot; +
                       &quot; state is &quot; + state ) ;
                checkThat( token.kind == expectation[k],
                       &quot;Expected a &quot; +
                       tokenImage[ expectation[k] ] +
                       &quot; but got a &quot; +
                       tokenImage[ token.kind ] + &quot; at token &quot; +
                       k + &quot; of input &lt;&lt;&quot; + input + &quot;&gt;&gt;&quot; +
                       &quot; state is &quot; + state ) ;
            } catch( TokenMgrErr e ) {
                checkThat( expectation[k] == TME,
                       &quot;Expected a &quot; +
                       tokenImage[ expectation[k] ] +
                       &quot; but got a TokenMgrErr at token &quot; +
                       k + &quot; of input &lt;&lt;&quot; + input + &quot;&gt;&gt;&quot; +
                       &quot; state is &quot; + state ) ; } } }

So now you can create and run a bunch of tests

    @Test
    public void testTokenMatching() {
        record Pair( String input, int[] expectation ) ;
        Pair[] tests = {
            new Pair( &quot;1234&quot;, int[]{ EVEN, EOF } ),
            new Pair( &quot;1233&quot;, int[]{ ODD, EOF } ),
            new Pair( &quot;&quot;. int[] { EOF },
            new Pair( &quot;123.3&quot;, int[]{ ODD, TME } } ;
        for( Pair t : tests ) {
            doOneTokenTest( t.input(), t.expectation() ) ; } }

huangapple
  • 本文由 发表于 2023年3月7日 13:35:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/75658361.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定