/// <summary> /// Gets the data type of the very first variable in the expression. Might want to replace with a more sophisticated type checking system later. /// Right now it finds the type of first variable and assume the rest of the expression lines up properly. /// </summary> /// <param name="exp"></param> /// <param name="vars"></param> /// <returns></returns> public static PezLexType GetTypeOfFirstVar(Node exp, List <Lexeme> vars) //exp is right subtree of assignment operation ast. { PezLexType type = PezLexType.unid; Queue <Node> nq = new Queue <Node>(); nq.Enqueue(exp); while (nq.Count > 0) { Node n = nq.Dequeue(); for (int i = 0; i < vars.Count; i++) { if (vars[i].token == n.data.token) { return(vars[i].LType); } } if (n.left != null) { nq.Enqueue(n.left); } if (n.right != null) { nq.Enqueue(n.right); } } return(type); }
/// <summary> /// Writes assignment statements in which the variable is both declared and assigned a value. /// </summary> /// <param name="ast"></param> /// <param name="scope"></param> private void WriteAssignmentState(Node ast, int scope) { AppendScope(scope); Node exp; string partial = " " + ast.left.data.token + " " + ast.data.token + " "; //variables.Add(ast.left.data); //ast.left will always be the name of the variable being assigned. PezLexType type = Parser.FindLexDataType(ast); TopOfSwitch: switch (type) { case PezLexType.id: //variable only assignment operation //access the first variable being operated on and return its type type = Parser.GetTypeOfFirstVar(ast.right, variables); goto TopOfSwitch; //repeat with found datatype. case PezLexType._int: source.Append("int" + partial); //for now, we are only doing integers so this is the type. exp = ast.right; //This subset tree of the assignment ast is the expression/value. source.Append(Parser.GetInfixExpression(exp)); ast.left.data.LType = PezLexType._int; //change identifer to int. variables.Add(ast.left.data); //add to variables table. break; case PezLexType._float: source.Append("float" + partial); //for now, we are only doing integers so this is the type. exp = ast.right; //This subset tree of the assignment ast is the expression/value. source.Append(Parser.GetInfixExpression(exp)); ast.left.data.LType = PezLexType._float; variables.Add(ast.left.data); break; case PezLexType._double: source.Append("double" + partial); //for now, we are only doing integers so this is the type. exp = ast.right; //This subset tree of the assignment ast is the expression/value. source.Append(Parser.GetInfixExpression(exp)); ast.left.data.LType = PezLexType._double; variables.Add(ast.left.data); break; case PezLexType._string: //add strings BEFORE going to C if necessary. source.Append("char*" + partial); source.Append(ProcessAssignmentStringState(ast.right)); ast.left.data.LType = PezLexType._string; variables.Add(ast.left.data); break; default: throw new Exception("TranslateC:WriteAssignmentState:: PezLexType is not a C primitive data type or used variable is not declared on Statement Number: " + statementNum); } source.AppendLine(";"); //string test = Parser.GetInfixExpression(ast.right); }
public static PezLexType FindLexDataType(Node root) { PezLexType type = PezLexType.unid; Queue <Node> nq = new Queue <Node>(); nq.Enqueue(root); int idTally = 0; while (nq.Count > 0) { Node n = nq.Dequeue(); if (n.data.LType == PezLexType.id) { idTally++; } if (IsType(n.data.LType)) { return(n.data.LType); } if (n.left != null) { nq.Enqueue(n.left); } if (n.right != null) { nq.Enqueue(n.right); } } if (idTally > 1) //identifier in the case that only variables are used in operations rather than types. should be > 1 because assignment ops always have at least 1 identifier. { return(PezLexType.id); } Console.Out.WriteLine(type.ToString()); return(type); }
public static bool IsType(PezLexType type) { string[] en = Enum.GetNames(typeof(PezLexType)); int t = (int)type; int r = -1; //max range for (int i = 0; i < en.Length; i++) { if (en[i] == Enum.GetName(typeof(PezLexType), PezLexType._double)) { r = i; break; } } if (t < r) { return(true); //_int should ALWAYS be @ 0 in PezLexType. } else { return(false); } }
public Lexeme(PezLexType type, string token) { LType = type; this.token = token; }
/// <summary> /// Returns the next lexeme/token in the file based on a list of separators defined in PezSym. /// </summary> /// <returns>The next lexeme/token in a file.</returns> private Lexeme Next() { Lexeme lex; StringBuilder sb = new StringBuilder(); if (!HasNextChar()) { return(new Lexeme(PezLexType.termin, eof)); } //Note: file[offset] is the current character we are looking at. //whitespace is first because i expect to read in a stream of \t when if statements pop up to determine scope. if (char.IsWhiteSpace(file[offset])) //we count \t as a scope token. \r\n is our terminating token. { switch (file[offset]) { case '\t': lex = new Lexeme(PezLexType.scoper, ";t"); // ; will be my marker for escape characters. ;t = \t but easier to recognize in output. ;rn = \r\n offset++; return(lex); case '\r': //\r\n lex = new Lexeme(PezLexType.termin, ";rn"); if (HasNextChar(1) && file[offset + 1] == '\n') { offset++; //skip \n } return(lex); default: offset++; return(Next()); //if bugs happen, it's probably here } } else if (file[offset] == '"') //string literal beginning. anything surrounded in quotations is a string. { sb.Append(file[offset]); //add quotation offset++; while (HasNextChar() && file[offset] != '"') { sb.Append(file[offset]); offset++; } sb.Append(file[offset]); //should be a closing quotation. offset++; //check to see if someone missed a quotation if (!HasNextChar() && sb[sb.Length - 1] != '"') { throw new Exception("Lexer:StringLiteral:: Missing Quotation."); } lex = new Lexeme(PezLexType._string, sb.ToString()); return(lex); } else if (char.IsLetter(file[offset])) //read until space as an identifier or type name. note: ids can be types. { while (HasNextChar() && char.IsLetterOrDigit(file[offset])) { sb.Append(file[offset]); offset++; } lex = new Lexeme(PezLexType.id, sb.ToString()); return(lex); } else if (char.IsDigit(file[offset])) //read value until space. test to see if it is an integer or float. { PezLexType type = PezLexType.unid; while (HasNextChar() && (char.IsDigit(file[offset]) || file[offset] == '.')) { if (file[offset] == '.') { type = PezLexType._float; } sb.Append(file[offset]); offset++; } if (type == PezLexType.unid) //probably an integer so lets test. { int val; if (!int.TryParse(sb.ToString(), out val)) { throw new Exception("Lexer:Digit:: Value is too big for an integer."); } lex = new Lexeme(PezLexType._int, sb.ToString()); return(lex); } else //type of float OR double. but we assume double here for now. { float val; double dval; if (!float.TryParse(sb.ToString(), out val)) //too big for a float { if (!double.TryParse(sb.ToString(), out dval)) { throw new Exception("Lexer:Digit:: Value is too big to be contained within a double."); } //return it as a double lex = new Lexeme(PezLexType._double, sb.ToString()); return(lex); } //it can fit in a float so return it as float lex = new Lexeme(PezLexType._float, sb.ToString()); return(lex); } } else if ((39 < file[offset]) && (file[offset] < 48) || file[offset] == '=') //42 - 47 are basic ops 40 and 41 are ( ) { if (file[offset] == 40) { lex = new Lexeme(PezLexType.l_paren, file[offset].ToString()); // ( offset++; return(lex); } else if (file[offset] == 41) { lex = new Lexeme(PezLexType.r_paren, file[offset].ToString()); // ) offset++; return(lex); } //theoretically can use .= .+ .- as operators... while (HasNextChar() && (41 < file[offset]) && (file[offset] < 48) || file[offset] == '=') //(41 < c < 48) //TODO: Move assignment to boolean lex for expressions later. { sb.Append(file[offset]); offset++; } lex = new Lexeme(PezLexType.op, sb.ToString()); return(lex); } else if (HasNextChar() && file[offset] == ':') //range operator or colon operators. { sb.Append(file[offset]); offset++; if (HasNextChar() && file[offset] == ':') //specifically range operators at the moment. { sb.Append(file[offset]); offset++; lex = new Lexeme(PezLexType.op, sb.ToString()); return(lex); } else { throw new Exception("Invalid range operator at: " + offset); } } else if (file[offset] == '#')//# will be my comment symbol much like R language. { //ignore the rest of the line by finding \r\n then going offset++ then return next() while (true) { offset++; if (!HasNextChar()) { return(new Lexeme(PezLexType.termin, eof)); } if (file[offset] == '\r') { offset++; if (HasNextChar() && file[offset] == '\n') { offset++; return(new Lexeme(PezLexType.termin, ";rn")); } else { throw new Exception("Lexer:Next:: ;r not followed by ;n. Pez requires Windows CRLF line endings to function."); } } } } else { throw new Exception("Lexer:Next:: Unidentified token encountered at offset: " + offset); } }