最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【记录】让antlr的预处理,支持无参数的宏替换

ANTLR crifan 2357浏览 0评论

【背景】

之前已经实现了,antlr的预处理,支持宏替换。

但是现在遇到了问题,对于没有参数的宏的识别和替换,都不支持。

 

【折腾过程】

1.修改相关的代码:

DIRECTIVE
@init{
    List args = new ArrayList();
    boolean condition = true;
    
    String arg0Text = "";
    String arg1Text = "";
    String definedContent = "";
    String defineId = "";
}
@after{
//SETTEXT(GETTEXT()->substring(GETTEXT(),1,GETTEXT()->len-1))
//String processedTokenStr = GETTEXT();
//String processedTokenStr = state.text;
//String processedTokenStr = getText();
//String processedTokenStr = this.getText();
//System.out.println("after process, whole token string is" + processedTokenStr);

}
:	('#define' WS* defineMacro=RAW_IDENTIFIER
    {
        args.add(""); // first element will hold the macro text
    }
        (
            ( '(' // get arguments if you find them (no spaces before left paren)
                (WS)? defineArg0=RAW_IDENTIFIER (WS)? {arg0Text = defineArg0.getText(); args.add(arg0Text);}
                ( ',' (WS)? defineArg1=RAW_IDENTIFIER (WS)? {arg1Text = defineArg1.getText(); args.add(arg1Text);} )*
              ')'
            | ' '|'\t'|'\f'
            )
            ( options{greedy=true;}: ' '|'\t'|'\f' )*
            // store the text verbatim - tokenize when called
            macroText=MACRO_TEXT 
            {
                definedContent = macroText.getText();
                definedContent = definedContent.replace("\\", ""); // remove mutile line define last's '\'
                args.set(0, definedContent);
            }
        )? '\r'? '\n'
    {
        defineId = defineMacro.getText();
        globalDefineMap.put(defineId, args );
        skip();
        
        //process the define content, to check whether it contain the previous define
        //if yes, then process it

        // // save current lexer's state
        // SaveStruct ss = new SaveStruct(input);
        // includes.push(ss);
        // // switch on new input stream
        // setCharStream(new ANTLRStringStream(definedContent));
        // reset();
        
        // isReplacingDefineContent = true;
    }
    )
    /*
    {
        //process the define content, to check whether it contain the previous define
        //if yes, then process it

        // save current lexer's state
        SaveStruct ss = new SaveStruct(input);
        includes.push(ss);
        // switch on new input stream
        setCharStream(new ANTLRStringStream(definedContent));
        reset();
        
        //after replacement
        //update the define map -> replace to the replaced text
        String processedDefineContent = macroText.getText();
        args.set(0, processedDefineContent);
        globalDefineMap.put(defineId, args );
        skip();
    }
    */;

为:

DIRECTIVE
@init{
    List args = new ArrayList();
    boolean condition = true;
    
    String arg0Text = "";
    String arg1Text = "";
    String definedContent = "";
    String defineId = "";
}
@after{
//SETTEXT(GETTEXT()->substring(GETTEXT(),1,GETTEXT()->len-1))
//String processedTokenStr = GETTEXT();
//String processedTokenStr = state.text;
//String processedTokenStr = getText();
//String processedTokenStr = this.getText();
//System.out.println("after process, whole token string is" + processedTokenStr);

}
:	('#define' WS* defineMacro=RAW_IDENTIFIER
    {
        args.add(""); // first element will hold the macro text
    }
        (
            ( '(' // get arguments if you find them (no spaces before left paren)
                (WS)? (defineArg0=RAW_IDENTIFIER (WS)? {arg0Text = defineArg0.getText(); args.add(arg0Text);})?
                ( ',' (WS)? defineArg1=RAW_IDENTIFIER (WS)? {arg1Text = defineArg1.getText(); args.add(arg1Text);} )*
              ')'
            | ' '|'\t'|'\f'
            )
            ( options{greedy=true;}: ' '|'\t'|'\f' )*
            // store the text verbatim - tokenize when called
            macroText=MACRO_TEXT 
            {
                definedContent = macroText.getText();
                definedContent = definedContent.replace("\\", ""); // remove mutile line define last's '\'
                args.set(0, definedContent);
            }
        )? '\r'? '\n'
    {
        defineId = defineMacro.getText();
        globalDefineMap.put(defineId, args );
        skip();
        
        //process the define content, to check whether it contain the previous define
        //if yes, then process it

        // // save current lexer's state
        // SaveStruct ss = new SaveStruct(input);
        // includes.push(ss);
        // // switch on new input stream
        // setCharStream(new ANTLRStringStream(definedContent));
        // reset();
        
        // isReplacingDefineContent = true;
    }
    )
    /*
    {
        //process the define content, to check whether it contain the previous define
        //if yes, then process it

        // save current lexer's state
        SaveStruct ss = new SaveStruct(input);
        includes.push(ss);
        // switch on new input stream
        setCharStream(new ANTLRStringStream(definedContent));
        reset();
        
        //after replacement
        //update the define map -> replace to the replaced text
        String processedDefineContent = macroText.getText();
        args.set(0, processedDefineContent);
        globalDefineMap.put(defineId, args );
        skip();
    }
    */;

就可以识别

#define xxx() yyy

的定义了。

2.后来经过折腾,把:

IDENTIFIER
@init{
    List define = new ArrayList();
    List foundArgs = new ArrayList();
    
    String callArg0Text = "";
    String callArg1Text = "";
}
@after{
//String curCallParaText = getText();
//	if(foundArgs.size() == 0)
//	{
//		//remove () if no para
//		setText("");
//	}
} :
    identifier=RAW_IDENTIFIER
    {
        String IdText = (String)identifier.getText();
    
        // see if this is a macro argument
        define = (List)globalDefineArgsMap.get(IdText);
        while(define != null)
        {
            //if define not null, then find recursively to get para's real value
            String firstParaValue = (String)define.get(0);
            if(globalDefineArgsMap.containsKey(firstParaValue))
            {
                define = (List)globalDefineArgsMap.get(firstParaValue);	
            }
            else
            {
                break;
            }
        }
        
        if (define==null) {
            // see if this is a macro call
            define = (List)globalDefineMap.get(IdText);
            
            //System.out.println("normal define call=" + IdText);
        }
        else
        {
        	//is define args replacement
        	isReplacingDefineContent = true;

        	//System.out.println("normal define args call=" + (String)define.get(0));
        }
    }
    ( {(define!=null) && (define.size()>=1)}?=> (WS|COMMENT)?
        // take in arguments if macro call requires them
        '('
        callArg0=EXPR
        {
            callArg0Text = callArg0.getText(); 
            foundArgs.add(callArg0Text);
        }
        ( COMMA callArg1=EXPR 
        {
            callArg1Text = callArg1.getText();
            foundArgs.add(callArg1Text);
        }
        )*
        { foundArgs.size()==define.size()-1 }? // better have right amount
        ')'
    | {!((define!=null) && (define.size()>1))}?=>
    )
{
if (define!=null) {
    String defineText = (String)define.get(0);

    if (define.size()==1) {
        //only have one value in list -> the defineText is the define para content -> just need replace directly
        setText(defineText);
    } else {
        //add new dict pair: (para, call value)
        for (int i=0;i<foundArgs.size();++i) {
            // treat macro arguments similar to local defines
            List arg = new ArrayList();
            arg.add((String)foundArgs.get(i));
            globalDefineArgsMap.put( (String)define.get(1+i), arg );
        }

        // save current lexer's state
        SaveStruct ss = new SaveStruct(input);
        includes.push(ss);

        // switch on new input stream
        setCharStream(new ANTLRStringStream(defineText));
        reset();
    }
}
};

