Skip to content

Instantly share code, notes, and snippets.

@worldbeater
Last active May 7, 2024 10:21
Show Gist options
  • Save worldbeater/4938db8596e276b16c840e741707e12e to your computer and use it in GitHub Desktop.
Save worldbeater/4938db8596e276b16c840e741707e12e to your computer and use it in GitHub Desktop.
Parses a subset of 1C into Python tuple-based AST. Uses peco.py, see https://github.com/true-grue/peco
from peco import *
from pprint import pprint
def toloc(f, sep='\n'):
n = f.__code__.co_argcount - 1
def parse(s):
lineno = s.data.count(sep, 0, s.pos) + 1
pos = len(s.stack) - n
part = f(*s.stack[pos:], (lineno, 0))
return s._replace(stack=s.stack[:pos] + (part,))
return parse
ws = many(space)
tok = lambda f: memo(seq(ws, f))
skip = lambda c: tok(sym(c))
op = lambda c: tok(cite(sym(c)))
keywords = seq(alt(
skip('Функция'),
skip('КонецФункции'),
skip('Возврат'),
skip('Для'),
skip('По'),
skip('Цикл'),
skip('КонецЦикла'),
skip('Новый')),
npeek(letter))
mkbop = toloc(lambda a, o, b, loc: (o, a, b, loc))
mknum = toloc(lambda x, loc: ('const', x, loc))
mkvar = toloc(lambda x, loc: ('var', x, loc))
mkapp = toloc(lambda fun, args, loc: ('call', fun, ('args', *args, loc), loc))
mkind = toloc(lambda src, ind, loc: ('index', src, ind, loc))
mkmem = toloc(lambda src, mem, loc: ('member', src, mem, loc))
mkass = toloc(lambda target, value, loc: ('assign', target, value, loc))
mknew = toloc(lambda name, loc: ('new', name, loc))
mkfor = toloc(lambda counter, lower, upper, body, loc: ('for', counter, lower, upper, ('body', *body, loc), loc))
mkfun = toloc(lambda name, args, body, loc: ('func', name, ('params', *args, loc), ('body', *body, loc), loc))
mkret = toloc(lambda val, loc: ('ret', val, loc))
integer = alt(seq(range_of('1', '9'), many(digit)), sym('0'))
fractional = seq(sym('.'), some(digit))
num = seq(cite(seq(integer, opt(fractional))), mknum)
var = seq(npeek(keywords), cite(seq(letter, many(alt(letter, digit)))))
expr = lambda s: expr(s)
term = lambda s: term(s)
fact = lambda s: fact(s)
attr = lambda s: attr(s)
stmt = lambda s: stmt(s)
attr = left(alt(
seq(attr, skip('.'), seq(tok(var), mkvar), mkmem),
seq(attr, skip('['), expr, skip(']'), mkind),
seq(attr, skip('('), group(opt(list_of(expr, skip(',')))), skip(')'), mkapp),
seq(tok(var), mkvar)))
fact = left(alt(
seq(skip('Новый'), seq(tok(var), mkvar), mknew),
seq(skip('('), expr, skip(')')),
tok(num),
attr))
term = left(alt(seq(term, op('*'), fact, mkbop),
seq(term, op('/'), fact, mkbop),
fact))
expr = left(alt(seq(expr, op('+'), term, mkbop),
seq(expr, op('-'), term, mkbop),
term))
stmt = left(alt(
seq(skip('Возврат'), expr, skip(';'), mkret),
seq(skip('Для'), tok(var), skip('='), expr, skip('По'), expr, skip('Цикл'),
group(seq(stmt, many(stmt))),
skip('КонецЦикла'), skip(';'), mkfor),
seq(skip('Функция'), tok(var), skip('('), group(opt(list_of(tok(var), skip(',')))), skip(')'),
group(seq(stmt, many(stmt))),
skip('КонецФункции'), skip(';'), mkfun),
seq(attr, skip('='), expr, skip(';'), mkass),
seq(attr, skip(';'))))
def ast(code):
state = parse(code, seq(many(stmt), ws))
return state.stack[-1]
CODE = '''
Функция ВыполнитьПредсказание(Тета, Объекты)
Выводы = Новый СписокЗначений;
Для НомерСтроки = 0 По Объекты.Количество() - 1 Цикл
СкалярноеПроизведение = 0;
Для НомерСтолбца = 0 По Объекты[НомерСтроки].Значение.Количество() - 1 Цикл
СкалярноеПроизведение =
СкалярноеПроизведение +
Объекты[НомерСтроки].Значение[НомерСтолбца].Значение *
Тета[НомерСтолбца].Значение;
КонецЦикла;
Выводы.Добавить(СкалярноеПроизведение);
КонецЦикла;
Предсказания = Новый СписокЗначений;
Для НомерСтроки = 0 По Выводы.Количество() - 1 Цикл
Предсказания.Добавить(1 / (1 + Exp(1 - Выводы[НомерСтроки].Значение)));
КонецЦикла;
Возврат Предсказания;
КонецФункции;
'''.strip()
pprint(ast(CODE))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment