jcxz 241 21 мая, 2019 Опубликовано 21 мая, 2019 · Жалоба 10 минут назад, xvr сказал: Вы внутрь этого смотрели? Это только для сильных духом А кто вам сказал, что ТС будет с этим разбираться? Он впендюрит этот код к себе в проект как есть, а потом, если что-то не заработает как надо, то разбираться будем в этом здесь, всем форумом. как будто в первой раз.... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 78 21 мая, 2019 Опубликовано 21 мая, 2019 · Жалоба 1 minute ago, xvr said: Вы внутрь этого смотрели? Это только для сильных духом (И размер в 500 строк ужаса содержимого не компенсируют) смотрел, немного расширенный пример парсера калькулятора из книжки Страуструпа по плюсам, с добавлением простой стэковой виртуальной машины. слабые духом могут в те три функции что непосредственно парсят С, даже не заглядывать, а просто добавить доступ из скрипта к своим "внешним переменным" вместо маллоков и принтфов, ничего особо не меняя. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 21 мая, 2019 Опубликовано 21 мая, 2019 · Жалоба Вопрос к jenya7 - будете смотреть с4, или мне продолжать писать тут движок? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 21 мая, 2019 Опубликовано 21 мая, 2019 (изменено) · Жалоба 1 hour ago, xvr said: Вопрос к jenya7 - будете смотреть с4, или мне продолжать писать тут движок? я его смотрел. в общем он понятен - общий принцип, но в частности... лично у меня, чтоб его модифицировать займет много времени и сил. нужно вгрызаться глубоко в суть. Изменено 21 мая, 2019 пользователем jenya7 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 21 мая, 2019 Опубликовано 21 мая, 2019 · Жалоба Ок, надеюсь что у меня получится понятнее :) Продолжим - лексер. Spoiler int Parser::yylex(void *out_) { static std::map<std::string, std::pair<int, int>> ids { #define VAR(n) {#n, {vID, IDV_##n}}, #include "var_defs.inc" #undef VAR {"if", {tIF, 0}}, {"then", {tTHEN, 0}} }; YYSTYPE& out = *(YYSTYPE*)out_; while(isspace(*input)) ++input; if (isdigit(*input)) { out.i_const = strtol(input, (char**)&input, 0); return vNUM; } if (isalnum(*input) || *input=='_') { char* start = input; while(isalnum(*input) || *input=='_') ++input; std::string tok(start, input); if (ids.count(tok)) { auto& value = ids[tok]; out.i_const = value.second; return value.first; } yyerror("Unexpected ID `"+tok+"`"); return -1; } #define V2(c1, c2) (uint8_t(c1) + 256*uint8_t(c2)) input += 2; switch(V2(input[-2], input[-1])) { case V2('>', '='): return sGE; case V2('<', '='): return sLE; case V2('=', '='): return sEQ; case V2('!', '='): return sNE; case V2('+', '='): return sASSIGN_ADD; case V2('-', '='): return sASSIGN_SUB; case V2('&', '&'): return sAND; case V2('|', '|'): return sOR; } return (--input)[-1]; #undef V2 } В файле var_defs.inc лежит список ваших переменных в таком виде - Spoiler VAR(CMP) VAR(PWM0) VAR(PWM1) Этот файл так же общий для РС и интерпретатора на МК Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 21 мая, 2019 Опубликовано 21 мая, 2019 · Жалоба 2 hours ago, xvr said: Reveal hidden contents VAR(CMP) VAR(PWM0) VAR(PWM1) Этот файл так же общий для РС и интерпретатора на МК как общий? я на МК пишу на С не С++. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 21 мая, 2019 Опубликовано 21 мая, 2019 · Жалоба 8 minutes ago, jenya7 said: как общий? я на МК пишу на С Там чистый С Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 21 мая, 2019 Опубликовано 21 мая, 2019 (изменено) · Жалоба 1 hour ago, xvr said: Там чистый С Выглядит как С++ int Parser::yylex(void *out_) Изменено 21 мая, 2019 пользователем jenya7 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 22 мая, 2019 Опубликовано 22 мая, 2019 · Жалоба 22 hours ago, jenya7 said: Выглядит как С++ int Parser::yylex(void *out_) Не этот файл общий, а var_defs.inc Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 22 мая, 2019 Опубликовано 22 мая, 2019 · Жалоба Продолжаем. Буффер кода и процедуры генерации байткода Spoiler void CodeGenerator::push(int opc, int length, int32_t data, const std::string& asm_menmonic) { size_t start_shift = code_image.size(); code_image.push_back(opc); uint8_t* p = (uint8_t*)&data; while(length--) code_image.push_back(*p++); if (lst_file) { std::string acc for(size_t i=start_shift; i<code_image.size(); ++i) acc += prn("%02X ", code_image[i]); add_lst_line(prn("%04X: %-15s %s", start_shift, acc.c_str(), asm_menmonic.c_str())); } } /////////////////////////////////////////////////////////////////////////////////////// void NodeConst::generate_code(CodeGenerator &cg) { auto asm = prn("Const %d", value); if (int16_t(value) != value) cg.push4(OP_Const4, value, asm); else if (value >= -64 && value <= 63) cg.push0(OP_Const0 | (value & 0x7F), asm); else cg.push2(OP_Const2, value, asm); } void NodeVar::generate_code(CodeGenerator &cg) { static const char* mnems[] = {"ReadVar", "SetVar", "AddVar"}; static const char* ids[] = { #define VAR(n) #n, #include "var_defs.inc" #undef VAR NULL }; if (assign_value) assign_value->generate_code(cg); auto asm = prn("%s #%d (%s)", mnems[(opcode - OP_ReadVar) >> 5], index, ids[index]); if (index<31) cg.push0(opcode | (index&0x31), asm); else cg.push1(opcode | 31, index-31, asm); if (next) next->generate_code(cg); } void NodeOp::generate_code(CodeGenerator &cg) { if (opcode == OP_Stop) cg.push0(OP_Stop, "STOP"); else { left->generate_code(cg); if (right) right->generate_code(cg); static const char* mnems[]= {"EQ", "NE", "GT", "GE", "And", "Or", "Add", "Sub", "Mul", "Div", "Mod", "Neg"}; cg.push0(opcode, mnems[opcode-OP_EQ]); } } Гененратор корневой конструкции (if ... then ...) Spoiler void Parser::add_if(Node* if_expression, NodeVar* then_expression) { if_expression->generate_code(code); size_t body_size; { CodeGenerator tmp_code; then_expression->generate_code(tmp_code); body_size = tmp_code.get_image().size(); } size_t shift = code.get_image().size() + body_size + 2; if (body_size <= 255) code.push1(OP_JmpF1, body_size, prn("JumpF +%d (=> %04X)", body_size, shift)); else code.push2(OP_JmpF2, body_size, prn("JumpF +%d (=> %04X)", body_size, shift + 1)); then_expression->generate_code(code); delete if_expression; delete then_expression; } И оптимизаторы для унарного минуса и бинарных операций Spoiler Node* Parser::new_unary(Opcode opcode, Node* left) { if (opcode == OP_Neg) // For now this is only possible { switch(left->opcode) // Find for possible optimisation { case OP_Neg: {auto result = left->left; left->left=NULL; delete left; return result;} // Remove - - sequence case OP_Add: left->opcode = OP_Sub; return left; // Change += for -= case OP_Sub: left->opcode = OP_Add; return left; // Change -= for += case OP_Const0: ((NodeConst*)left)->value *= -1; return left; // Flip sign of constant value } } return new NodeOp(opcode, left); } Node* Parser::new_binary(Opcode opcode, Node* left, Node* right) { if (left->opcode == OP_Const0 && right->opcode == OP_Const0) // Constant evaluation { int32_t l = ((NodeConst*)left)->value; int32_t r = ((NodeConst*)right)->value; delete left; delete right; switch(opcode) { case OP_EQ: r = l == r; break; case OP_NE: r = l != r; break; case OP_GT: r = l > r; break; case OP_GE: r = l >= r; break; case OP_And: r = l && r; break; case OP_Or: r = l || r; break; case OP_Add: r = l + r; break; case OP_Sub: r = l - r; break; case OP_Mul: r = l * r; break; case OP_Div: r = l / r; break; case OP_Mod: r = l % r; break; default: r=0; // this is should never happened! } return new NodeConst(r); } if (left->opcode == OP_Const0 || right->opcode == OP_Const0) // Shortcut with some constants { #define L(opc, value) ((opc<<3) | ((value+1)<<1)) // <const> <opcode> <some> version #define R(opc, value) (L(opc, value) | 1) // <some> <opcode> <const> version Node *const_ptr = left; Node *other_ptr = right; int32_t value; int sw; if (left->opcode == OP_Const0) { const_ptr = left; other_ptr = right; value = ((NodeConst*)const_ptr)->value; sw = L(opcode, value); } else { const_ptr = right; other_ptr = left; value = ((NodeConst*)const_ptr)->value; sw = R(opcode, value); } if (value && other_ptr->opcode == OP_Or) {delete const_ptr; delete other_ptr; return new NodeConst(1);} if (value >= -1 && value <= 1) switch(sw) // Try to optimize { #define LR(opc, num) L(opc, num): case R(opc, num) // <some> + 0, 0 + <some>, <some> * 1, 1 * <some>, <some> / 1 => <some> case LR(OP_Add,0): case LR(OP_Mul,1): case R(OP_Sub,0): case R(OP_Div,1): delete const_ptr; return other_ptr; // <some> * -1, -1 * <some>, 0 - <some> => - <some> case LR(OP_Mul,-1): case R(OP_Div,-1): case L(OP_Sub,0): delete const_ptr; return new_unary(OP_Neg, other_ptr); // <some> * 0, 0 * <some>, <some> % 1 => 0 case LR(OP_Mul,0): case LR(OP_And,0): case R(OP_Mod,1): delete const_ptr; delete other_ptr; return new NodeConst(0); } #undef L #undef R #undef LR } return new NodeOp(opcode, left, right); } В принципе оптимизаторы можно выкинуть (за исключением последовательности - <const>), если предполагать, что пользователь не будет писать бессмыссленных выражений (и что он сам умеет считать и сможет вычислить константы) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 22 мая, 2019 Опубликовано 22 мая, 2019 · Жалоба 56 минут назад, xvr сказал: В принципе оптимизаторы можно выкинуть (за исключением последовательности - <const>), если предполагать, что пользователь не будет писать бессмыссленных выражений (и что он сам умеет считать и сможет вычислить константы) Лучше предполагать, что он так будет делать. Так как это - хороший стиль. Код должен быть самокомментируемым. По возможности. А не состоять из малоосмысленных числовых выражений x=1234+7654. И числовые константы - вещь очень нужная. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 22 мая, 2019 Опубликовано 22 мая, 2019 · Жалоба 2 hours ago, xvr said: Продолжаем. Буффер кода и процедуры генерации байткода Reveal hidden contents void CodeGenerator::push(int opc, int length, int32_t data, const std::string& asm_menmonic) { size_t start_shift = code_image.size(); code_image.push_back(opc); uint8_t* p = (uint8_t*)&data; while(length--) code_image.push_back(*p++); if (lst_file) { std::string acc for(size_t i=start_shift; i<code_image.size(); ++i) acc += prn("%02X ", code_image[i]); add_lst_line(prn("%04X: %-15s %s", start_shift, acc.c_str(), asm_menmonic.c_str())); } } /////////////////////////////////////////////////////////////////////////////////////// void NodeConst::generate_code(CodeGenerator &cg) { auto asm = prn("Const %d", value); if (int16_t(value) != value) cg.push4(OP_Const4, value, asm); else if (value >= -64 && value <= 63) cg.push0(OP_Const0 | (value & 0x7F), asm); else cg.push2(OP_Const2, value, asm); } void NodeVar::generate_code(CodeGenerator &cg) { static const char* mnems[] = {"ReadVar", "SetVar", "AddVar"}; static const char* ids[] = { #define VAR(n) #n, #include "var_defs.inc" #undef VAR NULL }; if (assign_value) assign_value->generate_code(cg); auto asm = prn("%s #%d (%s)", mnems[(opcode - OP_ReadVar) >> 5], index, ids[index]); if (index<31) cg.push0(opcode | (index&0x31), asm); else cg.push1(opcode | 31, index-31, asm); if (next) next->generate_code(cg); } void NodeOp::generate_code(CodeGenerator &cg) { if (opcode == OP_Stop) cg.push0(OP_Stop, "STOP"); else { left->generate_code(cg); if (right) right->generate_code(cg); static const char* mnems[]= {"EQ", "NE", "GT", "GE", "And", "Or", "Add", "Sub", "Mul", "Div", "Mod", "Neg"}; cg.push0(opcode, mnems[opcode-OP_EQ]); } } Гененратор корневой конструкции (if ... then ...) Reveal hidden contents void Parser::add_if(Node* if_expression, NodeVar* then_expression) { if_expression->generate_code(code); size_t body_size; { CodeGenerator tmp_code; then_expression->generate_code(tmp_code); body_size = tmp_code.get_image().size(); } size_t shift = code.get_image().size() + body_size + 2; if (body_size <= 255) code.push1(OP_JmpF1, body_size, prn("JumpF +%d (=> %04X)", body_size, shift)); else code.push2(OP_JmpF2, body_size, prn("JumpF +%d (=> %04X)", body_size, shift + 1)); then_expression->generate_code(code); delete if_expression; delete then_expression; } И оптимизаторы для унарного минуса и бинарных операций Reveal hidden contents Node* Parser::new_unary(Opcode opcode, Node* left) { if (opcode == OP_Neg) // For now this is only possible { switch(left->opcode) // Find for possible optimisation { case OP_Neg: {auto result = left->left; left->left=NULL; delete left; return result;} // Remove - - sequence case OP_Add: left->opcode = OP_Sub; return left; // Change += for -= case OP_Sub: left->opcode = OP_Add; return left; // Change -= for += case OP_Const0: ((NodeConst*)left)->value *= -1; return left; // Flip sign of constant value } } return new NodeOp(opcode, left); } Node* Parser::new_binary(Opcode opcode, Node* left, Node* right) { if (left->opcode == OP_Const0 && right->opcode == OP_Const0) // Constant evaluation { int32_t l = ((NodeConst*)left)->value; int32_t r = ((NodeConst*)right)->value; delete left; delete right; switch(opcode) { case OP_EQ: r = l == r; break; case OP_NE: r = l != r; break; case OP_GT: r = l > r; break; case OP_GE: r = l >= r; break; case OP_And: r = l && r; break; case OP_Or: r = l || r; break; case OP_Add: r = l + r; break; case OP_Sub: r = l - r; break; case OP_Mul: r = l * r; break; case OP_Div: r = l / r; break; case OP_Mod: r = l % r; break; default: r=0; // this is should never happened! } return new NodeConst(r); } if (left->opcode == OP_Const0 || right->opcode == OP_Const0) // Shortcut with some constants { #define L(opc, value) ((opc<<3) | ((value+1)<<1)) // <const> <opcode> <some> version #define R(opc, value) (L(opc, value) | 1) // <some> <opcode> <const> version Node *const_ptr = left; Node *other_ptr = right; int32_t value; int sw; if (left->opcode == OP_Const0) { const_ptr = left; other_ptr = right; value = ((NodeConst*)const_ptr)->value; sw = L(opcode, value); } else { const_ptr = right; other_ptr = left; value = ((NodeConst*)const_ptr)->value; sw = R(opcode, value); } if (value && other_ptr->opcode == OP_Or) {delete const_ptr; delete other_ptr; return new NodeConst(1);} if (value >= -1 && value <= 1) switch(sw) // Try to optimize { #define LR(opc, num) L(opc, num): case R(opc, num) // <some> + 0, 0 + <some>, <some> * 1, 1 * <some>, <some> / 1 => <some> case LR(OP_Add,0): case LR(OP_Mul,1): case R(OP_Sub,0): case R(OP_Div,1): delete const_ptr; return other_ptr; // <some> * -1, -1 * <some>, 0 - <some> => - <some> case LR(OP_Mul,-1): case R(OP_Div,-1): case L(OP_Sub,0): delete const_ptr; return new_unary(OP_Neg, other_ptr); // <some> * 0, 0 * <some>, <some> % 1 => 0 case LR(OP_Mul,0): case LR(OP_And,0): case R(OP_Mod,1): delete const_ptr; delete other_ptr; return new NodeConst(0); } #undef L #undef R #undef LR } return new NodeOp(opcode, left, right); } В принципе оптимизаторы можно выкинуть (за исключением последовательности - <const>), если предполагать, что пользователь не будет писать бессмыссленных выражений (и что он сам умеет считать и сможет вычислить константы) я с нуля никогда не создавал проект С++. В какой среде лучше работать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 22 мая, 2019 Опубликовано 22 мая, 2019 · Жалоба Сделал проект в VS2017. Компилятор получился на 500 строк (в сумме по всем файлам) Пример скрипта: if CMP == 0 && PWM0 > PWM1 then PWM0 += 1; PWM1 = (CMP-(3-4)) Выхлоп (листинг): # if CMP == 0 && PWM0 > PWM1 then PWM0 += 1; PWM1 = (CMP-(3-4)) 0000: 80 ReadVar #0 (CMP) 0001: 00 Const 0 0002: E4 EQ 0003: 81 ReadVar #1 (PWM0) 0004: 80 ReadVar #2 (PWM1) 0005: E6 GT 0006: E8 And 0007: E2 06 JumpF +6 (=> 000F) 0009: 01 Const 1 000A: C1 AddVar #1 (PWM0) 000B: 80 ReadVar #0 (CMP) 000C: 7F Const -1 000D: EB Sub 000E: A0 SetVar #2 (PWM1) 000F: FF Stop script.zip 20 minutes ago, jcxz said: И числовые константы - вещь очень нужная. угу, только в этом недоязыке их нет :( Но можно пропустить через CPP препроцессор - появятся :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 22 мая, 2019 Опубликовано 22 мая, 2019 · Жалоба 2 hours ago, xvr said: Сделал проект в VS2017. Компилятор получился на 500 строк (в сумме по всем файлам) А какой тип проекта? там несколько. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 23 мая, 2019 Опубликовано 23 мая, 2019 · Жалоба 18 hours ago, jenya7 said: А какой тип проекта? там несколько. В атаче в моём предыдущем посте готовый проект (вместе с всеми необходимыми для VS файлами) Проект - С++ Win32 Console Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться