parser

Написать ответ на текущее сообщение

 

 
   команды управления поиском

что у parser внутри #6

Александр Петросян (PAF) 06.02.2007 22:00 / 06.02.2007 22:04

немного деталей к #1 для тех, кто непуглив.

всё не так страшно, как кажется.
мы компилируем в байт-код, т.е. в массив неких "Operation".
каждый Operation может быть одним из нескольких штуковин.
у каждой штуковин не написано, что это (используется union) просто есть соглашение что за чем следует: Operation.code подразумевают, что ноль, одна или две следующих Operation суть параметры этой.
штуковины:
	OPCODE code; ///< operation code
скажем OP_ADD = "снять два верхних элемента со стека, сложить их между собой, результат положить обратно на стек"
	Origin origin; ///< not an operation, but rather debug information: [OP_VALUE; debug_info; Value*]
так пишу debug info
	Value* value; ///< not an operation, but rather value stored after argumented op
это параметр только что указанной операции, скажем за Operation где лежит .code=OP_VALUE следует Operation.value где лежит значение, которое нужно положить на стек
	ArrayOperation* ops; ///< not an operation, but rather code array stored after argumented op
это параметр предыдущей операции, когда данных нужно много.
например, у вызова параметр - код вычисления аргуметов.

возмём простой код
$c($a+$b)
parser-компилятор даст такой байткод.
пишу из головы, практический может чуть отличаться — кому не лень, пусть проверит и опубликует тут результат отладочной печати, если снять этот комментарий: "//#define DEBUG_EXECUTE"
Operation.code OP_WITH_ROOT
Operation.code OP_VALUE
Operation.origin file#1, line#11231, col#54
Operation.value VString("c")
Operation.code OP_PREPARE_TO_EXPRESSION
Operation.code OP_WITH_READ
Operation.code OP_VALUE
Operation.origin file#1, line#11231, col#57
Operation.value VString("a")
Operation.code OP_GET_ELEMENT
Operation.code OP_WITH_READ
Operation.code OP_VALUE
Operation.origin file#1, line#11231, col#59
Operation.value VString("b")
Operation.code OP_GET_ELEMENT
Operation.code OP_ADD
Operation.code OP_CONSTRUCT_EXPR
у байтмашины, которая это выполняет, нет регистров, всё тупо: живём в стеке (убираю debug info):
Operation.code OP_WITH_ROOT
положить в стек адрес хранилища, куда будем записывать элемент
Operation.code OP_VALUE
Operation.value VString("c")
положить в стек строку "c"
Operation.code OP_WITH_READ
положить в стек адрес хранилища, откуда будем читать элемент
Operation.code OP_VALUE
Operation.value VString("a")
положить в стек строку "a"
Operation.code OP_GET_ELEMENT
снять со стека имя
снять со стека адрес хранилища
положить в стек значение "хранилище->get_element(имя)"
[положить в стек значение $b, абсолютно такое же, как $a]
Operation.code OP_ADD
снять со стека значение
снять со стека значение
сложить их
результат положить в стек
Operation.code OP_CONSTRUCT_EXPR
снять со стека значение
снять со стека имя
снять со стека адрес хранилища
сделать хранилище->put_element(имя, значение)


ещё подробнее:
Operation.code OP_WITH_ROOT

		case OP_WITH_ROOT:
			{
				stack.push(*method_frame);
				break;
			}
т.е. положить на стек адрес того места, куда мы будем записывать переменную.
объект method_frame хитрый, и локальные переменные записывает в себя, остальное пропускает в "self" (который суть текущий объект или текущий класс).
Operation.code OP_VALUE
Operation.origin file#1, line#11231, col#54
Operation.value VString("c")

		case OP_VALUE:
			{
				debug_origin=i.next().origin;
				Value& value=*i.next().value;
				stack.push(value);
				break;
			}
увидев OP_VALUE, байтмашина высасывает next() две Operation, выдирает из них
* debug info на всякий случай (для stacktrace),
* само значение
кладёт значение в стек
Operation.code OP_PREPARE_TO_EXPRESSION
эта штука переключает флажок runtime оптимизации, отключая проверки, которые не нужны при обработке выражения.
Operation.code OP_WITH_READ

		case OP_WITH_READ: 
			{
				stack.push(*rcontext);
				break;
			}
т.е. положить на стек адрес того места, откуда мы будем считывать переменную.
по сути, это тоже method_frame.

...
Operation.code OP_ADD

		case OP_ADD: 
			{
				Value& b=stack.pop().value();  Value& a=stack.pop().value();
				Value& value=*new VDouble(a.as_double() + b.as_double());
				stack.push(value);
				break;
			}

Operation.code OP_CONSTRUCT_EXPR

		case OP_CONSTRUCT_VALUE:
			{
				Value& value=stack.pop().value();
				const String& name=stack.pop().string();  debug_name=&name;
				Value& ncontext=stack.pop().value();
				put_element(ncontext, name, value);

				break;
			}