改为:

IDENTIFIER
@init{
    List define = new ArrayList();
    List foundArgs = new ArrayList();
    
    String callArg0Text = "";
    String callArg1Text = "";
}
@after{
//String curCallParaText = getText();
//	if(foundArgs.size() == 0)
//	{
//		//remove () if no para
//		setText("");
//	}
} :
    identifier=RAW_IDENTIFIER
    {
        String IdText = (String)identifier.getText();
    
        // see if this is a macro argument
        define = (List)globalDefineArgsMap.get(IdText);
        while(define != null)
        {
            //if define not null, then find recursively to get para's real value
            String firstParaValue = (String)define.get(0);
            if(globalDefineArgsMap.containsKey(firstParaValue))
            {
                define = (List)globalDefineArgsMap.get(firstParaValue);	
            }
            else
            {
                break;
            }
        }
        
        if (define==null) {
            // see if this is a macro call
            define = (List)globalDefineMap.get(IdText);
            
            //System.out.println("normal define call=" + IdText);
        }
        else
        {
        	//is define args replacement
        	isReplacingDefineContent = true;

        	//System.out.println("normal define args call=" + (String)define.get(0));
        }
    }
    ( {(define!=null) && (define.size()>=1)}?=> (WS|COMMENT)?
        // take in arguments if macro call requires them
        '('
        callArg0=EXPR
        {
            callArg0Text = callArg0.getText(); 
            //foundArgs.add(callArg0Text);
            //maybe whitespace, so need trim here
            if(!callArg0Text.isEmpty() && !callArg0Text.trim().isEmpty())
            {
            	foundArgs.add(callArg0Text);
            }
        }
        ( COMMA callArg1=EXPR 
        {
            callArg1Text = callArg1.getText();
            //foundArgs.add(callArg1Text);
            //maybe whitespace, so need trim here
            if(!callArg1Text.isEmpty() && !callArg1Text.trim().isEmpty())
            {
            	foundArgs.add(callArg1Text);
            }
        }
        )*
        { foundArgs.size()==define.size()-1 }? // better have right amount
        ')'
    | {!((define!=null) && (define.size()>1))}?=>
    )
{
if (define!=null) {
    String defineText = (String)define.get(0);

    if (define.size()==1) {
        //only have one value in list -> the defineText is the define para content -> just need replace directly
        setText(defineText);
    } else {
        //add new dict pair: (para, call value)
        for (int i=0;i<foundArgs.size();++i) {
            // treat macro arguments similar to local defines
            List arg = new ArrayList();
            arg.add((String)foundArgs.get(i));
            globalDefineArgsMap.put( (String)define.get(1+i), arg );
        }

        // save current lexer's state
        SaveStruct ss = new SaveStruct(input);
        includes.push(ss);

        // switch on new input stream
        setCharStream(new ANTLRStringStream(defineText));
        reset();
    }
}
};

就可以识别无参数的调用了,比如处理:

#define SETVALUE(a) getValue(a+1)

SETVALUE(2);

#define GET_DEV_VAR_VALUE()	_get_dev_var_value((a),(b),METHODID(c))

GET_DEV_VAR_VALUE();

为:

getValue(2+1);


_get_dev_var_value((a),(b),METHODID(c));

3.但是上述存在一个bug,就是当调用无参数耳朵宏的时候,故意添加了多个空格到括号里面时(甚至空格里面有tab),会无法识别。

比如这种:

#define SETVALUE(a) getValue(a+1)

SETVALUE(2);

#define GET_DEV_VAR_VALUE()	_get_dev_var_value((a),(b),METHODID(c))

GET_DEV_VAR_VALUE(   	   );

就不支持。

所以后来又添加两个 WS* ,改为:

