diff options
| author | Clément Zrounba <6691770+clement-z@users.noreply.github.com> | 2023-09-30 23:06:01 +0200 |
|---|---|---|
| committer | Clément Zrounba <6691770+clement-z@users.noreply.github.com> | 2023-09-30 23:26:46 +0200 |
| commit | ff9b8bb838ecdfbfc1dc81038fcf3b2a87636982 (patch) | |
| tree | 21f27be782ce11c6d00b96ce100a2bff88141b2e /src/parser/parser.y | |
| download | specs-ff9b8bb838ecdfbfc1dc81038fcf3b2a87636982.tar.gz specs-ff9b8bb838ecdfbfc1dc81038fcf3b2a87636982.zip | |
Initial release
Diffstat (limited to 'src/parser/parser.y')
| -rw-r--r-- | src/parser/parser.y | 961 |
1 files changed, 961 insertions, 0 deletions
diff --git a/src/parser/parser.y b/src/parser/parser.y new file mode 100644 index 0000000..36be00f --- /dev/null +++ b/src/parser/parser.y @@ -0,0 +1,961 @@ +%define api.pure full +%param { yyscan_t scanner } + + +%code requires{ + typedef void * yyscan_t; + // char *yyget_text ( yyscan_t yyscanner ); + // int yyget_lineno ( yyscan_t yyscanner ); + // int yylex(YYSTYPE * yylval, yyscan_t scanner); + + //extern int yylineno; + //extern char *yytext; +} + +%{ +#include <iostream> +#include <string> +#include <vector> +#include <cstring> +#include <cmath> +#include <memory> +#include "parse_tree.h" +#include "parse_element.h" +#include "parse_analysis.h" +#include "parse_directive.h" + +#include "../build/parser/parser.tab.h" +#include "../build/parser/parser.yy.h" + +using std::string; +using std::vector; +using std::pow; + +extern ParseTree *cur_pt; + +/*int yyerror(yyscan_t scanner, ParseTree *pt, const char *err) +{ + (void)pt; + (void)p; + printf("Error in the netlist (line %u:\"%s\")\n", yylineno, yytext); + printf("-- Error at line %u:\n\t%s\n", yylineno, err); + return 0; +} +*/ +int yyerror(yyscan_t scanner, ParseTree *pt, const char *err); +%} + +%union { + double d_val; + int i_val; + char c_val; + string *s_ptr; + char *c_ptr; + vector<double> *vec_d_ptr; + pair<string, Variable> *assig_ptr; + Variable *variable_ptr; + vector<Variable> *vec_var_ptr; + pair<string, string> *elemattr_ptr; + pair<string, pair<string, Variable>> *netval_assign_ptr; + pair<pair<string, string>, vector<double>> *cw_sweep_order_ptr; +} + +// %define api.value.type {struct YYSTYPE} + +%token <d_val> T_NUM +%token <i_val> T_INT +%token <i_val> T_NONE +%token <s_ptr> T_STR +%token <s_ptr> T_ASSIGN_ID +%token <s_ptr> T_ELEM_CWSRC T_ELEM_VLSRC T_ELEM_EVLSRC +%token <s_ptr> T_ELEM_WG T_ELEM_COUPLER T_ELEM_MERGER T_ELEM_SPLITTER +%token <s_ptr> T_ELEM_PSHIFT T_ELEM_MZI T_ELEM_CROSSING T_ELEM_PCMCELL +%token <s_ptr> T_ELEM_PROBE T_ELEM_MLPROBE T_ELEM_PDET +%token <s_ptr> T_ELEM_X +%token <i_val> T_ANALYSIS_OP T_ANALYSIS_DC T_ANALYSIS_TRAN +%token <i_val> T_DIRECTIVE_OPTIONS T_DIRECTIVE_NODESET +%token <i_val> T_DIRECTIVE_SUBCKT +%token <s_ptr> T_DIRECTIVE_ENDS +%token <s_ptr> T_DIRECTIVE_SAVE +%token <i_val> T_LOCAL_ASSIGNMENT +%type <c_val> '=' + + +// Available circuit elements +%type <i_val> element.wg +%type <i_val> element.merger +%type <i_val> element.splitter +%type <i_val> element.coupler +%type <i_val> element.pshift +%type <i_val> element.mzi +%type <i_val> element.crossing +%type <i_val> element.pcm_cell +%type <i_val> element.cwsrc +%type <i_val> element.vlsrc +%type <i_val> element.evlsrc +%type <i_val> element.probe +%type <i_val> element.mlprobe +%type <i_val> element.pdet +%type <i_val> element.x + +// Available analysis +%type <i_val> analysis.op +%type <i_val> analysis.dc +%type <i_val> analysis.tran +%type <cw_sweep_order_ptr> cw_sweep_order + +// Available directives +%type <i_val> directive.options +%type <i_val> directive.nodeset + +// Rules for circuit nets (value is index in PT elements) +%type <s_ptr> net_name.base.str +%type <s_ptr> net_name_base +%type <s_ptr> net_name +%type <s_ptr> net.oanalog net.eanalog net.edigital +%type <s_ptr> net.oa.explicit_bidir +%type <s_ptr> net.oa.bidir +%type <s_ptr> net.oa.in +%type <s_ptr> net.oa.out + +//%type <s_ptr> bus_name bus bus.oanalog bus.eanalog bus.edigital + +// Rules related to subcircuits +%type <i_val> subcircuit +%type <i_val> subcircuit.with_ports +%type <i_val> subcircuit.with_assignments +%type <s_ptr> port_name + +// Rules for circuit elements (value is index in PT elements arrays) +%type <i_val> atomelement element +%type <i_val> element.with_args element.with_kwargs +%type <i_val> element.x.with_args element.x.with_kwargs + +// Rules for circuit analysis (value is ptr to ParseAnalysis) +%type <i_val> atomanalysis analysis +%type <i_val> analysis.with_args analysis.with_kwargs + +// Rules for simulator directives (value is ptr to ParseDirective) +%type <i_val> atomdirective directive +%type <i_val> directive.with_args directive.with_kwargs + +// For argument parsing +%type <assig_ptr> assignment +%type <variable_ptr> variable variable_base variable_or_empty +%type <variable_ptr> variable.free_expr variable.delimited_expr +//%type <variable_ptr> variable.str_without_quotes +%type <netval_assign_ptr> netval_assignment +%type <elemattr_ptr> element_attribute + +// For expression parsing +%type <variable_ptr> expr term fact pow constant +%type <variable_ptr> listvar.tail listvar.unbound listvar.bound //TODO: check + +// Add parse tree parameter to yyparse signature +%parse-param {ParseTree *pt} +//%verbose +//%define parse.error detailed +//%define parse.trace + +// On start, set current parse tree to the one passed in call to yyparse +%initial-action { + cur_pt = pt; + if (!pt) + yyerror(scanner, pt, "Invalid parse tree pointer"); +} + + +%% + +input: %empty + | input line '\n' +; + +line: %empty + | element { /* cout << "Inserted element: " << cur_pt->elements[$1]->name << endl; */ } + | analysis { /* cout << "Registered analysis [...]" << endl; */ } + | directive { /* cout << "Registered directive [...]" << endl; */ } + | subcircuit { /* cout << "Parsed subcircuit [...]" << endl; */ } + | local_assignment { /* cout << "Processed local assignment [...]" << endl; */ } +; + +local_assignment: T_LOCAL_ASSIGNMENT assignment + { + cur_pt->set_local_variable($2->first, $2->second); + } + | local_assignment assignment + { + cur_pt->set_local_variable($2->first, $2->second); + } +; + +/* --------- Directives definitions parsing ----------- */ + +directive.options: T_DIRECTIVE_OPTIONS { $$ = cur_pt->register_directive(new OPTIONSDirective); } +; + +directive.nodeset: T_DIRECTIVE_NODESET { $$ = cur_pt->register_directive(new NODESETDirective); } + | directive.nodeset netval_assignment + { + static_cast<NODESETDirective *>(cur_pt->directives[$1])->net_assignments[$2->first].push_back($2->second); + $$ = $1; + } +; +subcircuit.with_ports: T_DIRECTIVE_SUBCKT T_STR + { + // Register a new subcircuit in current parse tree + $$ = cur_pt->register_subcircuit(*$2); + delete $2; + } + | subcircuit.with_ports port_name + { + if (!cur_pt->subcircuits[$1]->kwargs.empty()) + { + cerr << "Expected keyword assignment in subcircuit declaration but got: " << *$2 << endl; + exit(1); + } + // cout << *$2 << endl; + cur_pt->subcircuits[$1]->register_port(*$2); + $$ = $1; + delete $2; + } +; +subcircuit.with_assignments: + subcircuit.with_assignments assignment + { + cur_pt->subcircuits[$1]->kwargs[$2->first] = $2->second; + + $$ = $1; + delete $2; + } +| subcircuit.with_ports +; + +subcircuit: subcircuit.with_assignments T_DIRECTIVE_ENDS + { + // cout << "Parsed subcircuit " << cur_pt->subcircuits[$1]->name << endl; + cur_pt->subcircuits[$1]->netlist = *$2; + delete $2; + } +; + +/* --------- Elements definitions parsing ----------- */ + +element.wg: T_ELEM_WG net.oa.in net.oa.out + { + $$ = cur_pt->register_element(new WGElement(*$1, {*$2, *$3})); + delete $1; + delete $2; + delete $3; + } +; + +element.merger: T_ELEM_MERGER net.oa.in net.oa.in net.oa.out + { + $$ = cur_pt->register_element(new MergerElement(*$1, {*$2, *$3, *$4})); + delete $1; + delete $2; + delete $3; + delete $4; + } +; + +element.splitter: T_ELEM_SPLITTER net.oa.in net.oa.out net.oa.out + { + $$ = cur_pt->register_element(new SplitterElement(*$1, {*$2, *$3, *$4})); + delete $1; + delete $2; + delete $3; + delete $4; + } +; + +element.coupler: T_ELEM_COUPLER net.oa.in net.oa.in net.oa.out net.oa.out + { + $$ = cur_pt->register_element(new DCElement(*$1, {*$2, *$3, *$4, *$5})); + delete $1; + delete $2; + delete $3; + delete $4; + delete $5; + } +; + +element.pshift: T_ELEM_PSHIFT net.oa.in net.oa.out net.eanalog + { + $$ = cur_pt->register_element(new PhaseShifterElement(*$1, {*$2, *$3, *$4})); + delete $1; + delete $2; + delete $3; + delete $4; + } +; + +element.mzi: T_ELEM_MZI net.oa.in net.oa.in net.oa.out net.oa.out net.eanalog + { + $$ = cur_pt->register_element(new MZIElement(*$1, {*$2, *$3, *$4, *$5, *$6})); + delete $1; + delete $2; + delete $3; + delete $4; + delete $5; + delete $6; + } +; + +element.crossing: T_ELEM_CROSSING net.oa.in net.oa.in net.oa.out net.oa.out + { + $$ = cur_pt->register_element(new CrossingElement(*$1, {*$2, *$3, *$4, *$5})); + delete $1; + delete $2; + delete $3; + delete $4; + delete $5; + } +; + +element.pcm_cell: T_ELEM_PCMCELL net.oa.in net.oa.out + { + $$ = cur_pt->register_element(new PCMCellElement(*$1, {*$2, *$3})); + delete $1; + delete $2; + delete $3; + } +; + +element.cwsrc: T_ELEM_CWSRC net.oa.out + { + $$ = cur_pt->register_element(new CWSourceElement(*$1, {*$2})); + delete $1; + delete $2; + } +; + +element.vlsrc: T_ELEM_VLSRC net.oa.out + { + $$ = cur_pt->register_element(new VLSourceElement(*$1, {*$2})); + delete $1; + delete $2; + } +; + +element.evlsrc: T_ELEM_EVLSRC net.eanalog + { + $$ = cur_pt->register_element(new EVLSourceElement(*$1, {*$2})); + delete $1; + delete $2; + } +; + +element.probe: T_ELEM_PROBE net.oa.in + { + $$ = cur_pt->register_element(new ProbeElement(*$1, {*$2})); + delete $1; + delete $2; + } +; + +element.mlprobe: T_ELEM_MLPROBE net.oa.in + { + $$ = cur_pt->register_element(new MLProbeElement(*$1, {*$2})); + delete $1; + delete $2; + } +; + +element.pdet: T_ELEM_PDET net.oa.in net.eanalog + { + $$ = cur_pt->register_element(new PhotodetectorElement(*$1, {*$2, *$3})); + delete $1; + delete $2; + delete $3; + } +; + +element.x: T_ELEM_X + { + $$ = cur_pt->register_element(new XElement(*$1)); + delete $1; + } +; + +/* --------- Analyses definitions parsing ----------- */ + +analysis.op: T_ANALYSIS_OP + { $$ = cur_pt->register_analysis(new OPAnalysis()); } +; + +analysis.dc: T_ANALYSIS_DC + { $$ = cur_pt->register_analysis(new DCAnalysis()); } + | analysis.dc cw_sweep_order + { + auto ana = dynamic_cast<DCAnalysis *>(cur_pt->analyses[$1]); + if (ana->sweep_orders.size()) + { + cerr << "Registering more than one DC sweep is not supported yet." << endl; + exit(1); + } + ana->register_sweep_order(*$2); + delete $2; + } +; + +analysis.tran: T_ANALYSIS_TRAN + { $$ = cur_pt->register_analysis(new TRANAnalysis()); } +; + + +/* ---------- Directives arguments parsing ----------- */ + +atomdirective: directive.options { $$ = $1; } + | directive.nodeset { $$ = $1; } +; + +directive.with_args: + directive.with_args variable + { + // cout << "found positional arg: " << $2->get_str() << endl; + if (!cur_pt->directives[$1]->kwargs.empty()) + yyerror(scanner, pt, "positional arguments cannot follow keyword arguments"); + cur_pt->directives[$1]->args.emplace_back(*$2); + $$ = $1; + delete $2; + } +| atomdirective { $$ = $1; } +; + +directive.with_kwargs: + directive.with_kwargs assignment + { + // cout << "found keyword arg: " << $2->second.get_str() << endl; + cur_pt->directives[$1]->kwargs[$2->first] = $2->second; + $$ = $1; + delete $2; + } +| directive.with_args +; + +directive: directive.with_kwargs +; + +/* --------- Elements arguments parsing ----------- */ + +atomelement: element.wg { $$ = $1; } + | element.merger { $$ = $1; } + | element.splitter { $$ = $1; } + | element.coupler { $$ = $1; } + | element.pshift { $$ = $1; } + | element.mzi { $$ = $1; } + | element.crossing { $$ = $1; } + | element.pcm_cell { $$ = $1; } + | element.cwsrc { $$ = $1; } + | element.vlsrc { $$ = $1; } + | element.evlsrc { $$ = $1; } + | element.probe { $$ = $1; } + | element.mlprobe { $$ = $1; } + | element.pdet { $$ = $1; } +; + +element.with_args: + element.with_args variable + { + // cout << "found positional arg: " << $2->get_str() << endl; + if (!cur_pt->elements[$1]->kwargs.empty()) + yyerror(scanner, pt, "positional arguments cannot follow keyword arguments"); + cur_pt->elements[$1]->args.emplace_back(*$2); + $$ = $1; + + // TODO: for X element only, nets are stored as args + // Xnnnn n1 n2 n3 ... sub_name **sub_kwargs + // because the number of nets is not known when reading n1 n2 n3... + // [n1 n2 n3 ... subname] are also args + // when the time an arg is found, the previous one (if it exists), can be considered a net + // and therefore added to the element's nets array and discarded from args + // this will ensure that args will contain only [sub_name] + // for this to work, the X element cannot have args beyond sub_name (only kwargs) + if (cur_pt->elements[$1]->args.size() == 2) + { + // check if the args[0] is a valid net name + // create net with name args[0] (by default with type NONE) + // add args[0] to nets + // delete args[0] from args + } + + delete $2; + } +| atomelement { $$ = $1; } +; + +element.with_kwargs: + element.with_kwargs assignment + { + // cout << "found keyword arg: " << $2->second.get_str() << endl; + cur_pt->elements[$1]->kwargs[$2->first] = $2->second; + $$ = $1; + delete $2; + } +| element.with_args +; + +element.x.with_args: + element.x.with_args net_name_base + { + // cout << "found positional arg: " << $2->get_str() << endl; + if (!cur_pt->elements[$1]->kwargs.empty()) + yyerror(scanner, pt, "positional arguments cannot follow keyword arguments"); + cur_pt->elements[$1]->args.emplace_back(Variable(*$2)); + $$ = $1; + + // TODO: for X element only, nets are stored as args + // Xnnnn n1 n2 n3 ... sub_name **sub_kwargs + // because the number of nets is not known when reading n1 n2 n3... + // [n1 n2 n3 ... subname] are also args + // when the time an arg is found, the previous one (if it exists), can be considered a net + // and therefore added to the element's nets array and discarded from args + // this will ensure that args will contain only [sub_name] + // for this to work, the X element cannot have args beyond sub_name (only kwargs) + if (cur_pt->elements[$1]->args.size() == 2) + { + // check if the args[0] is a valid net name + // create net with name args[0] (by default with type NONE) + // add args[0] to nets + // delete args[0] from args + } + + delete $2; + } +| element.x { $$ = $1; } +; + +element.x.with_kwargs: + element.x.with_kwargs assignment + { + // cout << "found keyword arg: " << $2->second.get_str() << endl; + cur_pt->elements[$1]->kwargs[$2->first] = $2->second; + $$ = $1; + delete $2; + } +| element.x.with_args +; + +element: + element.with_kwargs +| element.x.with_kwargs +; + +/* ---------- Analysis arguments parsing ----------- */ + +atomanalysis: analysis.op { $$ = $1; } + | analysis.dc { $$ = $1; } + | analysis.tran { $$ = $1; } +; + +analysis.with_args: + analysis.with_args variable + { + // cout << "found positional arg: " << $2->get_str() << endl; + if (!cur_pt->analyses[$1]->kwargs.empty()) + yyerror(scanner, pt, "positional arguments cannot follow keyword arguments"); + cur_pt->analyses[$1]->args.emplace_back(*$2); + $$ = $1; + delete $2; + } +| atomanalysis { $$ = $1; } +; + +analysis.with_kwargs: + analysis.with_kwargs assignment + { + // cout << "found keyword arg: " << $2->second.get_str() << endl; + cur_pt->analyses[$1]->kwargs[$2->first] = $2->second; + $$ = $1; + delete $2; + } +| analysis.with_args +; + +analysis: analysis.with_kwargs + +/* --------- NET type parsing ----------- */ + +net.oanalog: net_name + { + bool ok = cur_pt->nets[*$1].setType(ParseNet::OANALOG); + if (!ok) + { + stringstream ret; + ret << "Error creating net '" + *$1 + "': net already exists with a different type" << endl; + ret << "\t (new type: " << "OANALOG" << ", old type: " << cur_pt->nets[*$1].type_str() << ")" << endl; + yyerror(scanner, pt, ret.str().c_str()); + } + cur_pt->nets[*$1].m_ports_count++; + $$ = $1; + } +; + +net.oa.explicit_bidir: + net.oanalog '&' + { + // this net will be both written to and read from by the new device + // so increment both reader and writer count + // and set the explicit "bidirectional" flag to true + cur_pt->nets[*$1].m_bidirectional = true; + cur_pt->nets[*$1].m_readers_count++; + cur_pt->nets[*$1].m_writers_count++; + $$ = $1; + } +; + +net.oa.bidir: + net.oa.explicit_bidir +| net.oanalog + { + // this net will be both written to and read from by the new device + // so increment both reader and writer count + cur_pt->nets[*$1].m_readers_count++; + cur_pt->nets[*$1].m_writers_count++; + $$ = $1; + } +; + +net.oa.in: + net.oanalog + { + // this net will only be read from by the new device + // so increment only reader count + cur_pt->nets[*$1].m_readers_count++; + $$ = $1; + } +| net.oa.explicit_bidir + { + // bidir already got a writer and reader increment, but + // this net will only be read from by the new device + // so decrement writer count + cur_pt->nets[*$1].m_writers_count--; + $$ = $1; + } +; + +net.oa.out: + net.oanalog + { + // this net will only be written to by the new device + // so increment only writer count + cur_pt->nets[*$1].m_writers_count++; + $$ = $1; + } +| net.oa.explicit_bidir + { + // bidir already got a writer and reader increment, but + // this net will only be written to by the new device + // so decrement reader count + cur_pt->nets[*$1].m_readers_count--; + $$ = $1; + } +; + +net.eanalog: net_name + { + bool ok = cur_pt->nets[*$1].setType(ParseNet::EANALOG); + if (!ok) + { + stringstream ret; + ret << "Error creating net '" + *$1 + "': net already exists with a different type" << endl; + ret << "\t (new type: " << "EANALOG" << ", old type: " << cur_pt->nets[*$1].type_str() << ")" << endl; + yyerror(scanner, pt, ret.str().c_str()); + } + $$ = $1; + } + +net.edigital: net_name + { + bool ok = cur_pt->nets[*$1].setType(ParseNet::EDIGITAL); + if (!ok) + { + stringstream ret; + ret << "Error creating net '" + *$1 + "': net already exists with a different type" << endl; + ret << "\t (new type: " << "EDIGITAL" << ", old type: " << cur_pt->nets[*$1].type_str() << ")"; + yyerror(scanner, pt, ret.str().c_str()); + } + $$ = $1; + } +; + +/* --------- BUS type parsing ----------- */ + +/* +bus.oanalog: bus_name + { + cur_pt->nets[*$1].m_type = ParseNet::OANALOG; + $$ = $1; + } +; + +bus.eanalog: bus_name + { + cur_pt->nets[*$1].m_type = ParseNet::EANALOG; + $$ = $1; + } +; + +bus.edigital: bus_name + { + cur_pt->nets[*$1].m_type = ParseNet::EDIGITAL; + $$ = $1; + } +; +bus: bus.oanalog { $$ = $1; } + | bus.eanalog { $$ = $1; } + | bus.edigital { $$ = $1; } +; +*/ +/* --------- NET and BUS name parsing ----------- */ + +net_name.base.str: + T_STR { $$ = $1; } + | '/' T_STR + { + $$ = $2; + *$2 = "/" + *$2; + } + | '/' T_INT + { + stringstream ss; + ss << "/" << $2; + $$ = new string(ss.str()); + } + | net_name.base.str '-' T_STR + { + $$ = $1; + *$1 += "-" + *$3; + delete $3; + } +; + +net_name_base: T_INT { $$ = new string(ParseNet::name_from_id($1)); } + | net_name.base.str { $$ = $1; } +; + +net_name: net_name_base + { + $$ = new string(cur_pt->get_or_create_net(*$1)); + delete $1; + } +; + +/* +bus_name: net_name { $$ = $1; } + | net_name_base '<' T_INT '>' + { + $$ = new string(cur_pt->get_or_create_net(*$1, $3)); + delete $1; + } +; +*/ +port_name: net_name_base { $$ = $1; } +; + +/* --------- Assignment and variable ----------- */ + +netval_assignment: '/' net_name '/' T_STR '=' variable.delimited_expr + { + $$ = new pair<string, pair<string, Variable>>( + *$2, + pair<string, Variable>(*$4, *$6) + ); + delete $2; + delete $4; + delete $6; + } +; + +cw_sweep_order: element_attribute variable_base variable_base variable_base + { + // cout << $1->first << "->" << $1->second; + // cout << " = [" << $2->as_double(); + // cout << ":" << $4->as_double(); + // cout << ":" << $3->as_double() << "]" << endl; + $$ = new pair<pair<string, string>, vector<double>>(*$1, {$2->as_double(), $3->as_double(), $4->as_double()}); + delete $1; + delete $2; + delete $3; + delete $4; + } +; + +element_attribute: '/' T_STR '/' T_STR + { + // cout << *$2 << "->" << *$4 << endl; + $$ = new pair<string, string>(*$2,*$4); + delete $2; + delete $4; + } +; + +assignment: T_ASSIGN_ID '=' variable + { + $$ = new pair<string, Variable>(*$1, *$3); + delete $1; + delete $3; + } +; + +variable_base: + T_INT + { + $$ = new Variable($1); + } + | T_NUM + { + $$ = new Variable($1); + } + | T_NONE + { + $$ = new Variable(Variable::NONE); + } + | '{' T_STR '}' + { + $$ = new Variable(cur_pt->get_variable(*$2)); + delete $2; + } + | '"' T_STR '"' + { + $$ = new Variable(*$2); + delete $2; + } + | listvar.bound + { + $$ = $1; + } +; + +variable.delimited_expr: + '{' expr '}' + { + $$ = $2; + } +| variable_base; +; + +variable.free_expr: + expr + { + $$ = $1; + } +; + +variable: + variable.free_expr +; + +/* +variable.str_without_quotes: + T_STR + { + if (*$1 == "None") + $$ = new Variable(Variable::NONE); + else + $$ = new Variable(*$1); + delete $1; + } +| variable; +; +*/ + +variable_or_empty: + variable + | %empty + { + $$ = new Variable(Variable::NONE); + } +; + +/* ------------ Expression parsing ------------- */ + +constant: variable_base { $$ = $1; } +; + +expr: + expr '+' term { $$ = $1; *$$ += *$3; delete $3; } +| expr '-' term { $$ = $1; *$$ -= *$3; delete $3; } +| term { $$ = $1; } +; + +term: + term '*' fact { $$ = $1; *$$ *= *$3; delete $3; } +| term '/' fact { $$ = $1; *$$ /= *$3; delete $3; } +| fact { $$ = $1; } +; + +fact: + fact '^' pow { $$ = $1; *$$ ^= *$3; delete $3; } +| pow { $$ = $1; } +; + +pow: + constant +| '(' expr ')' { $$ = $2; } +; + +// --------------- variables list (elements can have different types) +listvar.tail: variable_or_empty + { + $$ = new Variable(Variable::LIST); + $$->vec.insert($$->vec.begin(), *$1); + delete $1; + } +; + +listvar.unbound: variable_or_empty ',' listvar.tail + { + $3->vec.insert($3->vec.begin(), *$1); + $$ = $3; + delete $1; + } + | variable_or_empty ',' listvar.unbound + { + $3->vec.insert($3->vec.begin(), *$1); + $$ = $3; + delete $1; + } +; + +listvar.bound: '[' listvar.tail ']' { $$ = $2; } + | '[' listvar.unbound ']' { $$ = $2; } +; + +%% + +int yyerror(yyscan_t scanner, ParseTree *pt, const char *err) +{ + (void)pt; + (void)scanner; + string token = yyget_text(scanner); + stringstream ss; + for (char c : token) + { + switch (c) + { + case '\r': + ss << "\\r"; + break; + case '\n': + ss << "\\n"; + break; + case '\t': + ss << "\\t"; + break; + case '\b': + ss << "\\b"; + break; + default: + ss << c; + break; + } + } + string token_escaped = ss.str(); + printf("-- Error in the netlist (line %u): %s\n", yyget_lineno(scanner), err); + printf("-- \"%s\"\n", token_escaped.c_str()); + //cerr << err << endl; + exit(1); +} |
