@q file: testout_prog.w@> @q% Copyright Dave Bone 1998 - 2015@> @q% /*@> @q% This Source Code Form is subject to the terms of the Mozilla Public@> @q% License, v. 2.0. If a copy of the MPL was not distributed with this@> @q% file, You can obtain one at http://mozilla.org/MPL/2.0/.@> @q% */@> @** Define variables.\fbreak \ptindent{1) Holding file to start things off --- command line data is put into this file} \ptindent{2) Define the \O2's tracing variable by macro} \ptindent{3) \O2's token containers needed} @+= #define Max_buf_size 2*1024 std::string Holding_file("testout_holding_file.cmd"); std::string To_parse_file; YACCO2_define_trace_variables(); yacco2::TOKEN_GAGGLE JUNK_tokens; yacco2::TOKEN_GAGGLE IP_tokens; yacco2::TOKEN_GAGGLE Error_queue; @** Local Routines.\fbreak |GET_CMD_LINE| is a basic copy of |O2|'s command line routine. It is changed as it just fetches the file to process. There are no other parameters to deal with. Have a read and compare |O2|'s routine against this one to see the variances. \O2's routines are written up in |common_externs.pdf| in the ``./docs'' folder. |DUMP_ERROR_QUEUE| ditto's |O2|'s error processing routine. Testout's difference to \O2{} is the use of its own error handler grammar. This is due to the different T vocabulary defined over \O2's vocabulary. This was done to show u what u'll be doing for your own compiler development as your T vocabulary will definitely be different from \O2. Have a look at the |testout_err_hdlr| grammar and see how it resolves the external file associated with the error T. The Error T processing is basicly a template using your specific grammar relative to its own language/Terminal Vocabulary. As O2's |o2_error_hdlr.lex| grammar deals with its own specific errors, this is why there is not a generic error template grammar that uses only the \ALLshift{} to trace all the T errors as anonymous entities. One could do this but u'll find that this is not too creative. Look at |o2_error_hdlr.lex|'s subrule with tandom errors --- ``file-inclusion'' ``bad filename'' as an example. Your own error reporting is open to your own code and style to format and notification. U might want to compare |testout_terminals.T| and |testout_err_symbols.T| definitions against \O2's vocabulary: |yacco2_terminals.T| and |yacco2_err_symbols.T| to get a feel on the range of Tes within \O2. What they stand for, and the different definition templates used: canned to full \Cpp{} definition / implementation. @*1 |GET_CMD_LINE| --- go fetch the fodder.\fbreak To note: the ``File\_to\_parse'' parameter is passed in as a reference which gets filled with the command line input. The file's existence check is done and if it exists, downstream parsing uses it passed in reference variable for the input tok\_can container to parse its contents. @+= void GET_CMD_LINE(int argc,char*argv[]@/ ,const char*Holding@/ ,std::string& File_to_parse@/ ,yacco2::TOKEN_GAGGLE&Errors) { using namespace std; using namespace NS_testout_err_symbols; using namespace yacco2; ofstream ofile; ofile.open(Holding,ios_base::out|ios::trunc); if(!ofile){ CAbs_lr1_sym*sym= new Err_bad_filename(Holding); sym->set_external_file_id(1); sym->set_line_no(1); sym->set_pos_in_line(1); Errors.push_back(*sym); return; } if(argc==1){ char cmd_line[Max_buf_size]; cout<<"Please enter Command line to process: "; cin.get(cmd_line,Max_buf_size,'\n'); ofile< Cmd1_tokens(Holding);//sets the table of files controlled by yacco2 for parsing T gpsing ifstream ifile; ifile.open(File_to_parse.c_str()); if(!ifile){ CAbs_lr1_sym*sym= new Err_bad_filename(File_to_parse.c_str()); sym->set_external_file_id(1); sym->set_line_no(1); sym->set_pos_in_line(1); Errors.push_back(*sym); return; } ifile.close(); return; } @*1 |DUMP_ERROR_QUEUE| --- the teller of horror.\fbreak The 2 |yacco2::PTR_LR1_eog__| added to the end-of-the-container allows the grammar's |start_rule| to be accepted. @+= void DUMP_ERROR_QUEUE(yacco2::TOKEN_GAGGLE&Errors) { using namespace NS_yacco2_k_symbols; using namespace yacco2; Errors.push_back(*yacco2::PTR_LR1_eog__); Errors.push_back(*yacco2::PTR_LR1_eog__); using namespace NS_testout_err_hdlr; Ctestout_err_hdlr fsm; Parser pass_errors(fsm,&Errors,0); pass_errors.parse(); yacco2::Parallel_threads_shutdown(pass_errors); } @** Mainline.\fbreak The mainline code demonstrates various ways to do ``literate programming: a mixture of Literate programming code modules and standard ``c'' code. {\bf{Note}:} I checked the returned code from the parser |Parser::erred| as to whether a parse error occurred. This is the proper way to do things but u'll see my lazyness in \O2's program listing to just check the ``Error queue''. If u misused the |RSVP_FSM| macro from a monolithic grammar's |failed| directive to do this, the parser did abort, the |failed| directive fired but the ``Error queue'' is empty as the error T is placed within the ``Accept queue'' which is the context for a threaded grammar to return a result back to a calling grammar. To see that |failed| works within the monolithic context, use ``testout\_error.dat'' file as input. \fbreak {\bf{So be forwarned}}. I guess this should be checked for by \O2{} and to thrown an error when compiling the grammar but for the moment it does not. @+= int main(int argc, char* argv[]) { std::cout << "testout start" << std::endl; using namespace yacco2; @; @; using namespace NS_pager_1; tok_can cmd_line(To_parse_file.c_str()); Cpager_1 pager_1_fsm; Parser testout_parse(pager_1_fsm,&cmd_line,&IP_tokens,0,&Error_queue,&JUNK_tokens,0); if (testout_parse.parse() == Parser::erred){ std::cout << "===============>ERROR OCCURRED" << std::endl; @; } exit:@/ std::cout << "Exiting testout" << std::endl; return 0; } @*1 Some Programming sections. @*2 Turn on some of \O2's dynamic tracing variables.\fbreak Tracings:\fbreak \ptindent{T - terminals} \ptindent{TH - threads if their fsm-debug options turned on} \ptindent{MSG - messages between grammars} \ptindent{MU - trace mutex activity} Notice that MU was turned off but kept as a comment. Due to how |Cweb| deals with comments, the underscore ``\_'' must be escaped. Have a look in the ``testout\_prog.w'' file where u'll see this. You will not see any ``MSG'' or ``TH'' tracings as there was not a threaded grammar called. So why do u include them? Just to pique your interest to \O2's delights. @= yacco2::YACCO2_T__ = 1; yacco2::YACCO2_TH__ = 1; yacco2::YACCO2_MSG__ = 1; //yacco2::YACCO2\_MU\_TRACING\_\_ = 1; @*2 Get command line, parse it, and place contents into a holding file.\fbreak @= GET_CMD_LINE(argc,argv,Holding_file.c_str(),To_parse_file,Error_queue); @; @*2 Do we have errors?.\fbreak Check that error queue for those errors. Note, |DUMP_ERROR_QUEUE| will also flush out any launched threads for the good housekeeping or is it housetrained seal award? Trying to do my best in the realm of short lived winddowns. @= if(Error_queue.empty()!=true){ DUMP_ERROR_QUEUE(Error_queue); return 1; } @*1 Testout implementation.\fbreak Start the code output to |testout.cpp| by appending its include file. @(testout.cpp@>= @;