IDENTIFIER
@init{
    List define = new ArrayList();
    List foundArgs = new ArrayList();
    
    String callArg0Text = "";
    String callArg1Text = "";
}
@after{
//String curCallParaText = getText();
//	if(foundArgs.size() == 0)
//	{
//		//remove () if no para
//		setText("");
//	}
} :
    identifier=RAW_IDENTIFIER
    {
        String IdText = (String)identifier.getText();
    
        // see if this is a macro argument
        define = (List)globalDefineArgsMap.get(IdText);
        while(define != null)
        {
            //if define not null, then find recursively to get para's real value
            String firstParaValue = (String)define.get(0);
            if(globalDefineArgsMap.containsKey(firstParaValue))
            {
                define = (List)globalDefineArgsMap.get(firstParaValue);	
            }
            else
            {
                break;
            }
        }
        
        if (define==null) {
            // see if this is a macro call
            define = (List)globalDefineMap.get(IdText);
            
            //System.out.println("normal define call=" + IdText);
        }
        else
        {
        	//is define args replacement
        	isReplacingDefineContent = true;

        	//System.out.println("normal define args call=" + (String)define.get(0));
        }
    }
    ( {(define!=null) && (define.size()>=1)}?=> (WS|COMMENT)?
        // take in arguments if macro call requires them
        '('
        WS*
        callArg0=EXPR
        {
            callArg0Text = callArg0.getText(); 
            //foundArgs.add(callArg0Text);
            //maybe whitespace, so need trim here
            if(!callArg0Text.isEmpty() && !callArg0Text.trim().isEmpty())
            {
            	foundArgs.add(callArg0Text);
            }
        }
        ( COMMA callArg1=EXPR 
        {
            callArg1Text = callArg1.getText();
            //foundArgs.add(callArg1Text);
            //maybe whitespace, so need trim here
            if(!callArg1Text.isEmpty() && !callArg1Text.trim().isEmpty())
            {
            	foundArgs.add(callArg1Text);
            }
        }
        )*
        { foundArgs.size()==define.size()-1 }? // better have right amount
        WS*
        ')'
    | {!((define!=null) && (define.size()>1))}?=>
    )
{
if (define!=null) {
    String defineText = (String)define.get(0);

    if (define.size()==1) {
        //only have one value in list -> the defineText is the define para content -> just need replace directly
        setText(defineText);
    } else {
        //add new dict pair: (para, call value)
        for (int i=0;i<foundArgs.size();++i) {
            // treat macro arguments similar to local defines
            List arg = new ArrayList();
            arg.add((String)foundArgs.get(i));
            globalDefineArgsMap.put( (String)define.get(1+i), arg );
        }

        // save current lexer's state
        SaveStruct ss = new SaveStruct(input);
        includes.push(ss);

        // switch on new input stream
        setCharStream(new ANTLRStringStream(defineText));
        reset();
    }
}
};

就支持,无参数的宏调用的时候,括号里面有空格(甚至tab等whitespace)。

 

【总结】

最终,通过如下antlr的.g语法:

grammar preprocess;
//lexer grammar preprocess;

options{
	language=Java;
	output = AST;
}

@lexer::header {
//package com.mm.antlrv3demo;

import java.io.*;
import java.util.*;
}

@parser::header {
//package com.mm.antlrv3demo;
}

