在ANTLR中使用语法指导的转换生成中间代码

时间:2018-11-24 06:40:34

标签: csv compiler-construction antlr

所以,这个问题不一定是我遇到的问题,而是缺乏理解。

我有这个ANTLR代码(由解析器和词法分析器组成):

grammar Compiler;

prog
: Class Program '{' field_decls method_decls '}'
;

field_decls returns [String s1]
: field_decls field_decl ';'
{
  $s1 = $field_decl.s2;
}
| field_decls inited_field_decl ';'
|
;

field_decl returns [String s2]
: field_decl ',' Ident
| field_decl ',' Ident '[' num ']'
| Type Ident
{
  System.out.println($Ident.text);
  $s2 = $Ident.text;
}
| Type Ident '[' num ']'
{
  System.out.println($Ident.text+"["+"]");
  $s2 = $Ident.text;
}
;

inited_field_decl
: Type Ident '=' literal
;

method_decls
: method_decls method_decl
|
;

method_decl
: Void Ident '(' params ')' block
| Type Ident '(' params ')' block
;

params
: Type Ident nextParams
|
;

nextParams
: ',' Type Ident nextParams
|
;

block
: '{' var_decls statements '}'
;

var_decls
: var_decls var_decl
|
;

var_decl
: Type Ident ';'
;

statements
: statement statements
|
;

statement
: location eqOp expr ';'
| If '(' expr ')' block
| If '(' expr ')' block Else block
| While '(' expr ')' statement
| Switch expr '{' cases '}'
| Ret ';'
| Ret '(' expr ')' ';'
| Brk ';'
| Cnt ';'
| block
| methodCall ';'
;

cases
: Case literal ':' statements cases
| Case literal ':' statements
;

methodCall
: Ident '(' args ')'
| Callout '(' Str calloutArgs ')'
;

args
: someArgs
|
;

someArgs
: someArgs ',' expr
| expr
;

calloutArgs
: calloutArgs ',' expr
| calloutArgs ',' Str
|
;

expr
: literal
| location
| '(' expr ')'
| SubOp expr
| '!' expr
| expr AddOp expr
| expr MulDiv expr
| expr SubOp expr
| expr RelOp expr
| expr AndOp expr
| expr OrOp expr
| methodCall
;

location
:Ident
| Ident '[' expr ']'
;

num
: DecNum
| HexNum
;

literal
: num
| Char
| BoolLit
;

eqOp
: '='
| AssignOp
;

//-----------------------------------------------------------------------------------------------------------
fragment Delim
: ' '
| '\t'
| '\n'
;

fragment Letter
: [a-zA-Z]
;

fragment Digit
: [0-9]
;

fragment HexDigit
: Digit
| [a-f]
| [A-F]
;

fragment Alpha
: Letter
| '_'
;

fragment AlphaNum
: Alpha
| Digit
;

WhiteSpace
: Delim+ -> skip
;

Char
: '\'' ~('\\') '\''
| '\'\\' . '\''
;

Str
:'"' ((~('\\' | '"')) | ('\\'.))* '"'
;

Class
: 'class'
;

Program
: 'Program'
;

Void
: 'void'
;

If
: 'if'
;

Else
: 'else'
;

While
: 'while'
;

Switch
: 'switch'
;

Case
: 'case'
;

Ret
: 'return'
;

Brk
: 'break'
;

Cnt
: 'continue'
;

Callout
: 'callout'
;

DecNum
: Digit+
;

HexNum
: '0x'HexDigit+
;

BoolLit
: 'true'
| 'false'
;

Type
: 'int'
| 'boolean'
;

Ident
: Alpha AlphaNum*
;

RelOp
: '<='
| '>='
| '<'
| '>'
| '=='
| '!='
;

AssignOp
: '+='
| '-='
;

MulDiv
: '*'
| '/'
| '%'
;

AddOp
: '+'
;

SubOp
: '-'
;

AndOp
: '&&'
;

OrOp
: '||'
;

基本上,我们需要使用语法指导的翻译生成中间代码。据我所知,这意味着我们必须在解析器语法中添加语义规则。我们需要获取生成的输出并将其封装到.csv文件中。

因此,我们有三个文件:symbol.csv,symtable.csv和structions.csv

在symbol.csv中,每一行的格式为:

int id; //serial no. of symbol, unique
int tabid; //id no. of symbol table
string name; //symbol name
enum types {INT, CHAR, BOOL, STR, VOID, LABEL, INVALID} ty; //symbol type
enum scope {GLOBAL, LOCAL, CONST, INVALID} sc; //symbol scope
boolean isArray; //is it an array variable
int arrSize; //array size, if applicable
boolean isInited; //is initialized
union initVal {
    int i;
    boolean b;
} in; //initial value, if applicable

在symtable.csv中,每行的格式为:

int id; //symbol table serial no., unique
int parent; //parent symbol table serial no.

在Instructions.csv中,每行的格式为:

int id; //serial no., unique
int res; //serial no. of result symbol
enum opcode {ADD, SUB, MUL, DIV, NEG, READ, WRITE, ASSIGN, GOTO, LT, GT, LE, GE, EQ, NE, PARAM, CALL, RET, LABEL} opc; //operation type
int op1; //serial no. of first operand symbol
int op2; //serial no. of second operand symbol

