//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtOptItem::ParseOpt -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // void DtOptItem::ParseOpt(DtOptItem* Options, int NumOpt, int argc, char* argv[], list<wstring>& FreeArgs) { // First assign default values to all options for (int i=0; i<NumOpt; i++) { Options[i].m_Option.m_Type = Options[i].m_Type; switch (Options[i].m_Type) { case OPT_TYPE_BOOL: case OPT_TYPE_INT: Options[i].m_Option.m_IntValue = Options[i].m_IntValue; break; case OPT_TYPE_INT64: Options[i].m_Option.m_Int64Value = Options[i].m_Int64Value; break; case OPT_TYPE_DOUBLE: Options[i].m_Option.m_DoubleValue = Options[i].m_DoubleValue; break; case OPT_TYPE_STRING: break; case OPT_TYPE_STRING_LIST: Options[i].m_Option.m_Strings.clear(); Options[i].m_Option.m_IntValue = Options[i].m_IntValue; for (int j=0; j<Options[i].m_Option.m_IntValue; j++) Options[i].m_Option.m_Strings.push_back(wstring()); break; default: assert(false); } } bool CheckOptions = true; // And then parse the actual commandline arguments for (int i=1; i<argc; i++) { #ifdef WINBUILD if (CheckOptions && (argv[i][0]=='-' || argv[i][0]=='/')) #else if (CheckOptions && argv[i][0]=='-') #endif { if (argv[i][1] == '-') { CheckOptions = false; continue; } string OptName(argv[i] + 1); wstring WOptName(OptName.begin(), OptName.end()); int j; for (j=0; j<NumOpt; j++) { if (Options[j].m_Name != WOptName) continue; Options[j].m_Option.m_IsSet = true; if (Options[j].m_Type == OPT_TYPE_BOOL) { Options[j].m_Option.m_IntValue = true; break; } if (Options[j].m_Type == OPT_TYPE_STRING_LIST) { if (i == argc - Options[j].m_IntValue) throw DtOptException(L"Not enough arguments for command-line " L"option: -%ls (expected %d)", WOptName.c_str(), Options[j].m_IntValue); list<wstring>::iterator It=Options[j].m_Option.m_Strings.begin(); for (int k=0; k<Options[j].m_IntValue; k++) { string OptArg(argv[++i]); *It = wstring(OptArg.begin(), OptArg.end()); It++; } break; } if (i == argc - 1) throw DtOptException(L"Missing argument for command-line option: -%ls", WOptName.c_str()); string OptArg(argv[++i]); Options[j].m_Option.m_StrValue = wstring(OptArg.begin(), OptArg.end()); if (Options[j].m_Type == OPT_TYPE_DOUBLE) Options[j].ParseDoubleOpt(); else if (Options[j].m_Type == OPT_TYPE_INT) Options[j].ParseIntOpt(); else if (Options[j].m_Type == OPT_TYPE_INT64) Options[j].ParseInt64Opt(); break; } if (j == NumOpt) throw DtOptException(L"Unknown command-line option (-%ls) encountered", WOptName.c_str()); } else { string Opt(argv[i]); FreeArgs.push_back(wstring(Opt.begin(), Opt.end())); } } }
/* The main program. Parse the command line and do it... */ int main(int argc, char **argv) { static int version = 0; static int rpflag = 0; static int basisflag = 0; static int compress = 0; static int quiet = 0; static int statistics = 0; static int mhflag = 0; static struct s_options options[] = { {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."}, {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."}, {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."}, {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."}, {OPT_FSTR, "l", (char*)handle_l_option, "Set an output language (c, c++, d)."}, {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file"}, {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."}, {OPT_FLAG, "s", (char*)&statistics, "Print parser stats to standard output."}, {OPT_FLAG, "x", (char*)&version, "Print the version number."}, {OPT_FLAG,0,0,0} }; int i; struct lemon lem; OptInit(argv,options,stderr); if( version ){ printf("Lemon version 1.0\n"); exit(0); } if( OptNArgs()!=1 ){ ErrorMsg("lemon", LINENO_NONE, "Exactly one filename argument is required.\n"); exit(1); } memset(&lem, 0, sizeof(lem)); lem.errorcnt = 0; /* Initialize the machine */ Strsafe_init(); Symbol_init(); State_init(); lem.argv0 = argv[0]; lem.filename = OptArg(0); lem.basisflag = basisflag; Symbol_new("$"); lem.errsym = Symbol_new("error"); lem.errsym->useCnt = 0; /* Parse the input file */ Parse(&lem); if( lem.errorcnt ) exit(lem.errorcnt); if( lem.nrule==0 ){ ErrorMsg(lem.filename, LINENO_NONE, "Empty grammar.\n"); exit(1); } /* Count and index the symbols of the grammar */ lem.nsymbol = Symbol_count(); Symbol_new("{default}"); lem.symbols = Symbol_arrayof(); for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i; qsort(lem.symbols,lem.nsymbol+1,sizeof(struct symbol*), (int(*)())Symbolcmpp); for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i; for(i=1; isupper(lem.symbols[i]->name[0]); i++); lem.nterminal = i; /* Generate a reprint of the grammar, if requested on the command line */ if( rpflag ){ Reprint(&lem); }else{ /* Initialize the size for all follow and first sets */ SetSize(lem.nterminal+1); /* Find the precedence for every production rule (that has one) */ FindRulePrecedences(&lem); /* Compute the lambda-nonterminals and the first-sets for every ** nonterminal */ FindFirstSets(&lem); /* Compute all LR(0) states. Also record follow-set propagation ** links so that the follow-set can be computed later */ lem.nstate = 0; FindStates(&lem); lem.sorted = State_arrayof(); /* Tie up loose ends on the propagation links */ FindLinks(&lem); /* Compute the follow set of every reducible configuration */ FindFollowSets(&lem); /* Compute the action tables */ FindActions(&lem); /* Compress the action tables */ if( compress==0 ) CompressTables(&lem); /* Reorder and renumber the states so that states with fewer choices ** occur at the end. */ ResortStates(&lem); /* Generate a report of the parser generated. (the "y.output" file) */ if( !quiet ) ReportOutput(&lem); /* Generate the source code for the parser */ ReportTable(&lem, mhflag); /* Produce a header file for use by the scanner. (This step is ** omitted if the "-m" option is used because makeheaders will ** generate the file for us.) */ if (! mhflag && language != LANG_D) ReportHeader(&lem); } if( statistics ){ LogMsg(LOGLEVEL_INFO, lem.filename, LINENO_NONE, "Parser statistics: %d terminals, %d nonterminals, %d rules\n", lem.nterminal, lem.nsymbol - lem.nterminal, lem.nrule); LogMsg(LOGLEVEL_INFO, lem.filename, LINENO_NONE, " %d states, %d parser table entries, %d conflicts\n", lem.nstate, lem.tablesize, lem.nconflict); } if( lem.nconflict ){ LogMsg(LOGLEVEL_WARNING, lem.filename, LINENO_NONE, "%d parsing conflicts.\n", lem.nconflict); } exit(lem.errorcnt + lem.nconflict); return (lem.errorcnt + lem.nconflict); }