antlr4: обработка условного кода в посетителе - PullRequest
0 голосов
/ 28 апреля 2020

Я пишу (собственный язык -> JS), используя ANTLR (javascript target, используя посетителя).
Фокус на вариациях , в генерации целевого кода .

Более ранняя ТАК сообщение , описывает решение более простой ситуации. Этот отличается, в основном из-за рекурсии.

Грамматика:

grammar Alang;
...

variableDeclaration : DECL (varDecBl1 | varDecBl2) EOS;
varDecBl1 : ID AS TYP;
varDecBl2 : CMP ID US (SGST varDecBl1+ SGFN);
...


DECL  : 'var-declare' ;
EOS   : ';' ;
SGST  : 'segment-start:' ;
SGFN  : 'segment-finish' ;
AS    : 'as';
CMP   : 'cmp';
US    : 'using';
TYP
: 'str'
| 'int'
| 'bool'
;
ID    : [a-zA-Z0-9_]+ ;

Два разных случая исходного кода должны обрабатываться по-разному.

Исходный код 1:

var-declare fooString as str;

цель, которую необходимо указать как: var fooString;

Исходный код 2:

var-declare cmp barComplex using 
segment-start:
 barF1 as int
 barF2 as bool
 barF3 as str 
segment-finish;

цель этого должна быть: var barComplex = new Map();
(так как простое объявление var не может обработать тип значения)

генерация кода выполнена с использованием:

  visitVarDecBl1 = function(ctx) {    
    this.targetCode += `var ${ctx.getChild(0).getText()};`;
    return this.visitChildren(ctx);
  };

....

  visitVarDecBl2 = function(ctx) {
    this.targetCode += `var ${ctx.getChild(1).getText()} = new Map();`;
    return this.visitChildren(ctx);
  };

(targetCode объединяет целевой код)

Выше работает для случая 1.
Для случая 2 он выходит за пределы var barComplex = new Map() из-за рекурсивного использования правила varDecBl1, которое вызывает visitVarDecBl1 code gen реализовать снова.

Неправильный результат:

var barComplex = new Map();
var barF1;   // <---- wrong one coming from visitVarDecBl1
var barF2;   // <---- wrong
var barF3;   // <---- wrong

Чтобы справиться с этим, я хочу попробовать один из подходов - сделать visitVarDecBl1 условным для родительского ctx.
Если родительский = variableDeclaration, целевой код = var ${ctx.getChild(0).getText()};.
Если родитель = varDecBl2, пропустить генерацию кода.

Но я не могу найти вызывающее правило в полезной нагрузке ctx, чтобы я мог сравнивать строки .
Использование чего-то вроде ctx.parentCtx дает мне [378 371 204 196 178 168] (хэши?).

Входные данные приветствуются. (включая предложение о лучшем подходе, если таковой имеется)

1 Ответ

0 голосов
/ 29 апреля 2020

На случай, если кто-нибудь увидит похожую ситуацию, я отправлю ответ сам.
Я справился с ним, извлекая родительское правило самостоятельно.

util = require("util");

...

//  parentCtx object -> string
const parentCtxStr = util.inspect(ctx.parentCtx);   

// snip out parent rule from payload, e.g.: 'varDecBl2 {…, ruleIndex: 16, …}'
const snip = parentCtxStr.slice(0,parentCtxStr.indexOf("{")-1); // extracts varDecBl2 for you
}

Теперь используйте значение snip для работы, как описано выше.

Конечно, этот способ устанавливает связь с тем, как структурирована полезная нагрузка. И риск в будущем, если это изменится. Я бы предпочел использовать те же самые вещи через API, хотя я не мог их найти.

...