作为示例,假设我们输入以下内容:

class Program {
    int x;
    int y, z;
    int w = 0;
    void main (int n) {
        int a;
        a = 0;
        while (a < n) {
            int n;
            n = a + 1;
            a = n;
        }
        callout("printf", "n = %d\n", n);
        return n;
    }
}

symbols.csv应该如下所示:

0, 0, x, INT, GLOBAL, false, 0, false, 0,
1, 0, y, INT, GLOBAL, false, 0, false, 0,
2, 0, z, INT, GLOBAL, false, 0, false, 0,
3, 0, 0, INT, CONST, false, 0, false, 0,
4, 0, w, INT, GLOBAL, false, 0, true, 0,
5, 0, main, LABEL, GLOBAL, false, 0, false, 0,
6, 1, n, INT, LOCAL, false, 0, false, 0,
7, 1, a, INT, LOCAL, false, 0, false, 0,
8, 1, 0, INT, CONST, false, 0, false, 0,
9, 2, n, INT, LOCAL, false, 0, false, 0,
10, 2, 1, INT, CONST, false, 0, false, 0,
11, 1, "printf", STR, CONST, false, 0, false, 0,
12, 1, "n = %d\n", STR, CONST, false, 0, false, 0,
13, 1, 2, INT, CONST, false, 0, false, 0,

symtables.csv应该如下所示:

0, -1,
1, 0,
2, 1,

instructions.csv应该如下所示:

0, 4, ASSIGN, 3, -1, #w = 0
1, 5, LABEL, -1, -1, #main:
2, 7, ASSIGN, 8, -1, #a = 0
3, 5, LT, 7, 6, #if a<n goto 5
4, 8, GE, 7, 6, #iffalse a<n goto 8
5, 9, ADD, 7, 10, #n = a + 1
6, 7, ASSIGN, 9, -1, #a = n
7, 2, GOTO, -1, -1, #goto 3
8, -1, PARAM, 12, -1, #"n = %d\n"
9, -1, PARAM, 6, -1, #n
10, -1, CALL, 11, 13, #callout("printf", "n = %d\n", n);
11, -1, RET, 6, -1, # return n

简而言之,我不确定从哪里开始。我了解必须将语义规则添加到解析器语法中,这样我才能获得如先前所述的输出。此外,我自己进行了一些研究,发现必须在Java中为我的符号以及symtable和symstack创建类。我是ANTLR的新手,如果有ANTLR经验的人可以为我指明正确的方向,我将不胜感激。

在此先感谢您的帮助。

P.S我的词法分析器和解析器基于下面发布的一种类似于C的小语言。

微小的类C语言:

program
:'class Program {'field_decl* method_decl*'}'

field_decl
: type (id | id'['int_literal']') ( ',' id | id'['int_literal']')*';'
| type id '=' literal ';'

method_decl
: (type | 'void') id'('( (type id) ( ','type id)*)? ')'block

block
: '{'var_decl* statement*'}'

var_decl
: type id(','id)* ';'

type
: 'int'
| 'boolean'

statement
: location assign_op expr';'
| method_call';'
| 'if ('expr')' block ('else' block  )?
| 'switch' expr '{'('case' literal ':' statement*)+'}'
| 'while (' expr ')' statement
| 'return' ( expr )? ';'
| 'break ;'
| 'continue ;'
| block

assign_op
: '='
| '+='
| '-='

method_call
: method_name '(' (expr ( ',' expr )*)? ')'
| 'callout (' string_literal ( ',' callout_arg )* ')'

method_name
: id

location
: id
| id '[' expr ']'

expr
: location
| method_call
| literal
| expr bin_op expr
| '-' expr
| '!' expr
| '(' expr ')'

callout_arg
: expr
| string_literal

bin_op
: arith_op
| rel_op
| eq_op
| cond_op

arith_op
: '+'
| '-'
| '*'
| '/'
| '%'

rel_op
: '<'
| '>'
| '<='
| '>='

eq_op
: '=='
| '!='

cond_op
: '&&'
| '||'

literal
: int_literal
| char_literal
| bool_literal

id
: alpha alpha_num*

alpha
: ['a'-'z''A'-'Z''_']

alpha_num
: alpha
| digit 

digit
: ['0'-'9']

hex_digit
: digit
| ['a'-'f''A'-'F']

int_literal
: decimal_literal
| hex_literal

decimal_literal
: digit+

hex_literal
: '0x' hex_digit+

bool_literal
: 'true'
| 'false'

char_literal
: '‘'char'’'

string_literal
: '“'char*'”'

1 个答案:

答案 0 :(得分:0)

这取决于您使用的ANTLR版本:

  • 在ANTLR 3中
    • 最常见的方法是使用Tree Construction指令创建(修改的)解析树/ AST,然后根据需要遍历该树。
    • ANTLR 3中不太常见的方法是将(动作)(目标语言)直接嵌入语法规则中,以捕获和解释解析后的输入。
  • 在ANTLR 4中,您使用ListenerVisitor处理已解析的输入。