void evalStackUntilLeftP() { //printf("eval leftp called\n"); command_t operand2, operand1; int operatorNumber; //pop_operator(); // get rid of RIGHTP while(operator_stack_top() != LEFTP) { //printf("operator top is %i\n",operator_stack_top()); if(operator_stack_top() == -1) error(1,0,"%i: Syntax Error. Mismatching parenthesis\n",g_lineNumber); operand2 = pop_operand(); operand1 = pop_operand(); operatorNumber = pop_operator(); push_operand(createCommand(operand1, operand2, operatorNumber)); } //do not assume we have a result. Parenthesis could be empty (). pop_operator();// get rid of LEFTP //printf("Operator_stackTop %i\n",operator_stack_top()); //printf("Operand_stacktop %i\n",operand_stack_top()); if(operand_stack_top() != NULL) { //convert command at the top of operand stack to subshell command. //printf("pooping operand\n"); operand1 = pop_operand(); push_operand(createCommand(operand1, NULL, RIGHTP)); } //printf("Number of operands left %i\n",g_iOperand_stack_size); //printf("Number of operators left %i\n",g_iOperator_stack_size); }
/** * While there are still operators, keep evaluating the stack so that what is left will * be one complete command in the operand stack. */ void evalStack() { command_t operand2, operand1; int operatorNumber; while(g_iOperator_stack_size > 0) { operand2 = pop_operand(); // if( !( g_iOperand_stack_size <= 0 && operator_stack_top() == SEMIC) ) operand1 = pop_operand(); // else //allow ';' to only have one operand // operand1 = NULL; operatorNumber = pop_operator(); push_operand(createCommand(operand1, operand2, operatorNumber)); } if(g_iOperand_stack_size > 1) { error(1, 0, "%i: Syntax Error. Incorrect number of elements on operand stack after evalStack\n", g_lineNumber); } }
static int compile_operator(compiletime c) { int operand_count = 0; const char *op = pop_operator(c, &operand_count); if (!strcmp(op, "*")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, multiply_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "**")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, power_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "/")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, divide_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "%")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, modulo_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "=")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, assign_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, ";")) { } else if (!strcmp(op, "if")) { const char *val1 = pop_operand(c); emit2(c, if_tc, val1); DEBUG printf("emit '%s' %s\n", val1, op); c->level++; } else if (!strcmp(op, "else")) { c->level--; emit1(c, else_tc); c->level++; DEBUG printf("emit %s\n", op); } else if (!strcmp(op, "fi")) { c->level--; emit1(c, fi_tc); DEBUG printf("emit %s\n", op); } else if (!strcmp(op, "!")) { const char *val1 = pop_operand(c); emit2(c, not_tc, val1); DEBUG printf("emit '%s' %s\n", val1, op); } else if (!strcmp(op, "+")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, add_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "-")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, subtract_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, ">")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, gt_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, ">=")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, geq_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "<=")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, leq_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "<")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, lt_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "&&")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, and_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "||")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, or_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "^^")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, xor_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "&")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, bit_and_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "|")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, bit_or_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "^")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, bit_xor_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "~")) { const char *val1 = pop_operand(c); emit2(c, bit_negate_tc, val1); DEBUG printf("emit %s %s\n", val1, op); } else if (!strcmp(op, "<<")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, shift_left_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, ">>")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, shift_right_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, ">>>")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, logical_shift_right_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "==")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, eq_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "!=")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, neq_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "fold-case")) { const char *val1 = pop_operand(c); emit2(c, func_fold_case_tc, val1); DEBUG printf("emit %s %s\n", op, val1); } else if (!strcmp(op, "size")) { const char *val1 = pop_operand(c); emit2(c, func_size_tc, val1); DEBUG printf("emit %s %s\n", op, val1); } else if (!strcmp(op, "print")) { const char *val1 = pop_operand(c); emit2(c, func_print_tc, val1); DEBUG printf("emit %s %s\n", op, val1); } else if (!strcmp(op, "jday")) { const char *val1 = pop_operand(c); emit2(c, func_jday_tc, val1); DEBUG printf("emit %s %s\n", op, val1); } else if (!strcmp(op, "dow")) { const char *val1 = pop_operand(c); emit2(c, func_dow_tc, val1); DEBUG printf("emit %s %s\n", op, val1); } else if (!strcmp(op, "equals")) { emit_code(c, func_eq_tc, operand_count); while (operand_count--) { const char *val1 = pop_operand(c); emit_value(c, val1); DEBUG printf("emit %s '%s'\n", op, val1); } } else if (!strcmp(op, "contains")) { emit_code(c, func_contains_tc, operand_count); while (operand_count--) { const char *val1 = pop_operand(c); emit_value(c, val1); DEBUG printf("emit %s '%s'\n", op, val1); } } else if (!strcmp(op, "begins-with")) { emit_code(c, func_begins_with_tc, operand_count); while (operand_count--) { const char *val1 = pop_operand(c); emit_value(c, val1); DEBUG printf("emit %s '%s'\n", op, val1); } } else if (!strcmp(op, "ends-with")) { emit_code(c, func_ends_with_tc, operand_count); while (operand_count--) { const char *val1 = pop_operand(c); emit_value(c, val1); DEBUG printf("emit %s '%s'\n", op, val1); } } else if (!strcmp(op, "int")) { const char *val1 = pop_operand(c); emit2(c, func_is_int_tc, val1); DEBUG printf("emit %s '%s'\n", op, val1); } else if (!strcmp(op, "real")) { const char *val1 = pop_operand(c); emit2(c, func_is_real_tc, val1); DEBUG printf("emit %s '%s'\n", op, val1); } else if (!strcmp(op, "nan")) { const char *val1 = pop_operand(c); emit2(c, func_is_nan_tc, val1); DEBUG printf("emit %s '%s'\n", op, val1); } else if (!strcmp(op, "string")) { const char *val1 = pop_operand(c); emit2(c, func_is_string_tc, val1); DEBUG printf("emit %s '%s'\n", op, val1); } else if (!strcmp(op, "(")) { return 1; } else if (!strcmp(op, ")")) { return 1; } else { DEBUG printf("bad operator '%s'\n", op); return 0; } push_operand(c, "_STACK"); return 1; }
command_stream_t make_command_stream (int (*get_next_byte) (void *), void *get_next_byte_argument) { char *operators[] = { "&&", "||", "|", "(", ")", ";" };//, "\n" }; int precedences[] = { 1, 1, 2, 4, -1, 0, 0 }; int i, j, isOperator, numChars = 0, inComment = 0; int operatorNumber = 0; int possibleNewCommand = 0; unsigned int currentWordSize = 16 * sizeof(char); int lastOperatorWasRightP = 0; char *operand, *lastCommand, *currentWord = checked_malloc(16 * sizeof(char)); char c = (char) get_next_byte(get_next_byte_argument); command_t operand1, operand2; // Initialize command stream command_stream_t commandStream = checked_malloc(10 * sizeof(struct command)); commandStream->currentStreamSize = 10 * sizeof(struct command); commandStream->numCommands = 0; commandStream->currentCommand = 0; g_lineNumber = 0; init_stacks(); while(c != EOF) { //printf("loop entered\n"); if( c == '\n') { g_lineNumber++; } if(inComment) { if( c == '\n' ) { inComment = 0; c = get_next_byte(get_next_byte_argument); continue; } else { c = get_next_byte(get_next_byte_argument); continue; } } else if( c == '#' ) { inComment = 1; c = get_next_byte(get_next_byte_argument); continue; } /** * Basically if there is a non-operator followed by a newline, there is a possibility * that the current command is done. The current command will be over if the newline * is then followed by another non-operator. Also ignore newlines inside commands. */ //printf("possible New COmmand is set to %i\n",possibleNewCommand); if ( (!isOperator || lastOperatorWasRightP) && c == '\n') { possibleNewCommand = 1; //printf("PossibleNewCommand set to 1 char is %c\n",c); // Used if a new command is actually started to finish the current one lastCommand = currentWord; fpos_t pos; fgetpos(get_next_byte_argument, &pos); c = get_next_byte(get_next_byte_argument); if (c != '\n') { //printf("continuing after setting possibleNewCommand to 1\n"); // if(c == EOF) // printf("new character is EOF and num of operands left is %i\n",g_iOperand_stack_size); fsetpos(get_next_byte_argument, &pos); lastOperatorWasRightP = 0; continue; } else { g_lineNumber++; } } else if (c == '\n') { c = get_next_byte(get_next_byte_argument); //printf("Operator followed by newlien detected. continiuing\n"); lastOperatorWasRightP = 0; continue; } //printf("Checkpoint 2\n"); /** * This loop checks if the current char is an operator. If it is, we create the operator word * and then we check the next char in case of double char operators such as || or && */ lastOperatorWasRightP = 0; isOperator = 0; for (i = 0; i < 6; i++) { // check if start of an operator if (c == operators[i][0]) { isOperator = 1; operand = currentWord; // Save old operand before creating operator currentWord = checked_malloc(3 * sizeof(char)); // Create the operator word currentWord[0] = c; fpos_t pos; fgetpos(get_next_byte_argument, &pos); if (c == '|' || c == '&') { if(g_iOperand_stack_size <= 0 && numChars <= 0) error(1,0,"%i: Did not expect binary operator",g_lineNumber); char current_char = c; c = get_next_byte(get_next_byte_argument); currentWord[1] = c; currentWord[2] = '\0'; if (c == '|' && c == current_char) { i = OR; } else if (c == '&' && c == current_char) { i = AND; } else if( current_char == '&' && c != current_char) { //TODO: Throw syntax error here. Single &! //fprintf(stderr,"%i: Isolated & found. Not a valid word character, and it is not an &&",lineNumber); error(1,0,"%i: Isolated & found",g_lineNumber); } else { i = PIPE; currentWord[1] = '\0'; fsetpos(get_next_byte_argument, &pos); } } else if( c == '(') { //printf("Found leftP\n"); i = LEFTP; currentWord[1] = '\0'; fsetpos(get_next_byte_argument, &pos); } else if( c == ')') { //printf("Found rightP\n"); lastOperatorWasRightP = 1; i = RIGHTP; currentWord[1] = '\0'; fsetpos(get_next_byte_argument, &pos); } else if( c == ';') { if(g_iOperand_stack_size <= 0 && numChars <= 0) error(1,0,"%i: Did not expect binary operator",g_lineNumber); currentWord[1] = '\0'; fsetpos(get_next_byte_argument, &pos); } else { currentWord[1] = '\0'; fsetpos(get_next_byte_argument, &pos); } break; } } /** * When we encounter an operator, we can create a simple command out of the previous word * if there was a word (operand) there. This should always happen?? */ if (isOperator) { //printf("isOperator\n"); if (numChars > 0) { operand[numChars] = '\0'; //printf("Pushed %s on operand stack\n", operand); //get rid of whitespaces in operand here. int onlyWhite = getRidOfExtraWhitespaces(operand); if(onlyWhite == 0) push_operand(createSimpleCommand(operand)); // printf("simple out of operand %s\n", operand); numChars = 0; } /** * While the top of the stack contains an operator with equal or higher precedance than the * operator we are currently dealing with, keeping popping one operator and two operands, * creating a command out of them, and pushing it onto the operand stack. */ //printf("Charly:top of stack is %i\n",operator_stack_top()); // if(operator_stack_top() == RIGHTP ) //eval stack until a LEFTP is found if(i == RIGHTP) { //printf("EvalStackuntilLeftP found. possibleNewCommand is %i\n",possibleNewCommand); evalStackUntilLeftP(); //printf("current char is %c\n",c); c = get_next_byte(get_next_byte_argument); //printf("nextchar is %c\n",c); continue; } while(g_iOperator_stack_size > 0 && g_iOperand_stack_size > 1 && (precedences[operator_stack_top()] >= precedences[i]) && ((operator_stack_top() != LEFTP) && i != RIGHTP )) { operand2 = pop_operand(); operand1 = pop_operand(); operatorNumber = pop_operator(); //printf("popped operands types %d %d\n", operand1->type, operand2->type); //printf("popped operator %s\n", operators[operatorNumber]); //printf("pushed type %d operand on stack\n", operatorNumber); push_operand(createCommand(operand1, operand2, operatorNumber)); } // Get the operator number for the current word for (j = 0; j < 6; j++) { if (strcmp(currentWord, operators[j]) == 0) { break; } } //printf("pushed operators %s %d on stack\n", currentWord, j); push_operator(j); currentWord = checked_malloc(3 * sizeof(char)); } else if (!possibleNewCommand) { //if last operator was rightP. do not run this. //printf("not a new command. new char is %c, numChars is %i, currentWordSize is %i\n",c,numChars,currentWordSize); if(c != ' ' || numChars > 0) { //printf("growing current word %s currentWordSize is %i and numChars is %i\n",currentWord,currentWordSize,numChars); // Grow current word which is an operand if necessary if ((numChars * sizeof(char)) >= currentWordSize) { //printf("doubling size of word %s\n",currentWord); currentWordSize *= 2; //char * buffer = checked_malloc(currentWordSize); //strncpy(buffer,currentWord,numChars); //free((void *)currentWord); //currentWord = checked_malloc(currentWordSize); //strncpy(currentWord,buffer,numChars); currentWord = checked_realloc(currentWord, currentWordSize );// for some reason this was messing up //printf("it is now %s\n",currentWord); } currentWord[numChars] = c; numChars++; } } else { //printf("Going to new command. operand stack size is %i\n",g_iOperand_stack_size); //printf("Operator stack size is %i. numChars is %i\n",g_iOperator_stack_size,numChars); //if(g_iOperand_stack_size <= 0) //{ // c = get_next_byte(get_next_byte_argument); // possibleNewCommand = 0; //continue; //} /** * This means that we are about to go onto a new command. We stop the current command and * finish building it with the lastCommand variable, and an operand/operator if necessary. * This command is then put into the command stream. */ lastCommand[numChars] = '\0'; //printf("Last Command getting rid of whites\n"); if(numChars > 0) { //printf("numchars is > 0 so word is %s\n",lastCommand); getRidOfExtraWhitespaces(lastCommand); push_operand(createSimpleCommand(lastCommand)); } else if(g_iOperand_stack_size <= 0) { c = get_next_byte(get_next_byte_argument); possibleNewCommand = 0; continue; } //else //{ // printf("numChars == 0 so we are continuing\n"); //continue // c = get_next_byte(get_next_byte_argument); // possibleNewCommand = 0; // continue; //} evalStack(); //printf("%s\n", "Finished one command"); if ((commandStream->numCommands * sizeof(struct command)) == commandStream->currentStreamSize) { commandStream->currentStreamSize *= 2; commandStream = checked_realloc(commandStream, commandStream->currentStreamSize); } command_t commandToPushToStream = pop_operand(); commandToPushToStream->status = -1; commandStream->stream[commandStream->numCommands] = commandToPushToStream; // TODO: if stack not empty, there was an error? commandStream->numCommands++; numChars = 0; currentWord = checked_malloc(3 * sizeof(char)); // prevent overwriting } //printf("PossibleNewCOmmand set to 0 right before checkpoint1\n"); c = get_next_byte(get_next_byte_argument); possibleNewCommand = 0; } //printf("Checkpoint1. possibleNEwCommand is %i num of operands is %i\n",possibleNewCommand,g_iOperand_stack_size); // Push last word onto operand stack and evaluate the rest if (!isOperator) { currentWord[numChars] = '\0'; //printf("pushed simple word %s with word count %i strlen is %i\n", currentWord,numChars,(int)strlen(currentWord)); getRidOfExtraWhitespaces(currentWord); if(strlen(currentWord) > 0) push_operand(createSimpleCommand(currentWord)); } else { // if a semicolon, valid? } //printf("evalstack at the end of loop\n"); evalStack(); // Put last command in command stream // if there is one! if(operand_stack_top() != NULL) { command_t commandToPushToStream = pop_operand(); commandToPushToStream->status = -1; commandStream->stream[commandStream->numCommands] = commandToPushToStream; commandStream->numCommands++; } //printf("Stack sizes: %d, %d\n", g_iOperator_stack_size, g_iOperand_stack_size); //printf("Final command type is %d\n", commandStream->stream[0]->type); return commandStream; }