Pol  Revision:cb584c9
eprog2.cpp
Go to the documentation of this file.
1 
7 #include <stdio.h>
8 #include <string.h>
9 #include <string>
10 
11 #include "../clib/clib.h"
12 #include "../clib/logfacility.h"
13 #include "../clib/passert.h"
14 #include "../clib/rawtypes.h"
15 #include "../clib/stlutil.h"
16 #include "compctx.h"
17 // EPROG compiler-only functions
18 #include "eprog.h"
19 #include "filefmt.h"
20 #include "fmodule.h"
21 #include "symcont.h"
22 #include "token.h"
23 #include "tokens.h"
24 #include "userfunc.h"
25 
26 namespace Pol
27 {
28 namespace Bscript
29 {
30 extern int include_debug;
31 
33 {
34  tokens.erase();
35  symbols.erase();
36  nglobals = 0;
37  dbg_filenum.clear();
38  dbg_linenum.clear();
39  globalvarnames.clear();
40  blocks.clear();
41  dbg_functions.clear();
42  dbg_ins_blocks.clear();
43  dbg_ins_statementbegin.clear();
44 }
45 
47 {
48  if ( token.dbg_filenum != 0 )
49  {
50  curfile = token.dbg_filenum;
51  curline = token.dbg_linenum;
52  }
53 }
54 
56 {
57  dbg_filenum.push_back( curfile );
58  dbg_linenum.push_back( curline );
59  dbg_ins_blocks.push_back( curblock );
61  statementbegin = false;
62  passert( tokens.count() == dbg_filenum.size() );
63 }
64 
66 {
67  curfile = ctx.dbg_filenum;
68  curline = ctx.line;
69 }
70 
71 void EScriptProgram::append( const StoredToken& stoken )
72 {
73  tokens.append_tok( stoken, 0 );
74 
76 }
77 
78 void EScriptProgram::append( const StoredToken& stoken, unsigned* posn )
79 {
80  tokens.append_tok( stoken, posn );
81 
83 }
84 
85 void EScriptProgram::append( const StoredToken& stoken, const CompilerContext& ctx )
86 {
87  tokens.append_tok( stoken, 0 );
88 
89  setcontext( ctx );
90 
92 }
93 
94 void EScriptProgram::append( const StoredToken& stoken, const CompilerContext& ctx, unsigned* posn )
95 {
96  tokens.append_tok( stoken, posn );
97 
98  setcontext( ctx );
99 
101 }
102 
103 void EScriptProgram::addToken( const Token& token )
104 {
105  unsigned tokpos = 0;
106  if ( token.id > 255 )
107  {
108  throw std::runtime_error( "Trying to write an illegal token" );
109  }
110 
111  update_dbg_pos( token );
112 
113  switch ( token.type )
114  {
115  case TYP_OPERAND: // is variable name, long, double, string lit
116  {
117  unsigned sympos = 0;
118  BTokenType type = token.type;
119  switch ( token.id )
120  {
121  case TOK_LONG:
122  symbols.append( token.lval, sympos );
123  break;
124  case TOK_DOUBLE:
125  symbols.append( token.dval, sympos );
126  break;
127  case TOK_STRING: // string literal
128  symbols.append( token.tokval(), sympos );
129  break;
130  case INS_ADDMEMBER2:
132  case TOK_IDENT: // unclassified (ick)
133  symbols.append( token.tokval(), sympos );
134  break;
135  case TOK_GLOBALVAR:
136  case TOK_LOCALVAR:
137  sympos = token.lval;
138  break;
139  case TOK_FUNCREF:
140  // num params in type
141  type = static_cast<BTokenType>( token.userfunc->parameters.size() );
142  default:
143  break;
144  }
145  tokens.append_tok( StoredToken( token.module, token.id, type, sympos ), &tokpos );
146  if ( token.id == TOK_FUNCREF )
147  token.userfunc->forward_callers.push_back( tokpos );
148  }
149  break;
150 
151  case TYP_USERFUNC: // these don't do anything.
152  return;
153 
154  case TYP_METHOD:
155  {
156  if ( token.id != INS_CALL_METHOD_ID )
157  {
158  unsigned sympos = 0;
159  passert( token.tokval() );
160 
161  symbols.append( token.tokval(), sympos );
162 
164  StoredToken(
165  token.module, token.id,
166  static_cast<BTokenType>(
167  token.lval ), // # of params, stored in Token.lval, saved in StoredToken.type
168  sympos ),
169  &tokpos );
170  }
171  else
172  {
173  tokens.append_tok( StoredToken( token.module, token.id, static_cast<BTokenType>( token.lval ),
174  static_cast<unsigned>( token.dval ) ),
175  &tokpos );
176  }
177  }
178  break;
179  case TYP_FUNC:
180  {
181  unsigned sympos = 0;
182  if ( include_debug )
183  {
184  if ( token.tokval() )
185  symbols.append( token.tokval(), sympos );
186  }
188  StoredToken(
189  token.module, token.id,
190  static_cast<BTokenType>(
191  token.lval ), // function index, stored in Token.lval, saved in StoredToken.type
192  sympos ),
193  &tokpos );
194  }
195  break;
196 
197  case TYP_RESERVED:
198  case TYP_OPERATOR:
199  case TYP_UNARY_OPERATOR:
200  if ( token.id == TOK_ARRAY_SUBSCRIPT )
201  {
202  // array subscript operators store their
203  // array index number in offset
204  tokens.append_tok( StoredToken( token.module, token.id, token.type, token.lval ) );
205  }
206  else if ( token.id == INS_GET_MEMBER || token.id == INS_SET_MEMBER ||
207  token.id == INS_SET_MEMBER_CONSUME )
208  {
209  unsigned sympos = 0;
210  symbols.append( token.tokval(), sympos );
211  tokens.append_tok( StoredToken( token.module, token.id, token.type, sympos ), &tokpos );
212  }
213  else
214  {
215  tokens.append_tok( StoredToken( token.module, token.id, token.type, token.lval ), &tokpos );
216  }
217  break;
218  case TYP_CONTROL:
219  switch ( token.id )
220  {
221  case CTRL_MAKELOCAL:
222  tokens.append_tok( StoredToken( token.module, token.id, token.type ) );
223  break;
224 
225  case CTRL_JSR_USERFUNC:
226  tokens.append_tok( StoredToken( token.module, token.id, token.type, 0 ), &tokpos );
227  token.userfunc->forward_callers.push_back( tokpos );
228  break;
229 
230  case INS_POP_PARAM_BYREF:
231  case INS_POP_PARAM:
232  {
233  unsigned sympos = 0;
234  symbols.append( token.tokval(), sympos );
235  tokens.append_tok( StoredToken( token.module, token.id, token.type, sympos ) );
236  }
237  break;
238 
239  default:
240  ERROR_PRINT << "AddToken: Can't handle TYP_CONTROL: " << token << "\n";
241  throw std::runtime_error( "Unexpected token in AddToken() (1)" );
242  break;
243  }
244  break;
245  default:
246  ERROR_PRINT << "AddToken: Can't handle " << token << "\n";
247  throw std::runtime_error( "Unexpected Token passed to AddToken() (2)" );
248  break;
249  }
250 
252 }
253 
254 int EScriptProgram::write( const char* fname )
255 {
256  EScriptProgram& program = *this;
257  FILE* fp = fopen( fname, "wb" );
258  if ( !fp )
259  return -1;
260 
261  BSCRIPT_FILE_HDR hdr;
262  hdr.magic2[0] = BSCRIPT_FILE_MAGIC0;
263  hdr.magic2[1] = BSCRIPT_FILE_MAGIC1;
264  hdr.version = ESCRIPT_FILE_VER_CURRENT; // auto-set to latest version (see filefmt.h)
265  hdr.globals = static_cast<unsigned short>( globalvarnames.size() );
266  fwrite( &hdr, sizeof hdr, 1, fp );
267 
268  BSCRIPT_SECTION_HDR sechdr;
269 
270  if ( haveProgram )
271  {
272  BSCRIPT_PROGDEF_HDR progdef_hdr;
273  memset( &progdef_hdr, 0, sizeof progdef_hdr );
274  sechdr.type = BSCRIPT_SECTION_PROGDEF;
275  sechdr.length = sizeof progdef_hdr;
276  fwrite( &sechdr, sizeof sechdr, 1, fp );
277  progdef_hdr.expectedArgs = expectedArgs;
278  fwrite( &progdef_hdr, sizeof progdef_hdr, 1, fp );
279  }
280 
281  for ( auto& module : program.modules )
282  {
283  sechdr.type = BSCRIPT_SECTION_MODULE;
284  sechdr.length = 0;
285  fwrite( &sechdr, sizeof sechdr, 1, fp );
286 
287  BSCRIPT_MODULE_HDR modhdr;
288  memset( &modhdr, 0, sizeof modhdr );
289  strzcpy( modhdr.modulename, module->modulename.get().c_str(), sizeof modhdr.modulename );
290  modhdr.nfuncs = static_cast<unsigned int>( module->used_functions.size() );
291  fwrite( &modhdr, sizeof modhdr, 1, fp );
292  for ( auto& module_func : module->used_functions )
293  {
295  memset( &func, 0, sizeof func );
296  passert( module_func->used );
297 
298  strzcpy( func.funcname, module_func->name.get().c_str(), sizeof func.funcname );
299  func.nargs = static_cast<unsigned char>( module_func->nargs );
300 
301  fwrite( &func, sizeof func, 1, fp );
302  }
303  }
304 
305  sechdr.type = BSCRIPT_SECTION_CODE;
306  sechdr.length = program.tokens.get_write_length();
307  fwrite( &sechdr, sizeof sechdr, 1, fp );
308  program.tokens.write( fp );
309 
310  sechdr.type = BSCRIPT_SECTION_SYMBOLS;
311  sechdr.length = program.symbols.get_write_length();
312  fwrite( &sechdr, sizeof sechdr, 1, fp );
313  program.symbols.write( fp );
314 
315  if ( !exported_functions.empty() )
316  {
319  sechdr.length = static_cast<unsigned int>( exported_functions.size() * sizeof bef );
320  fwrite( &sechdr, sizeof sechdr, 1, fp );
321  for ( auto& elem : exported_functions )
322  {
323  strzcpy( bef.funcname, elem.name.c_str(), sizeof bef.funcname );
324  bef.nargs = elem.nargs;
325  bef.PC = elem.PC;
326  fwrite( &bef, sizeof bef, 1, fp );
327  }
328  }
329 
330  fclose( fp );
331  return 0;
332 }
333 
334 
336 {
337  commit( prog );
338 }
339 
341 {
342  module_count = static_cast<unsigned int>( prog.modules.size() );
343  tokens_count = prog.tokens.count();
344  symbols_length = prog.symbols.length();
345  sourcelines_count = static_cast<unsigned int>( prog.sourcelines.size() );
346  fileline_count = static_cast<unsigned int>( prog.fileline.size() );
347 }
348 
349 unsigned EScriptProgram::varcount( unsigned block )
350 {
351  unsigned cnt = static_cast<unsigned int>( blocks[block].localvarnames.size() );
352  if ( block != 0 )
353  {
354  cnt += varcount( blocks[block].parentblockidx );
355  }
356  return cnt;
357 }
358 unsigned EScriptProgram::parentvariables( unsigned parent )
359 {
360  unsigned cnt = 0;
361  if ( parent != 0 )
362  {
363  cnt = blocks[parent].parentvariables + parentvariables( blocks[parent].parentblockidx );
364  }
365  return cnt;
366 }
367 int EScriptProgram::write_dbg( const char* fname, bool gen_txt )
368 {
369  FILE* fp = fopen( fname, "wb" );
370  if ( !fp )
371  return -1;
372 
373  FILE* fptext = NULL;
374  if ( gen_txt )
375  fptext = fopen( ( std::string( fname ) + ".txt" ).c_str(), "wt" );
376 
377  u32 count;
378 
379  // just a version number
380  count = 3;
381  fwrite( &count, sizeof count, 1, fp );
382 
383  count = static_cast<unsigned int>( dbg_filenames.size() );
384  fwrite( &count, sizeof count, 1, fp );
385  for ( unsigned i = 0; i < dbg_filenames.size(); ++i )
386  {
387  if ( fptext )
388  fprintf( fptext, "File %u: %s\n", i, dbg_filenames[i].c_str() );
389  count = static_cast<unsigned int>( dbg_filenames[i].size() + 1 );
390  fwrite( &count, sizeof count, 1, fp );
391  fwrite( dbg_filenames[i].c_str(), count, 1, fp );
392  }
393  count = static_cast<unsigned int>( globalvarnames.size() );
394  fwrite( &count, sizeof count, 1, fp );
395  for ( unsigned i = 0; i < globalvarnames.size(); ++i )
396  {
397  if ( fptext )
398  fprintf( fptext, "Global %u: %s\n", i, globalvarnames[i].c_str() );
399  count = static_cast<unsigned int>( globalvarnames[i].size() + 1 );
400  fwrite( &count, sizeof count, 1, fp );
401  fwrite( globalvarnames[i].c_str(), count, 1, fp );
402  }
403  count = tokens.count();
404  fwrite( &count, sizeof count, 1, fp );
405  for ( unsigned i = 0; i < tokens.count(); ++i )
406  {
407  if ( fptext )
408  fprintf( fptext, "Ins %u: File %u, Line %u, Block %u %s\n", i, dbg_filenum[i], dbg_linenum[i],
409  dbg_ins_blocks[i], ( dbg_ins_statementbegin[i] ? "StatementBegin" : "" ) );
411  ins.filenum = dbg_filenum[i];
412  ins.linenum = dbg_linenum[i];
413  ins.blocknum = dbg_ins_blocks[i];
414  ins.statementbegin = dbg_ins_statementbegin[i] ? 1 : 0;
415  ins.rfu1 = 0;
416  ins.rfu2 = 0;
417  fwrite( &ins, sizeof ins, 1, fp );
418  }
419  count = static_cast<unsigned int>( blocks.size() );
420  fwrite( &count, sizeof count, 1, fp );
421  for ( unsigned i = 0; i < blocks.size(); ++i )
422  {
423  const EPDbgBlock& block = blocks[i];
424  if ( fptext )
425  {
426  fprintf( fptext, "Block %u:\n", i );
427  fprintf( fptext, " Parent block: %u\n", block.parentblockidx );
428  }
429 
430  u32 tmp;
431  tmp = block.parentblockidx;
432  fwrite( &tmp, sizeof tmp, 1, fp );
433  tmp = block.parentvariables;
434  fwrite( &tmp, sizeof tmp, 1, fp );
435 
436  count = static_cast<unsigned int>( block.localvarnames.size() );
437  fwrite( &count, sizeof count, 1, fp );
438 
439  unsigned int varfirst = block.parentvariables;
440  unsigned int varlast = static_cast<unsigned int>( varfirst + block.localvarnames.size() - 1 );
441  if ( varlast >= varfirst )
442  {
443  if ( fptext )
444  fprintf( fptext, " Local variables %u-%u: \n", varfirst, varlast );
445  for ( unsigned j = 0; j < block.localvarnames.size(); ++j )
446  {
447  std::string varname = block.localvarnames[j];
448  if ( fptext )
449  fprintf( fptext, " %u: %s\n", varfirst + j, varname.c_str() );
450 
451  count = static_cast<unsigned int>( varname.size() + 1 );
452  fwrite( &count, sizeof count, 1, fp );
453  fwrite( varname.c_str(), count, 1, fp );
454  }
455  }
456  }
457  count = static_cast<unsigned int>( dbg_functions.size() );
458  fwrite( &count, sizeof count, 1, fp );
459  for ( unsigned i = 0; i < dbg_functions.size(); ++i )
460  {
461  const EPDbgFunction& func = dbg_functions[i];
462  if ( fptext )
463  {
464  fprintf( fptext, "Function %u: %s\n", i, func.name.c_str() );
465  fprintf( fptext, " FirstPC=%u, lastPC=%u\n", func.firstPC, func.lastPC );
466  }
467  count = static_cast<unsigned int>( func.name.size() + 1 );
468  fwrite( &count, sizeof count, 1, fp );
469  fwrite( func.name.c_str(), count, 1, fp );
470  u32 tmp;
471  tmp = func.firstPC;
472  fwrite( &tmp, sizeof tmp, 1, fp );
473  tmp = func.lastPC;
474  fwrite( &tmp, sizeof tmp, 1, fp );
475  }
476 
477  if ( fptext )
478  fclose( fptext );
479  fptext = NULL;
480  fclose( fp );
481  fp = NULL;
482 
483  return 0;
484 }
485 
486 int EScriptProgram::add_dbg_filename( const std::string& filename )
487 {
488  for ( unsigned i = 0; i < dbg_filenames.size(); ++i )
489  {
490  if ( dbg_filenames[i] == filename )
491  return i;
492  }
493 
494  // file 0 is nothing
495  if ( dbg_filenames.empty() )
496  dbg_filenames.push_back( "" );
497 
498  dbg_filenames.push_back( filename );
499  return static_cast<int>( dbg_filenames.size() - 1 );
500 }
501 
502 std::string EScriptProgram::dbg_get_instruction( size_t atPC ) const
503 {
504  OSTRINGSTREAM os;
505  os << instr[atPC].token;
506  return OSTRINGSTREAM_STR( os );
507 }
508 
509 
511 {
512  statementbegin = true;
513 }
515 {
517  curblock = 0;
518 }
520 {
522 }
524 {
525  EPDbgBlock block;
526  if ( blocks.empty() )
527  {
528  block.parentblockidx = 0;
529  block.parentvariables = 0;
530  blocks.push_back( block );
531  curblock = 0;
532  }
533 
534  block.parentblockidx = curblock;
535  block.parentvariables = varcount( curblock );
536 
537  curblock = static_cast<unsigned int>( blocks.size() );
538  blocks.push_back( block );
539 }
541 {
542  passert( curblock );
543  bool remove = blocks[curblock].localvarnames.empty() && curblock == blocks.size() - 1;
544  curblock = blocks[curblock].parentblockidx;
545  if ( remove )
546  {
547  blocks.pop_back();
548  for ( auto& elem : dbg_ins_blocks )
549  {
550  if ( elem >= blocks.size() )
551  elem = curblock;
552  }
553  }
554 }
555 void EScriptProgram::addlocalvar( const std::string& localvarname )
556 {
557  blocks[curblock].localvarnames.push_back( localvarname );
558 }
559 void EScriptProgram::addfunction( std::string funcname, unsigned firstPC, unsigned lastPC )
560 {
561  EPDbgFunction func;
562  func.name = funcname;
563  func.firstPC = firstPC;
564  func.lastPC = lastPC;
565  dbg_functions.push_back( func );
566 }
567 
569 {
570  size_t size = sizeof( EScriptProgram ) + program_decl.capacity();
571  size += 3 * sizeof( std::string* ) + sourcelines.capacity() * sizeof( std::string );
572  for ( const auto& l : sourcelines )
573  size += l.capacity();
574  size += 3 * sizeof( std::string* ) + fileline.capacity() * sizeof( std::string );
575  for ( const auto& l : fileline )
576  size += l.capacity();
577  size += 3 * sizeof( std::string* ) + function_decls.capacity() * sizeof( std::string );
578  for ( const auto& l : function_decls )
579  size += l.capacity();
580  size += 3 * sizeof( std::string* ) + globalvarnames.capacity() * sizeof( std::string );
581  for ( const auto& l : globalvarnames )
582  size += l.capacity();
583  size += 3 * sizeof( std::string* ) + dbg_filenames.capacity() * sizeof( std::string );
584  for ( const auto& l : dbg_filenames )
585  size += l.capacity();
586  size += 3 * sizeof( unsigned* ) + dbg_filenum.capacity() * sizeof( unsigned );
587  size += 3 * sizeof( unsigned* ) + dbg_linenum.capacity() * sizeof( unsigned );
588  size += 3 * sizeof( unsigned* ) + dbg_ins_blocks.capacity() * sizeof( unsigned );
589  size += 3 * sizeof( bool* ) + dbg_ins_statementbegin.capacity() * sizeof( bool );
590 
591  size += 3 * sizeof( FunctionalityModule** ) + modules.capacity() * sizeof( FunctionalityModule* );
592  size += 3 * sizeof( EPExportedFunction* ) +
593  exported_functions.capacity() * sizeof( EPExportedFunction );
594 
595 
596  size += 3 * sizeof( Instruction* ) + instr.capacity() * sizeof( Instruction );
597 
598  size += 3 * sizeof( EPDbgBlock* ) + blocks.capacity() * sizeof( EPDbgBlock );
599  size += 3 * sizeof( EPDbgFunction* ) + dbg_functions.capacity() * sizeof( EPDbgFunction );
600 
601  return size;
602 }
603 }
604 }
std::vector< unsigned > dbg_ins_blocks
Definition: eprog.h:141
void append_tok(const StoredToken &token, unsigned *position=NULL)
Definition: symcont.cpp:170
unsigned parentvariables
Definition: eprog.h:57
void setcontext(const CompilerContext &ctx)
Definition: eprog2.cpp:65
int include_debug
Definition: eprog2.cpp:30
BTokenType type
Definition: token.h:40
#define ESCRIPT_FILE_VER_CURRENT
Definition: filefmt.h:44
std::vector< bool > dbg_ins_statementbegin
Definition: eprog.h:142
const char * tokval() const
Definition: token.h:71
#define BSCRIPT_FILE_MAGIC0
Definition: filefmt.h:21
BTokenId id
Definition: token.h:39
std::vector< EPExportedFunction > exported_functions
Definition: eprog.h:117
unsigned short globals
Definition: filefmt.h:50
SymbolContainer symbols
Definition: eprog.h:94
#define OSTRINGSTREAM_STR(x)
Definition: stlutil.h:76
void addfunction(std::string name, unsigned firstPC, unsigned lastPC)
Definition: eprog2.cpp:559
int write(const char *fname)
Definition: eprog2.cpp:254
virtual void write(FILE *fp)
Definition: symcont.cpp:117
unsigned parentvariables(unsigned parent)
Definition: eprog2.cpp:358
std::vector< EPDbgFunction > dbg_functions
Definition: eprog.h:135
unsigned int u32
Definition: rawtypes.h:27
int add_dbg_filename(const std::string &filename)
Definition: eprog2.cpp:486
unsigned short version
Definition: filefmt.h:49
EScriptProgramCheckpoint(const EScriptProgram &)
Definition: eprog2.cpp:335
unsigned int get_write_length() const
Definition: symcont.cpp:125
std::vector< std::string > globalvarnames
Definition: eprog.h:133
#define BSCRIPT_FILE_MAGIC1
Definition: filefmt.h:22
void commit(const EScriptProgram &prog)
Definition: eprog2.cpp:340
std::vector< std::string > dbg_filenames
Definition: eprog.h:136
void append(const char *string, unsigned &position)
Definition: symcont.cpp:80
std::vector< std::string > fileline
Definition: eprog.h:114
unsigned count(void) const
Definition: symcont.h:94
std::vector< std::string > sourcelines
Definition: eprog.h:113
#define OSTRINGSTREAM
Definition: stlutil.h:75
std::string dbg_get_instruction(size_t atPC) const
Definition: eprog2.cpp:502
#define passert(exp)
Definition: passert.h:62
std::vector< Instruction > instr
Definition: eprog.h:124
unsigned length(void) const
Definition: symcont.h:67
void update_dbg_pos(const Token &tkn)
Definition: eprog2.cpp:46
std::vector< EPDbgBlock > blocks
Definition: eprog.h:134
unsigned int count() const
Definition: refptr.h:130
std::vector< std::string > function_decls
Definition: eprog.h:115
StoredTokenContainer tokens
Definition: eprog.h:93
size_t sizeEstimate() const
Definition: eprog2.cpp:568
int write_dbg(const char *fname, bool gen_txt)
Definition: eprog2.cpp:367
std::vector< unsigned > dbg_linenum
Definition: eprog.h:140
std::vector< unsigned > dbg_filenum
Definition: eprog.h:139
unsigned parentblockidx
Definition: eprog.h:56
std::vector< std::string > localvarnames
Definition: eprog.h:58
void addlocalvar(const std::string &localvarname)
Definition: eprog2.cpp:555
unsigned char module
Definition: token.h:55
UserFunction * userfunc
Definition: token.h:52
#define strzcpy
Definition: clib.h:154
#define ERROR_PRINT
Definition: logfacility.h:230
unsigned varcount(unsigned block)
Definition: eprog2.cpp:349
void addToken(const Token &token)
Definition: eprog2.cpp:103
bool commit(const std::string &basename)
Definition: uimport.cpp:968
void append(const StoredToken &stoken)
Definition: eprog2.cpp:71
Definition: berror.cpp:12
std::vector< FunctionalityModule * > modules
Definition: eprog.h:92
std::string program_decl
Definition: eprog.h:112