@lexer::members {
    //public static TokenStreamSelector selector; // must be assigned externally
    protected static Integer ifState = 1; // -1: no-else false, 0:false, 1: true
    protected static List ifStates = new ArrayList(); // holds nested if conditions
    protected static Map globalDefineMap = new Hashtable(); // holds the globalDefineMap
    protected Map globalDefineArgsMap = new Hashtable(); // holds the args for a macro call
    /*
    public void uponEOF() throws TokenStreamException, CharStreamException {
        try {
            selector.pop(); // return to old lexer/stream
            selector.retry();
        } catch (NoSuchElementException e) {
            // return a real EOF if nothing in stack
        }
    }
    */

    protected static boolean isReplacingDefineContent = false;
	
	class SaveStruct {
      SaveStruct(CharStream input){
        this.input = input;
        this.marker = input.mark();
      }
      public CharStream input;
      public int marker;
     }
     Stack<SaveStruct> includes = new Stack<SaveStruct>();
     
	// class SaveStruct_defines {
      // SaveStruct(CharStream input){
        // this.input = input;
        // this.marker = input.mark();
      // }
      // public CharStream input;
      // public int marker;
     // }
     // Stack<SaveStruct_defines> definesSaveStruct = new Stack<SaveStruct_defines>();
 
    // We should override this method for handling EOF of included file
     public Token nextToken(){
       Token token = super.nextToken();
 
       if(token.getType() == Token.EOF && !includes.empty()){
        // We've got EOF and have non empty stack.
         SaveStruct ss = includes.pop();
         setCharStream(ss.input);
         input.rewind(ss.marker);
         //this should be used instead of super [like below] to handle exits from nested includes
         //it matters, when the 'include' token is the last in previous stream (using super, lexer 'crashes' returning EOF token)
         token = this.nextToken();
       }
 
      // Skip first token after switching on another input.
      // You need to use this rather than super as there may be nested include files
       if(((CommonToken)token).getStartIndex() < 0)
         token = this.nextToken();
 
       return token;
     }
}

COMMENT
    :   ('//' ~('\n'|'\r')* '\r'? '\n') {skip();}
    |   ('/*' ( options {greedy=false;} : . )* '*/') {skip();}
    ;

// and lexer rule
INCLUDE    :    '#include' (WS)? f=STRING 
{
    String name = f.getText();
    name = name.substring(1,name.length()-1);
    try {
        // save current lexer's state
        SaveStruct ss = new SaveStruct(input);
        includes.push(ss);
 
        // switch on new input stream
        setCharStream(new ANTLRFileStream(name));
        reset();

    } catch(Exception fnf) { throw new Error("Cannot open file " + name); }
};
/*
fragment
NON_CR_LF	:	~('\r'|'\n');

fragment
TAB_SPACE
	:	(' ' | '\t');
*/

//DIRECTIVE 	:	('#define' WS* defineMacro=ID WS* defineText=STRING)
//DIRECTIVE 	:	('#define' WS* defineMacro=ID WS* defineText=( NON_CR_LF+ | (NON_CR_LF* (TAB_SPACE+ '\\' '\r'? '\n' NON_CR_LF+)*) ) )


fragment
//MACRO_TEXT :    ( (('\\'){skip();System.out.println("skip line tail back slash");} '\r'? '\n')
//MACRO_TEXT :    ( ('\\'{$channel=HIDDEN;System.out.println("set back slash to hidden");} '\r'? '\n')
//MACRO_TEXT :    ( (('\\'){setText("");System.out.println("set back slash to empty");} '\r'? '\n')
MACRO_TEXT :    (('\\' '\r'? '\n') | (~('\r'|'\n')))*;
//MACRO_TEXT :    (('\\' '\r'? '\n') | (~('\n')))*;
//MACRO_TEXT :    (('\\' '\n') | (~('\n')))*;
//MACRO_TEXT :    (('\\' '\n') | (~('\n' | '\r')))*;
//MACRO_TEXT :    ( ('\\' '\r'? '\n') | (~('\r'|'\n')))* -> ( ('\r'? '\n') | (~('\r'|'\n')))*;
//MACRO_TEXT :    (('\\'{setText("");} '\r'? '\n') | (~('\r'|'\n')))*;
/*
MACRO_TEXT :    ((('\\' '\r'? '\n') | (~('\r'|'\n')))*)
	{
		String origMultiLineStr = getText();
		String newMultiLineStr = origMultiLineStr.replace("\\", "");
		setText(newMultiLineStr);
	};
*/
//MACRO_TEXT :    ( (('\\' '\r'? '\n')=>('\r' '\n')) | (~('\r'|'\n')))*;


