Example #1
0
/* compile the given expression else read from stdin.
 * exit(2) if trouble.
 */
static void
compile (char *expr)
{
	char errmsg[1024];
	char *exp = expr;

	if (!exp) {
	    /* read expression from stdin */
	    int nr, nexp = 0;
	    exp = malloc(1024);
	    while ((nr = fread (exp+nexp, 1, 1024, stdin)) > 0)
		exp = realloc (exp, (nexp+=nr)+1024);
	    exp[nexp] = '\0';
	}

	if (verbose)
	    fprintf (stderr, "Compiling: %s\n", exp);
	if (compileExpr (exp, errmsg) < 0) {
	    fprintf (stderr, "Compile err: %s\n", errmsg);
	    exit(2);
	}

	if (exp != expr)
	    free (exp);
}
Example #2
0
// Compiling the constants is a case of wrapping up the same values
// In the byte code structure.  No run-time evaluation is necessary
void compileConst(Const conste, BInstr* ibfr, int* icount, char* strbfr) {
	ibfr[*icount].ic = 0;
	switch (conste.type)
	{
		case OBJ:
			{
				ibfr[*icount].type = BCONSTOBJ;
				ibfr[*icount].argc = 0;
				(*icount)++;
				return;	
			}
		case BOOL:
			{
				ibfr[*icount].type = BCONSTBOOL;
				ibfr[*icount].argc = 1;

				ibfr[*icount].args = malloc(sizeof(char*));

				ibfr[*icount].args[0] = malloc(sizeof(char)*2);
				ibfr[*icount].args[0][0] = conste.data.b + '0';
				ibfr[*icount].args[0][1] = 0;
				(*icount)++;
				return;
			}
		case FLOAT:
			{
				ibfr[*icount].type = BCONSTFLOAT;
				ibfr[*icount].argc = 1;

				ibfr[*icount].args = malloc(sizeof(char*));

				ibfr[*icount].args[0] = malloc((strlen(conste.data.f) + 1) * sizeof(char));
				strcpy(ibfr[*icount].args[0], conste.data.f);

				(*icount)++;
				return;
			}
		case INT:
			{
				ibfr[*icount].type = BCONSTINT;
				ibfr[*icount].argc = 1;

				sprintf(strbfr, "%d", conste.data.v);
				ibfr[*icount].args = malloc(sizeof(char*));

				ibfr[*icount].args[0] = malloc((strlen(strbfr) + 1) * sizeof(char));
				strcpy(ibfr[*icount].args[0], strbfr);

				(*icount)++;
				return;
			}
		case STR:
			{
				ibfr[*icount].type = BCONSTSTR;
				ibfr[*icount].argc = 1;

				ibfr[*icount].args = malloc(sizeof(char*));

				ibfr[*icount].args[0] = malloc((strlen(conste.data.str) + 1) * sizeof(char));
				strcpy(ibfr[*icount].args[0], conste.data.str);
				(*icount)++;
				return;
			}
		case FID:
			{
				ibfr[*icount].type = BCONSTFID;
				ibfr[*icount].argc = 1;

				sprintf(strbfr, "%d", conste.data.fid);
				ibfr[*icount].args = malloc(sizeof(char*));

				ibfr[*icount].args[0] = malloc((strlen(strbfr) + 1) * sizeof(char));
				strcpy(ibfr[*icount].args[0], strbfr);

				(*icount)++;
				return;
			}
		case LIST:
			{
				List l = conste.data.l;

				for (int i = 0; i < l.length; i++)
				{
					compileExpr(l.values[i], ibfr, icount, strbfr);
				}

				ibfr[*icount].ic = 0;
				ibfr[*icount].type = BSQUASHLIST;
				ibfr[*icount].argc = 1;

				sprintf(strbfr, "%d", l.length);
				ibfr[*icount].args = malloc(sizeof(char*));

				ibfr[*icount].args[0] = malloc((strlen(strbfr) + 1) * sizeof(char));
				strcpy(ibfr[*icount].args[0], strbfr);

				(*icount)++;

				return;
			}
		case LISTCON:
			{

				ListCon lc = conste.data.lc;

				compileExpr(*(lc.start), ibfr, icount, strbfr);
				compileExpr(*(lc.end), ibfr, icount, strbfr);
				compileExpr(*(lc.step), ibfr, icount, strbfr);
				ibfr[*icount].ic = 0;

				ibfr[*icount].type = BGENLIST;
				ibfr[*icount].argc = 0;

				(*icount)++;

				return;
			}
		default:
			{
				return;
			}
	}
}
Example #3
0
// Compiling specific operationg
void compileOp(Op op, BInstr* ibfr, int* icount, char* strbfr) {

	// Compile the operands
	compileExpr(*(op.a), ibfr, icount, strbfr);
	if (op.type != NOT && op.type != MEMB) compileExpr(*(op.b), ibfr, icount, strbfr);

	// Create the new instruction, one per operation
	ibfr[*icount].ic = 0;
	switch (op.type)
	{
		case IND:
		{
			ibfr[*icount].type = BIND;
			break;
		}
		case MEMB:
		{
			ibfr[*icount].type = BMEMB;
			ibfr[*icount].argc = 1;
			ibfr[*icount].args = malloc (sizeof(char*));
			ibfr[*icount].args[0] = malloc (sizeof(char) * (strlen(op.b->data.vare->name) + 1));
			strcpy(ibfr[*icount].args[0], op.b->data.vare->name);
			break;
		}
		case POW:
		{
			ibfr[*icount].type = BPOW;
			break;
		}
		case MULT:
		{
			ibfr[*icount].type = BMULT;
			break;
		}
		case DIV:
		{
			ibfr[*icount].type = BDIV;
			break;
		}
		case MINUS:
		{
			ibfr[*icount].type = BMINUS;
			break;
		}
		case PLUS:
		{
			ibfr[*icount].type = BPLUS;
			break;
		}
		case NOT:
		{
			ibfr[*icount].type = BNOT;
			break;
		}
		case ONTO:
		{
			ibfr[*icount].type = BONTO;
			break;
		}
		case GT:
		{
			ibfr[*icount].type = BGT;
			break;
		}
		case LT:
		{
			ibfr[*icount].type = BLT;
			break;
		}
		case GTE:
		{
			ibfr[*icount].type = BGTE;
			break;
		}
		case LTE:
		{
			ibfr[*icount].type = BLTE;
			break;
		}
		case IS:
		{
			ibfr[*icount].type = BIS;
			break;
		}
		case OR:
		{
			ibfr[*icount].type = BOR;
			break;
		}
		case AND:
		{
			ibfr[*icount].type = BAND;
			break;
		}
		default:
			break;
	}
	if (op.type != MEMB) ibfr[*icount].argc = 0;
	(*icount)++;
}
Example #4
0
// Compile an individual expression and put evaluated value on stack
void compileExpr(Expr expr, BInstr* ibfr, int* icount, char* strbfr) {
	ibfr[*icount].ic = 0;
	switch (expr.type)
	{
		case CONST:
			{
				// Constants immediately resolve to constant values
				compileConst(*(expr.data.conste), ibfr, icount, strbfr);
				return;
			}
		case VAR:
			{
				// Load instruction, loads variable of that name
				ibfr[*icount].type = BLOAD;
				ibfr[*icount].argc = 1;

				ibfr[*icount].args = malloc(sizeof(char*));

				ibfr[*icount].args[0] = malloc((strlen(expr.data.vare->name) + 1) * sizeof(char));
				strcpy(ibfr[*icount].args[0], expr.data.vare->name);
				(*icount)++;
				return;
			}
		case OP:
			{
				// Compile the operation
				compileOp(*(expr.data.ope), ibfr, icount, strbfr);
				return;
			}
		case CALL:
			{
				// Compile all of the arguments and leave them on the stack
				for (int i = 0; i < expr.data.calle->argc; i++)
				{
					compileExpr(expr.data.calle->args[i], ibfr, icount, strbfr);
				}

				// Load the FID associated with the function name
				compileExpr(*(expr.data.calle->lhs), ibfr, icount, strbfr);

				// Call that FID
				if (expr.data.calle->lhs->type == OP && expr.data.calle->lhs->data.ope->type == MEMB)
				{
					compileExpr(*(expr.data.calle->lhs->data.ope->a), ibfr, icount, strbfr);
					ibfr[*icount].type = BCALLM;
				}
				else
				{
					ibfr[*icount].type = BCALL;
				}
				ibfr[*icount].ic = 0;
				ibfr[*icount].argc = 1;

				sprintf(strbfr, "%d", expr.data.calle->argc);
				ibfr[*icount].args = malloc(sizeof(char*));

				ibfr[*icount].args[0] = malloc((strlen(strbfr) + 1) * sizeof(char));
				strcpy(ibfr[*icount].args[0], strbfr);
				(*icount)++;

				return;
			}
		default:
			{
				return;
			}
	}
}
Example #5
0
// Compile an individual instruction
void compileInstr(Instr instr, BInstr* ibfr, int* icount, char* strbfr) {
	ibfr[*icount].ic = 0;
	switch (instr.type)
	{
		// Print instruction
		case PRINT:
			{
				// Compile the expression to print
				compileExpr(*(instr.data.printi->expression), ibfr, icount, strbfr);

				// Generate print instruction
				ibfr[*icount].type = BPRINT;
				ibfr[*icount].argc = 0;
				(*icount)++;

				return;
			}	
		// Assign instructions
		case ASSIGN:
			{
				// Compile the value
				compileExpr(*(instr.data.assigni->rhs), ibfr, icount, strbfr);
				ibfr[*icount].ic = 0;
				// Look at what is being assigned to
				switch (instr.data.assigni->lhs->type)
				{
					case VAR:
					{
						// If it's a variable, create store instruction for that variable
						char* n = instr.data.assigni->lhs->data.vare->name;
						ibfr[*icount].type = BSTORE;
						ibfr[*icount].argc = 1;

						ibfr[*icount].args = malloc(sizeof(char*));

						ibfr[*icount].args[0] = malloc((strlen(n) + 1) * sizeof(char));
						strcpy(ibfr[*icount].args[0], n);

						(*icount)++;
						break;
					}
					case OP:
					{
						// If it's an IND operation
						Op* ope = instr.data.assigni->lhs->data.ope;
						if (ope->type == IND)
						{
							// Compile the list and index values
							compileExpr(*(ope->a), ibfr, icount, strbfr);
							compileExpr(*(ope->b), ibfr, icount, strbfr);
							ibfr[*icount].type = BUPDATELIST;
							ibfr[*icount].argc = 0;
							ibfr[*icount].ic = 0;
							(*icount)++;

							break;
						}
						// If it's a MEMB
						if (ope->type == MEMB)
						{
							// Compile the object
							compileExpr(*(ope->a), ibfr, icount, strbfr);
							ibfr[*icount].type = BUPDATEFIELD;
							ibfr[*icount].argc = 1;
							ibfr[*icount].args = malloc(sizeof(char*));
							char* n = ope->b->data.vare->name;
							ibfr[*icount].args[0] = malloc((strlen(n) + 1) * sizeof(char));
							strcpy(ibfr[*icount].args[0], n);
							ibfr[*icount].ic = 0;
							(*icount)++;

							break;
						}
						break;
					}
					default:
						break;
				}

				return;
			}
		// Return instructions
		case RETURN:
			{
				// Just compile the expression to return
				compileExpr(*(instr.data.returni->expression), ibfr, icount, strbfr);

				// Then create return instruction
				ibfr[*icount].type = BRETURN;
				ibfr[*icount].argc = 0;
				ibfr[*icount].ic = 0;
				(*icount)++;

				return;
			}
		// If it's an If statement
		case IF:
			{
				// Compile the condition
				compileExpr(*(instr.data.ifi->expression), ibfr, icount, strbfr);
				ibfr[*icount].type = BIF; // Create IF instruction

				// Compile all the child instructions
				int ic = 0;
				BInstr* is = malloc(MAX_INSTRUCTION_LENGTH * 10 * sizeof(BInstr));
				for (int i = 0; i < instr.data.ifi->ificount; i++)
					compileInstr(instr.data.ifi->ifinstrs[i], is, &ic, strbfr);

				// Put those compiled instructions into the bytecode instruction
				ibfr[*icount].is = malloc (ic * sizeof(BInstr));
				for (int i = 0; i < ic; i++)
					ibfr[*icount].is[i] = is[i];
				
				ibfr[*icount].ic = ic;
				ibfr[*icount].argc = 0;

				// Create else instruction
				(*icount)++;
				ibfr[*icount].type = BYELSE;

				// Compile the else instruction
				ic = 0;
				for (int i = 0; i < instr.data.ifi->elicount; i++)
					compileInstr(instr.data.ifi->elseinstrs[i], is, &ic, strbfr);

				// Add the else children to the else instruction
				ibfr[*icount].is = malloc (ic * sizeof(BInstr));
				for (int i = 0; i < ic; i++)
					ibfr[*icount].is[i] = is[i];

				// Dispose of temporary list of instructions
				free(is);
				
				ibfr[*icount].ic = ic;
				ibfr[*icount].argc = 0;

				(*icount)++;
				return;
			}
		// While instruction
		case WHILE:
			{
				// While instruction
				ibfr[*icount].type = BWHILE;
				ibfr[*icount].argc = 0;

				int ic = 0;
				BInstr* is = malloc(MAX_INSTRUCTION_LENGTH * 10 * sizeof(BInstr));

				compileExpr(*(instr.data.whilei->expression), is, &ic, strbfr);

				// Instructions to exit while look when
				// condition no longer holds
				is[ic].type = BNOT;
				is[ic].argc = 0;
				is[ic].ic = 0;
				ic++;

				is[ic].type = BIF;
				is[ic].argc = 0;
				is[ic].ic = 1;
				is[ic].is = malloc(sizeof(BInstr));

				is[ic].is[0].type = BBREAK;
				is[ic].is[0].argc = 0;
				is[ic].is[0].ic = 0;

				ic++;

				// Compile child instructions
				for (int i = 0; i < instr.data.whilei->icount; i++)
					compileInstr(instr.data.whilei->instrs[i], is, &ic, strbfr);

				ibfr[*icount].is = malloc (ic * sizeof(BInstr));
				for (int i = 0; i < ic; i++)
					ibfr[*icount].is[i] = is[i];

				free(is);
				
				ibfr[*icount].ic = ic;

				(*icount)++;
				return;
			}

		// FOR statement
		case FOR:
			{
				if (instr.data.fori->iterator->type != VAR) return;

				if (instr.data.fori->expression->type == CONST &&
					instr.data.fori->expression->data.conste->type == LISTCON)
				{
					ListCon lc = instr.data.fori->expression->data.conste->data.lc;
					compileExpr(*(lc.start), ibfr, icount, strbfr);
					compileExpr(*(lc.end), ibfr, icount, strbfr);
					compileExpr(*(lc.step), ibfr, icount, strbfr);
					ibfr[*icount].ic = 0;

					ibfr[*icount].type = BFOR;

				} else {
					compileExpr(*(instr.data.fori->expression), ibfr, icount, strbfr);
					ibfr[*icount].type = BFOREACH;
				}

				ibfr[*icount].argc = 1;

				ibfr[*icount].args = malloc(sizeof(char*));
				char* iname = instr.data.fori->iterator->data.vare->name;
				ibfr[*icount].args[0] = malloc((strlen(iname) + 1) * sizeof(char));
				strcpy(ibfr[*icount].args[0], iname);

				int ic = 0;
				BInstr* is = malloc(MAX_INSTRUCTION_LENGTH * 10 * sizeof(BInstr));

				for (int i = 0; i < instr.data.fori->icount; i++)
					compileInstr(instr.data.fori->instrs[i], is, &ic, strbfr);

				ibfr[*icount].is = malloc (ic * sizeof(BInstr));
				for (int i = 0; i < ic; i++)
					ibfr[*icount].is[i] = is[i];

				free(is);
				
				ibfr[*icount].ic = ic;

				(*icount)++;
				return;
			}
		//CONTINUE, BREAK
		case CONTROL:
			{
				switch (instr.data.controli->type)
				{
					case BREAK:
					{
						ibfr[*icount].type = BBREAK;
						ibfr[*icount].argc = 0;
						ibfr[*icount].ic = 0;
						(*icount)++;
						break;
					}
					case CONTINUE:
					{
						ibfr[*icount].type = BCONTINUE;
						ibfr[*icount].argc = 0;
						ibfr[*icount].ic = 0;
						(*icount)++;
						break;
					}
				}
				return;
			}
		default:
			{
				return;
			}
	}
}