/*============================================================================= * parser for pseudo-Boolean instances * * Copyright (c) 2005-2007 Olivier ROUSSEL and Vasco MANQUINHO * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. *============================================================================= */ #include #include #include #ifdef useGMP #include typedef mpz_t IntegerType; #else #warning this IntegerType may not be suitable for some input file. Consider using GMP typedef long IntegerType; #endif /* * This section defines the callback that are used by the * parser to send data back to the program. * * These functions must be redefined by the user. */ /** * callback called when we get the number of variables and the * expected number of constraints * @param nbvar: the number of variables * @param nbconstr: the number of contraints */ void metaData(int nbvar, int nbconstr) { printf("[nbvar=%d]\n",nbvar); printf("[nbconstr=%d]\n",nbconstr); } /** * callback called before we read the objective function */ void beginObjective() { printf("objective: "); } /** * callback called after we've read the objective function */ void endObjective() { printf("\n"); } /** * callback called when we read a term of the objective function * * @param coeff: the coefficient of the term * @param var: the identifier of the variable */ void objectiveTerm(IntegerType coeff, char *var) { #ifdef useGMP gmp_printf("[%+Zd %s] ",coeff,var); #else printf("[%+d %s] ",coeff,var); #endif } /** * callback called before we read a constraint */ void beginConstraint() { printf("constraint: "); } /** * callback called after we've read a constraint */ void endConstraint() { printf("\n"); } /** * callback called when we read a term of a constraint * * @param coeff: the coefficient of the term * @param var: the identifier of the variable */ void constraintTerm(IntegerType coeff, char *var) { #ifdef useGMP gmp_printf("[%+Zd %s] ",coeff,var); #else printf("[%+d %s] ",coeff,var); #endif } /** * callback called when we read the relational operator of a constraint * * @param relop: the relational oerator (>= or =) */ void constraintRelOp(char *relop) { printf("[%s] ",relop); } /** * callback called when we read the right term of a constraint (also * known as the degree) * * @param val: the degree of the constraint */ void constraintRightTerm(IntegerType val) { #ifdef useGMP gmp_printf("[%+Zd] ",val); #else printf("[%+d] ",val); #endif } /* * private section * */ FILE *in; // the file we're reading from int nbVars,nbConstr; // MetaData: #Variables and #Constraints in file. /** * stop the program when an error is found * * @param msg: the error message */ void runtimeError(char *msg) { printf("Error: %s\n",msg); exit(1); } /** * get the next character from the stream */ char get() { return fgetc(in); } /** * put back a character into the stream (only one chr can be put back) */ void putback(char c) { ungetc(c,in); } /** * return 1 iff we've reached EOF */ int eof() { return feof(in); } /** * skip white spaces */ void skipSpaces() { char c; while(isspace(c=get())); putback(c); } /** * read an identifier from stream and store it in s * @param s: the variable to hold the identifier we read * @param len: the size of the buffer to hold the identifier * @return 1 iff an identifier was correctly read */ int readIdentifier(char *s, int len) { char c,*last=s+len-1; char* first = s; int varID; skipSpaces(); // first char (must be 'x') c=get(); if (eof()) return 0; if (c!='x') { putback(c); return 0; } *s++=c; //next chars (must be digits) while(s!=last) { c=get(); if (eof()) break; if (isdigit(c)) *s++=c; else { putback(c); break; } } *s=0; //Small check on the coefficient ID to make sure everything is ok sscanf(first+1,"%d", &varID); if (varID > nbVars) { runtimeError("Variable identifier larger than #variables in metadata."); } return 1; } /** * read a relational operator from stream and store it in s * @param s: the variable to hold the relational operator we read. Must be at lest 3 characters long. * @return 1 iff a relational operator was correctly read */ int readRelOp(char *s) { char c; skipSpaces(); c=get(); if (eof()) return 0; if (c=='=') { strcpy(s,"="); return 1; } if (c=='>' && get()=='=') { strcpy(s,">="); return 1; } return 0; } /** * read the first comment line to get the number of variables and * the number of constraints in the file * * calls metaData with the data that was read */ void readMetaData() { char c; char s[1024]; // get the number of variables and constraints c=get(); if (c!='*') runtimeError("First line of input file should be a comment"); fscanf(in,"%20s",s); if (eof() || strcmp(s,"#variable=")!=0) runtimeError("First line should contain #variable= as first keyword"); fscanf(in,"%d",&nbVars); fscanf(in,"%20s",s); if (eof() || strcmp(s,"#constraint=")!=0) runtimeError("First line should contain #constraint= as second keyword"); fscanf(in,"%d",&nbConstr); // skip the rest of the line fgets(s,sizeof(s),in); // callback to transmit the data metaData(nbVars,nbConstr); } /** * skip the comments at the beginning of the file */ void skipComments() { char s[1024]; char c; // skip further comments while(!eof() && (c=get())=='*') { fgets(s,sizeof(s),in); } putback(c); } /** * read a term into coeff and var * @param coeff: the coefficient of the variable * @param var: the indentifier we read * @param len: the size of the buffer to hold the identifier */ void readTerm(IntegerType *coeff, char *var, int len) { char c; #ifdef useGMP gmp_fscanf(in,"%Zd",*coeff); #else fscanf(in,"%d",coeff); #endif skipSpaces(); if (!readIdentifier(var,len)) runtimeError("identifier expected"); } /** * read the objective line (if any) * * calls beginObjective, objectiveTerm and endObjective */ void readObjective() { char c; char s[1024],var[1024]; IntegerType coeff; #ifdef useGMP mpz_init(coeff); #endif // read objective line (if any) skipSpaces(); c=get(); if (c!='m') { // no objective line putback(c); return; } if (get()=='i' && get()=='n' && get()==':') { beginObjective(); // callback while(!eof()) { readTerm(&coeff,var,sizeof(var)); objectiveTerm(coeff,var); // callback skipSpaces(); c=get(); if (c==';') break; // end of objective else if (c=='-' || c=='+' || isdigit(c)) putback(c); else runtimeError("unexpected character in objective function"); } endObjective(); } else runtimeError("input format error: 'min:' expected"); #ifdef useGMP mpz_clear(coeff); #endif } /** * read a constraint * * calls beginConstraint, constraintTerm and endConstraint */ void readConstraint() { char s[1024], var[1024]; char c; IntegerType coeff; #ifdef useGMP mpz_init(coeff); #endif beginConstraint(); while(!eof()) { readTerm(&coeff,var,sizeof(var)); constraintTerm(coeff,var); skipSpaces(); c=get(); if (c=='>' || c=='=') { // relational operator found putback(c); break; } else if (c=='-' || c=='+' || isdigit(c)) putback(c); else runtimeError("unexpected character in constraint"); } if (eof()) runtimeError("unexpected EOF before end of constraint"); if (readRelOp(s)) constraintRelOp(s); else runtimeError("unexpected relational operator in constraint"); #ifdef useGMP gmp_fscanf(in,"%Zd",coeff); #else fscanf(in,"%d",&coeff); #endif constraintRightTerm(coeff); skipSpaces(); c=get(); if (eof() || c!=';') runtimeError("semicolon expected at end of constraint"); endConstraint(); #ifdef useGMP mpz_clear(coeff); #endif } /* * public section * */ /** * parses the file and uses the callbacks to send to send the data * back to the program * * @param filename: the file to parse */ void parse(char *filename) { char c; in=fopen(filename,"rt"); if (in==NULL) runtimeError("error opening input file"); readMetaData(); skipComments(); readObjective(); // read constraints int nbConstraintsRead = 0; while(!eof()) { skipSpaces(); if (eof()) break; putback(c=get()); if(c=='*') skipComments(); if (eof()) break; readConstraint(); nbConstraintsRead++; } //Small check on the number of constraints if (nbConstraintsRead != nbConstr) { runtimeError("Number of constraints read is different from metadata."); } } int main(int argc, char *argv[]) { if (argc!=2) printf("usage: SimpleParser \n"); else parse(argv[1]); return 0; }