DIRECTIVE
@init{
    List args = new ArrayList();
    boolean condition = true;
    
    String arg0Text = "";
    String arg1Text = "";
    String definedContent = "";
    String defineId = "";
}
@after{
//SETTEXT(GETTEXT()->substring(GETTEXT(),1,GETTEXT()->len-1))
//String processedTokenStr = GETTEXT();
//String processedTokenStr = state.text;
//String processedTokenStr = getText();
//String processedTokenStr = this.getText();
//System.out.println("after process, whole token string is" + processedTokenStr);

}
:	('#define' WS* defineMacro=RAW_IDENTIFIER
    {
        args.add(""); // first element will hold the macro text
    }
        (
            ( '(' // get arguments if you find them (no spaces before left paren)
                (WS)? (defineArg0=RAW_IDENTIFIER (WS)? {arg0Text = defineArg0.getText(); args.add(arg0Text);})?
                ( ',' (WS)? defineArg1=RAW_IDENTIFIER (WS)? {arg1Text = defineArg1.getText(); args.add(arg1Text);} )*
              ')'
            | ' '|'\t'|'\f'
            )
            ( options{greedy=true;}: ' '|'\t'|'\f' )*
            // store the text verbatim - tokenize when called
            macroText=MACRO_TEXT 
            {
                definedContent = macroText.getText();
                definedContent = definedContent.replace("\\", ""); // remove mutile line define last's '\'
                args.set(0, definedContent);
            }
        )? '\r'? '\n'
    {
        defineId = defineMacro.getText();
        globalDefineMap.put(defineId, args );
        skip();
        
        //process the define content, to check whether it contain the previous define
        //if yes, then process it

        // // save current lexer's state
        // SaveStruct ss = new SaveStruct(input);
        // includes.push(ss);
        // // switch on new input stream
        // setCharStream(new ANTLRStringStream(definedContent));
        // reset();
        
        // isReplacingDefineContent = true;
    }
    )
    /*
    {
        //process the define content, to check whether it contain the previous define
        //if yes, then process it

        // save current lexer's state
        SaveStruct ss = new SaveStruct(input);
        includes.push(ss);
        // switch on new input stream
        setCharStream(new ANTLRStringStream(definedContent));
        reset();
        
        //after replacement
        //update the define map -> replace to the replaced text
        String processedDefineContent = macroText.getText();
        args.set(0, processedDefineContent);
        globalDefineMap.put(defineId, args );
        skip();
    }
    */;

IDENTIFIER
@init{
    List define = new ArrayList();
    List foundArgs = new ArrayList();
    
    String callArg0Text = "";
    String callArg1Text = "";
}
@after{
//String curCallParaText = getText();
//	if(foundArgs.size() == 0)
//	{
//		//remove () if no para
//		setText("");
//	}
} :
    identifier=RAW_IDENTIFIER
    {
        String IdText = (String)identifier.getText();
    
        // see if this is a macro argument
        define = (List)globalDefineArgsMap.get(IdText);
        while(define != null)
        {
            //if define not null, then find recursively to get para's real value
            String firstParaValue = (String)define.get(0);
            if(globalDefineArgsMap.containsKey(firstParaValue))
            {
                define = (List)globalDefineArgsMap.get(firstParaValue);	
            }
            else
            {
                break;
            }
        }
        
        if (define==null) {
            // see if this is a macro call
            define = (List)globalDefineMap.get(IdText);
            
            //System.out.println("normal define call=" + IdText);
        }
        else
        {
	       	//is define args replacement
	       	isReplacingDefineContent = true;
	
        	//System.out.println("normal define args call=" + (String)define.get(0));
        }
    }
    ( {(define!=null) && (define.size()>=1)}?=> (WS|COMMENT)?
        // take in arguments if macro call requires them
        '('
        WS*
        callArg0=EXPR
        {
            callArg0Text = callArg0.getText(); 
            //foundArgs.add(callArg0Text);
            //maybe whitespace, so need trim here
            if(!callArg0Text.isEmpty() && !callArg0Text.trim().isEmpty())
            {
            	foundArgs.add(callArg0Text);
            }
        }
        ( COMMA callArg1=EXPR 
        {
            callArg1Text = callArg1.getText();
            //foundArgs.add(callArg1Text);
            //maybe whitespace, so need trim here
            if(!callArg1Text.isEmpty() && !callArg1Text.trim().isEmpty())
            {
            	foundArgs.add(callArg1Text);
            }
        }
        )*
        { foundArgs.size()==define.size()-1 }? // better have right amount
        WS*
        ')'
    | {!((define!=null) && (define.size()>1))}?=>
    )
{
if (define!=null) {
    String defineText = (String)define.get(0);

    if (define.size()==1) {
        //only have one value in list -> the defineText is the define para content -> just need replace directly
        setText(defineText);
    } else {
        //add new dict pair: (para, call value)
        for (int i=0;i<foundArgs.size();++i) {
            // treat macro arguments similar to local defines
            List arg = new ArrayList();
            arg.add((String)foundArgs.get(i));
            globalDefineArgsMap.put( (String)define.get(1+i), arg );
        }

        // save current lexer's state
        SaveStruct ss = new SaveStruct(input);
        includes.push(ss);

        // switch on new input stream
        setCharStream(new ANTLRStringStream(defineText));
        reset();
    }
}
};

