Генерация промежуточного кода с использованием синтаксически-направленного перевода в ANTLR - PullRequest
0 голосов
/ 24 ноября 2018

Итак, этот вопрос не обязательно является моей проблемой, скорее это недостаток понимания.

У меня есть этот код 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.

Итак, у нас есть три файла: symbols.csv, symtable.csv и инструкция.csv

В символах.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.

В инструкции .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,

инструкция.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, мог указать мне правильное направление.

Заранее благодарю за любую помощь.

PS Мои лексеры и парсер основаныот крошечного C-подобного языка, который размещен ниже.

Tiny C-Like Language:

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 голосов
/ 26 ноября 2018

Это зависит от того, какую версию ANTLR вы используете:

  • В ANTLR 3
    • Наиболее распространенным подходом было использование Конструкция дерева инструкции длясоздайте (измененное) дерево разбора / AST, а затем пройдитесь по этому дереву по мере необходимости.
    • Менее распространенный подход в ANTLR 3 состоит в том, чтобы встраивать действия (на целевом языке) непосредственно в правила грамматики.для захвата и интерпретации проанализированного ввода.
  • В ANTLR 4 вы используете Listener или Visitor для обработки проанализированного ввода.
...