#include "parser.h" #include "lexer.h" #include "graphics_context.h" #include "exprparser.h" parse_error::parse_error(int l, const char* s):line_number(l) { strcpy(error,s); cerr << "ERROR: " << s << " near line " << l << endl; } double parser::read_eval_exp(istream& is, list& B, double* V) { expression * ex = exprparser.read(is,B); double v = ex->evaluate(V); delete ex; return v; } coordinate parser::read_coordinate(istream& is, list& B, double* V) { lex.check_token(is,"["); double x = read_eval_exp(is,B,V); lex.check_token(is,","); double y = read_eval_exp(is,B,V); lex.check_token(is,"]"); return coordinate(x,y); } color parser::read_color(istream& is, list& B, double* V) { lex.check_token(is,"["); int r = (int)read_eval_exp(is,B,V); lex.check_token(is,","); int g = (int)read_eval_exp(is,B,V); lex.check_token(is,","); int b = (int)read_eval_exp(is,B,V); lex.check_token(is,"]"); return color((short)r,(short)g,(short)b); } parser::parser():exprparser(&lex),xmin(-100),xmax(100),ymin(-100),ymax(100), xres(100),yres(100) { } point* parser::read_point(istream& is,list& B,double* V) { lex.check_token(is,"("); coordinate c = read_coordinate(is,B,V); lex.check_token(is,")"); point *p = new point(coordsys(xmin,ymin,xmax,ymax),c); p->set_order(gc.order); p->set_depth(gc.depth); p->set_pen_color(gc.pen_color); p->set_rotate(gc.rotate); p->set_rotation_center(gc.rotation_center); p->set_rotation_angle(gc.rotation_angle); return p; } line* parser::read_line(istream& is,list& B,double* V) { lex.check_token(is,"("); coordinate c1 = read_coordinate(is,B,V); lex.check_token(is,","); coordinate c2 = read_coordinate(is,B,V); lex.check_token(is,")"); line* l = new line(coordsys(xmin,ymin,xmax,ymax),c1,c2); l->set_order(gc.order); l->set_depth(gc.depth); l->set_pen_color(gc.pen_color); l->set_rotate(gc.rotate); l->set_rotation_center(gc.rotation_center); l->set_rotation_angle(gc.rotation_angle); return l; } rectangle* parser::read_rectangle(istream& is,list& B,double* V) { lex.check_token(is,"("); coordinate c = read_coordinate(is,B,V); lex.check_token(is,","); double a = read_eval_exp(is,B,V); lex.check_token(is,","); double b = read_eval_exp(is,B,V); lex.check_token(is,")"); rectangle * r = new rectangle(coordsys(xmin,ymin,xmax,ymax),c,a,b); r->set_order(gc.order); r->set_depth(gc.depth); r->set_pen_color(gc.pen_color); r->set_rotate(gc.rotate); r->set_rotation_center(gc.rotation_center); r->set_rotation_angle(gc.rotation_angle); r->set_filled(gc.filled); r->set_fill_color(gc.fill_color); r->set_center_angle(gc.center_angle); return r; } triangle* parser::read_triangle(istream& is,list& B,double* V) { lex.check_token(is,"("); coordinate c1 = read_coordinate(is,B,V); lex.check_token(is,","); coordinate c2 = read_coordinate(is,B,V); lex.check_token(is,","); coordinate c3 = read_coordinate(is,B,V); lex.check_token(is,")"); triangle* t = new triangle(coordsys(xmin,ymin,xmax,ymax),c1,c2,c3); t->set_order(gc.order); t->set_depth(gc.depth); t->set_pen_color(gc.pen_color); t->set_rotate(gc.rotate); t->set_rotation_center(gc.rotation_center); t->set_rotation_angle(gc.rotation_angle); t->set_filled(gc.filled); t->set_fill_color(gc.fill_color); t->set_center_angle(gc.center_angle); return t; } square* parser::read_square(istream& is,list& B,double* V) { lex.check_token(is,"("); coordinate c = read_coordinate(is,B,V); lex.check_token(is,","); double a = read_eval_exp(is,B,V); lex.check_token(is,")"); square *s = new square(coordsys(xmin,ymin,xmax,ymax),c,a); s->set_order(gc.order); s->set_depth(gc.depth); s->set_pen_color(gc.pen_color); s->set_rotate(gc.rotate); s->set_rotation_center(gc.rotation_center); s->set_rotation_angle(gc.rotation_angle); s->set_filled(gc.filled); s->set_fill_color(gc.fill_color); s->set_center_angle(gc.center_angle); return s; } ellipse* parser::read_ellipse(istream& is,list& B,double* V) { lex.check_token(is,"("); coordinate c = read_coordinate(is,B,V); lex.check_token(is,","); double a = read_eval_exp(is,B,V); lex.check_token(is,","); double b = read_eval_exp(is,B,V); lex.check_token(is,")"); ellipse* e = new ellipse(coordsys(xmin,ymin,xmax,ymax),c,a,b); e->set_order(gc.order); e->set_depth(gc.depth); e->set_pen_color(gc.pen_color); e->set_rotate(gc.rotate); e->set_rotation_center(gc.rotation_center); e->set_rotation_angle(gc.rotation_angle); e->set_filled(gc.filled); e->set_fill_color(gc.fill_color); e->set_center_angle(gc.center_angle); return e; } circle* parser::read_circle(istream& is,list& B,double* V) { lex.check_token(is,"("); coordinate o = read_coordinate(is,B,V); lex.check_token(is,","); double r = read_eval_exp(is,B,V); lex.check_token(is,")"); circle * c = new circle(coordsys(xmin,ymin,xmax,ymax),o,r); c->set_order(gc.order); c->set_depth(gc.depth); c->set_pen_color(gc.pen_color); c->set_rotate(gc.rotate); c->set_rotation_center(gc.rotation_center); c->set_rotation_angle(gc.rotation_angle); c->set_filled(gc.filled); c->set_fill_color(gc.fill_color); c->set_center_angle(gc.center_angle); return c; } void parser::read_figure(istream& is,list& B,double* V, drawable_list& L, figure_descriptor* d) { lex.check_token(is,"("); double* P = new double[d->get_argc()]; for(int i=0; i< d->get_argc(); i++) { P[i] = read_eval_exp(is,B,V); if (i != d->get_argc() - 1) { lex.check_token(is,","); } } lex.check_token(is,")"); list_iterator I = d->first_statement(); while(I.has_more_elements()) { coordsys S(xmin,ymin,xmax,ymax); (*I)->execute(gc,L,S,P); I++; } delete [] P; } void parser::read_shape(istream& is,list& B,double* V, drawable_list& L) { const char* token = lex.get_token(is); if (strcmp(token,"rectangle") == 0) { L.insert(read_rectangle(is,B,V)); } else if (strcmp(token,"square") == 0) { L.insert(read_square(is,B,V)); } else if (strcmp(token,"ellipse") == 0) { L.insert(read_ellipse(is,B,V)); } else if (strcmp(token,"circle") == 0) { L.insert(read_circle(is,B,V)); } else if (strcmp(token,"triangle") == 0) { L.insert(read_triangle(is,B,V)); } else { figure_descriptor* d = T.find_descriptor(token); if (d == (figure_descriptor*)0) { throw parse_error(lex.get_line_number(),"figure expected"); } read_figure(is,B,V,L,d); } } void parser:: read_coordinate_expression(istream& is, list& B, expression*& x, expression*& y) { expression* tmp; lex.check_token(is,"["); tmp = exprparser.read(is,B); x = tmp->simplify(); delete tmp; lex.check_token(is,","); tmp = exprparser.read(is,B); y = tmp->simplify(); delete tmp; lex.check_token(is,"]"); } conditional* parser::read_conditional(istream& is,list& B) { // if assumed to be read! lex.check_token(is,"("); expression * tmp = exprparser.read(is,B); expression * cond = tmp->simplify(); delete tmp; lex.check_token(is,")"); conditional * cs = new conditional(cond); lex.check_token(is,"{"); const char* token = lex.get_token(is); while(strcmp(token,"}") != 0) { lex.putback(); cs->add_statement(read_statement(is,B)); token = lex.get_token(is); } token = lex.next_token(is); if (strcmp(token,"else") == 0) { lex.check_token(is,"{"); token = lex.get_token(is); while(strcmp(token,"}") != 0) { lex.putback(); cs->add_else_statement(read_statement(is,B)); token = lex.get_token(is); } } else { lex.putback(); } return cs; } set_color* parser::read_set_color(istream& is,list& B) { char token[128]; strcpy(token,lex.get_token(is)); expression * tmp; lex.check_token(is,"["); tmp = exprparser.read(is,B); expression* r = tmp->simplify(); delete tmp; lex.check_token(is,","); tmp = exprparser.read(is,B); expression* g = tmp->simplify(); delete tmp; lex.check_token(is,","); tmp = exprparser.read(is,B); expression* b = tmp->simplify(); delete tmp; lex.check_token(is,"]"); set_color * cs; if (strcmp(token,"fill_color") == 0) { cs = new set_fill_color(r,g,b); } else if (strcmp(token,"pen_color") == 0) { cs = new set_pen_color(r,g,b); } else { delete r; delete g; delete b; throw new parse_error(lex.get_line_number(), "fill_color or pen_color expected"); } return cs; } set_single_val* parser::read_set_single_val(istream& is,list& B) { char token[128]; strcpy(token,lex.get_token(is)); expression * tmp = exprparser.read(is,B); expression * ex = tmp->simplify(); delete tmp; set_single_val* ss; if (strcmp(token,"filled") == 0) { ss = new set_filled(ex); } else if (strcmp(token,"rotate") == 0) { ss = new set_rotate(ex); } else if (strcmp(token,"center_angle") == 0) { ss = new set_center_angle(ex); } else if (strcmp(token,"rotation_angle") == 0) { ss = new set_rotation_angle(ex); } else if (strcmp(token,"depth") == 0) { ss = new set_depth(ex); } else if (strcmp(token,"order") == 0) { ss = new set_order(ex); } else { delete ex; throw new parse_error(lex.get_line_number(),"unknown parameter"); } return ss; } set_rotation_center* parser::read_set_rotation_center(istream& is, list& B) { const char* token = lex.get_token(is); if (strcmp(token,"rotation_center") != 0) { throw new parse_error(lex.get_line_number(),"unknown parameter"); } expression *x, *y; read_coordinate_expression(is,B,x,y); return new set_rotation_center(x,y); } draw_point* parser::read_draw_point(istream& is,list& B) { lex.check_token(is,"("); expression *x, *y; read_coordinate_expression(is,B,x,y); lex.check_token(is,")"); return new draw_point(x,y); } draw_line* parser::read_draw_line(istream& is,list& B) { lex.check_token(is,"("); expression *x1, *y1; read_coordinate_expression(is,B,x1,y1); lex.check_token(is,","); expression *x2, *y2; read_coordinate_expression(is,B,x2,y2); lex.check_token(is,")"); return new draw_line(x1,y1,x2,y2); } draw_circle* parser::read_draw_circle(istream& is,list& B) { lex.check_token(is,"("); expression *x, *y; read_coordinate_expression(is,B,x,y); lex.check_token(is,","); expression *tmp = exprparser.read(is,B); expression *r = tmp->simplify(); delete tmp; lex.check_token(is,")"); return new draw_circle(x,y,r); } draw_square* parser::read_draw_square(istream& is,list& B) { lex.check_token(is,"("); expression *x, *y; read_coordinate_expression(is,B,x,y); lex.check_token(is,","); expression *tmp = exprparser.read(is,B); expression *a = tmp->simplify(); delete tmp; lex.check_token(is,")"); return new draw_square(x,y,a); } draw_rectangle* parser::read_draw_rectangle(istream& is,list& B) { lex.check_token(is,"("); expression *x, *y; read_coordinate_expression(is,B,x,y); lex.check_token(is,","); expression *tmp = exprparser.read(is,B); expression *a = tmp->simplify(); delete tmp; lex.check_token(is,","); tmp = exprparser.read(is,B); expression *b = tmp->simplify(); delete tmp; lex.check_token(is,")"); return new draw_rectangle(x,y,a,b); } draw_triangle* parser::read_draw_triangle(istream& is,list& B) { lex.check_token(is,"("); expression *x1, *y1; read_coordinate_expression(is,B,x1,y1); lex.check_token(is,","); expression *x2, *y2; read_coordinate_expression(is,B,x2,y2); lex.check_token(is,","); expression *x3, *y3; read_coordinate_expression(is,B,x3,y3); lex.check_token(is,")"); return new draw_triangle(x1,y1,x2,y2,x3,y3); } draw_ellipse* parser::read_draw_ellipse(istream& is,list& B) { lex.check_token(is,"("); expression *x, *y, *tmp; read_coordinate_expression(is,B,x,y); lex.check_token(is,","); tmp = exprparser.read(is,B); expression *a = tmp->simplify(); delete tmp; lex.check_token(is,","); tmp = exprparser.read(is,B); expression *b = tmp->simplify(); delete tmp; lex.check_token(is,")"); return new draw_ellipse(x,y,a,b); } draw_figure* parser::read_draw_figure(istream& is,list& B, figure_descriptor* d) { draw_figure * df = new draw_figure(d); lex.check_token(is,"("); for(int i=0; i< d->get_argc(); i++) { expression * tmp = exprparser.read(is,B); df->add_expression(tmp->simplify()); delete tmp; if (i != d->get_argc() - 1) { lex.check_token(is,","); } } lex.check_token(is,")"); return df; } statement* parser::read_statement(istream& is,list& B) { const char* token = lex.get_token(is); statement * s = (statement*)0; if (strcmp(token,"set") == 0) { // set token = lex.get_token(is); if (strcmp(token,"pen_color") == 0 || strcmp(token,"fill_color") == 0 ) { lex.putback(); s = read_set_color(is,B); } else if (strcmp(token,"filled") == 0 || strcmp(token,"rotate") == 0 || strcmp(token,"center_angle") == 0 || strcmp(token,"rotation_angle") == 0 || strcmp(token,"depth") == 0 || strcmp(token,"order") == 0) { lex.putback(); s = read_set_single_val(is,B); } else if (strcmp(token,"rotation_center") == 0) { lex.putback(); s = read_set_rotation_center(is,B); } else { throw new parse_error(lex.get_line_number(),"unknown parameter"); } lex.check_token(is,";"); } else if (strcmp(token,"draw") == 0) { // draw token = lex.get_token(is); if (strcmp(token,"point") == 0) { // point s = read_draw_point(is,B); } else if (strcmp(token,"line") == 0) { // line s = read_draw_line(is,B); } else if (strcmp(token,"circle") == 0) { // circle s = read_draw_circle(is,B); } else if (strcmp(token,"triangle") == 0) { // triangle s = read_draw_triangle(is,B); } else if (strcmp(token,"square") == 0) { // square s = read_draw_square(is,B); } else if (strcmp(token,"rectangle") == 0) { // rectangle s = read_draw_rectangle(is,B); } else if (strcmp(token,"ellipse") == 0) { // ellipse s = read_draw_ellipse(is,B); } else { // a figure from symbol table figure_descriptor* d = T.find_descriptor(token); if (d == (figure_descriptor*)0) { throw new parse_error(lex.get_line_number(), "unknown figure"); } s = read_draw_figure(is,B,d); } lex.check_token(is,";"); } else if (strcmp(token,"if") == 0) { // if s = read_conditional(is,B); } else if (strcmp(token,"print") == 0) { // print token = lex.check_token(is,LEX_STRING); s = new print_statement(token); lex.check_token(is,";"); } else { throw new parse_error(lex.get_line_number(),"unknown command"); } return s; } void parser::read_figure_descriptor(istream& is) { // figure has already been read char name[128]; strcpy(name,lex.get_token(is)); // figue if (T.find_descriptor(name) != (figure_descriptor*)0) { throw new parse_error(lex.get_line_number(), "figure already defined"); } lex.check_token(is,"("); list B; // bindings list_iterator I; int nof_params = 0; while(true) { const char* symbol = lex.get_token(is); if (strcmp(symbol,")") == 0) break; // params read I = B.first(); while(I.has_more_elements()) { if (strcmp(*I,symbol) == 0) { // re-declared throw new parse_error(lex.get_line_number(), "duplicate identifier in parameter list"); } I++; } char* s = new char[strlen(symbol)+1]; strcpy(s,symbol); B.insert_after(B.last(),s); nof_params++; symbol = lex.get_token(is); if (strcmp(symbol,",") == 0) continue; else lex.putback(); } figure_descriptor *d = new figure_descriptor(name,nof_params); T.add_descriptor(d); lex.check_token(is,"{"); while(true) { const char* symbol = lex.get_token(is); if (strcmp(symbol,"}") == 0) break; // done lex.putback(); d->add_statement(read_statement(is,B)); } I = B.first(); while(I.has_more_elements()) { delete [] *I; I++; } } void parser::parse(drawable_list& L, istream& is) { const char* token; token = lex.next_token(is); bool canvas_defined = false, system_defined = false; list B; // fake binding double *V = (double*)0; // fake values while(token != (char*)0) { if (strcmp(token,"define") == 0) { token = lex.get_token(is); if (strcmp(token,"canvas") == 0) { lex.check_token(is,"("); xres = (int)read_eval_exp(is,B,V); lex.check_token(is,","); yres = (int)read_eval_exp(is,B,V); lex.check_token(is,")"); if (xres <= 0 || yres <= 0) { throw new parse_error(lex.get_line_number(), "invalid resolution"); } canvas_defined = true; } else if (strcmp(token,"system") == 0) { lex.check_token(is,"("); xmin = read_eval_exp(is,B,V); lex.check_token(is,","); ymin = read_eval_exp(is,B,V); lex.check_token(is,","); xmax = read_eval_exp(is,B,V); lex.check_token(is,","); ymax = read_eval_exp(is,B,V); lex.check_token(is,")"); if (xmax <= xmin || ymax <= ymin) { throw new parse_error(lex.get_line_number(), "invalid system dimensions"); } system_defined = true; } else { throw new parse_error(lex.get_line_number(), "system or canvas expected"); } lex.check_token(is,";"); } else if (strcmp(token,"draw") == 0) { // draw if (!system_defined || !canvas_defined) { throw new parse_error(lex.get_line_number(), "system and canvas must be defined before draw"); } token = lex.get_token(is); if (strcmp(token,"point") == 0) { // draw point L.insert(read_point(is,B,V)); } else if (strcmp(token,"line") == 0) { // draw line L.insert(read_line(is,B,V)); } else { // shape lex.putback(); read_shape(is,B,V,L); } lex.check_token(is,";"); } else if (strcmp(token,"set") == 0) { // set param token = lex.get_token(is); if (strcmp(token,"pen_color") == 0) { gc.pen_color = read_color(is,B,V); } else if (strcmp(token,"fill_color") == 0) { gc.fill_color = read_color(is,B,V); } else if (strcmp(token,"filled") == 0) { gc.filled = read_eval_exp(is,B,V) > 0; } else if (strcmp(token,"rotate") == 0) { gc.rotate = read_eval_exp(is,B,V) > 0; } else if (strcmp(token,"rotation_center") == 0) { gc.rotation_center = read_coordinate(is,B,V); } else if (strcmp(token,"rotation_angle") == 0) { gc.rotation_angle = read_eval_exp(is,B,V); } else if (strcmp(token,"rotation_center") == 0) { gc.rotation_angle = read_eval_exp(is,B,V); } else if (strcmp(token,"center_angle") == 0) { gc.center_angle = read_eval_exp(is,B,V); } else if (strcmp(token,"depth") == 0) { gc.depth = (int)read_eval_exp(is,B,V); } else if (strcmp(token,"order") == 0) { gc.order = (int)read_eval_exp(is,B,V); } else { throw new parse_error(lex.get_line_number(), "invalid parameter"); } lex.check_token(is,";"); } else if(strcmp(token,"figure") == 0) { if (!system_defined || !canvas_defined) { throw new parse_error(lex.get_line_number(), "system and canvas must be defined before figure definition"); } read_figure_descriptor(is); // HERE } else { throw parse_error(lex.get_line_number(),"unknown command"); } token = lex.next_token(is); } // while } int parser::x_resolution() const { return xres; } int parser::y_resolution() const { return yres; }