fragment RAW_IDENTIFIER : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')* ;

NUMBER : ('0'..'9') ('0'..'9'|'a'..'z'|'A'..'Z'|'_')* ; // allow ahpha suffixes on numbers (i.e. L:long)

// group symbols into categories to parse EXPR
LEFT  : '(' | '[' | '{' ;
RIGHT : ')' | ']' | '}' ;
COMMA : ',' ;
OPERATOR : '!' | '#' | '$' | '%' | '&' | '*' | '+' | '-' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '\\' | '^' | '`' | '|' | '~' ;


fragment EXPR // allow just about anything without being ambiguous
    : (WS)? (NUMBER|IDENTIFIER)?
            (
                        ( LEFT EXPR ( COMMA EXPR )* RIGHT
            | STRING
            | OPERATOR // quotes, COMMA, LEFT, and RIGHT not in here
            )
            EXPR
        )?
    ;

//INT :	'0'..'9'+    ;

FLOAT
    :   ('0'..'9')+ '.' ('0'..'9')* EXPONENT?
    |   '.' ('0'..'9')+ EXPONENT?
    |   ('0'..'9')+ EXPONENT
    ;

WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {$channel=HIDDEN;}
    ;

//RestSymbo	:	'{' | '}' | '&' | ';' | ',' | '+' | '-' | ')' | '(' | '~' | '/' | '`' | '$' | '@' | '%' | '^' | '#' | '\\' ;

STRING
    :  '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
    ;

CHAR:  '\'' ( ESC_SEQ | ~('\''|'\\') ) '\''
    ;

fragment
EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;

fragment
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;

fragment
ESC_SEQ
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    |   UNICODE_ESC
    |   OCTAL_ESC
    ;

fragment
OCTAL_ESC
    :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7')
    ;

fragment
UNICODE_ESC
    :   '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
    ;
    
header
	:	include*;
include	:	INCLUDE;//'#include ' '<' ID ('.h' | '.ddl') '>';

可以将:

#define SETVALUE(a) getValue(a+1)

SETVALUE(2);

#define GET_DEV_VAR_VALUE()	_get_dev_var_value((a),(b),METHODID(c))

GET_DEV_VAR_VALUE(   	   );

处理为:

getValue(2+1);


_get_dev_var_value((a),(b),METHODID(c));

了。

转载请注明:在路上 » 【记录】让antlr的预处理,支持无参数的宏替换

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
82 queries in 0.170 seconds, using 22.12MB memory