/// <summary> /// converting from NPL code to xml element /// </summary> /// <param name="npl_code">the statement must be like msg = {...}</param> /// <returns></returns> public static XmlElement NPLCodeToXmlElement(string npl_code) { NPLLex lex = new NPLLex(); NPLLex.LexState ls = lex.SetInput(npl_code); ls.nestlevel = 0; XmlDocument doc = new XmlDocument(); try { /** read first token*/ next(ls); XmlElement result = DataStatementToXmlElement(doc, ls); if (result != null) { testnext(ls, ';'); if (ls.t.token == (int)NPLLex.RESERVED.TK_EOS) { return result; } else { throw new Exception("only one table or data statement in input string is allowed."); } } } catch (Exception e) { ParaGlobal.log(e.ToString()); ParaGlobal.log("\r\n"); return null; } return null; }
public static int testnext(NPLLex.LexState ls, int c) { if (ls.t.token == c) { next(ls); return 1; } else return 0; }
public static void lookahead(NPLLex.LexState ls) { System.Diagnostics.Debug.Assert(ls.lookahead.token == (int)NPLLex.RESERVED.TK_EOS); ls.lookahead.token = NPLLex.luaX_lex(ls, ls.lookahead.seminfo); }
public static void next(NPLLex.LexState ls) { ls.lastline = ls.linenumber; if (ls.lookahead.token != (int)NPLLex.RESERVED.TK_EOS) { /* is there a look-ahead token? */ ls.t = ls.lookahead; /* use this one */ ls.lookahead.token = (int)NPLLex.RESERVED.TK_EOS; /* and discharge it */ } else ls.t.token = NPLLex.luaX_lex(ls, ls.t.seminfo); /* read next token */ }
public static void error_expected(NPLLex.LexState ls, int token) { NPLLex.luaX_syntaxerror(ls, string.Format("'{0}' expected", NPLLex.luaX_token2str(ls, token))); }
public static void leavelevel(NPLLex.LexState ls) { --ls.nestlevel; }
public static void enterlevel(NPLLex.LexState ls) { if (++(ls.nestlevel) > LUA_MAXPARSERLEVEL) NPLLex.luaX_syntaxerror(ls, "too many syntax levels"); }
/// <summary> /// Parse: name = data | table /// Basically, there is only one statement like msg = {...} in a web service or NPL activation call. /// </summary> /// <param name="doc"></param> /// <param name="ls"></param> /// <returns> XmlElement with the name is returned. null is returned if input is invalid</returns> public static XmlElement DataStatementToXmlElement(XmlDocument doc, NPLLex.LexState ls) { if (ls.t.token == (int)NPLLex.RESERVED.TK_NAME && ls.t.seminfo.ts == "msg") { XmlElement node = doc.CreateElement(ls.t.seminfo.ts); next(ls); if (ls.t.token == '=') { next(ls); if (FillDataToXmlElement(doc, ls, node)) { return node; } } } return null; }
public static void check_match(NPLLex.LexState ls, int what, int who, int where) { if (testnext(ls, what) == 0) { if (where == ls.linenumber) error_expected(ls, what); else { NPLLex.luaX_syntaxerror(ls, string.Format("'{0}' expected (to close `{1}' at line {2})", NPLLex.luaX_token2str(ls, what), NPLLex.luaX_token2str(ls, who), where)); } } }
public static void check(NPLLex.LexState ls, int c) { if (testnext(ls, c) == 0) error_expected(ls, c); }
/// <summary> /// Parse: data | table /// NPL uses a similar element name for basic data types as in soap and xml/rpc /// Supported NPL types are table, boolean, string, double, index, nil. /// e.g. the NPL table msg={x=2, [1]="string value",OK=true} will be serialized to following table. /// <msg> /// <x type="double">2</x> /// <param index=1 type="string" >string value</param> /// <OK type="boolean">true</OK> /// </msg> /// the input NPL table key name better not be the above name to avoid confusion. /// </summary> /// <param name="doc"></param> /// <param name="ls"></param> /// <param name="ParentNode"></param> /// <returns>true if there are data to fill </returns> public static bool FillDataToXmlElement(XmlDocument doc, NPLLex.LexState ls, XmlElement ParentNode) { // data int c = ls.t.token; switch (c) { case (int)NPLLex.RESERVED.TK_TRUE: { ParentNode.SetAttribute("type", "boolean"); ParentNode.InnerText = "true"; next(ls); return true; } case (int)NPLLex.RESERVED.TK_FALSE: { ParentNode.SetAttribute("type", "boolean"); ParentNode.InnerText = "false"; next(ls); return true; } case (int)NPLLex.RESERVED.TK_NIL: { ParentNode.SetAttribute("type", "nil"); next(ls); return true; } case (int)NPLLex.RESERVED.TK_NUMBER: { ParentNode.SetAttribute("type", "double"); // TODO: what kind of encoding should we use? otherwise, we may be sending long string, like 0.00000000 ParentNode.InnerText = ls.t.seminfo.r.ToString(); next(ls); return true; } case (int)NPLLex.RESERVED.TK_STRING: { ParentNode.SetAttribute("type", "string"); /// Note:2008.3.27: I found that the xmlserializer strips away \r\n out during deserialization (and just leave \n). WebService strips out \r\n (an leave \n) even using XMLNode.SetInnerText(). /// so the msg code sending using InnerText of XML web service call will have \r removed. This leads to errors for scode. /// A workaround is to replace \r and \n with 
 and 
 respectively in FillDataToXmlElement of NPLParser.cs for string type. In fact, I just replace \r, since \n is not removed. /// // ParentNode.InnerText = ls.t.seminfo.ts; ParentNode.InnerText = ls.t.seminfo.ts.Replace("\r", "
"); next(ls); return true; } case '-': { // negative number next(ls); if (ls.t.token == (int)NPLLex.RESERVED.TK_NUMBER) { ParentNode.SetAttribute("type", "double"); // TODO: what kind of encoding should we use? otherwise, we may be sending long string, like 0.00000000 ParentNode.InnerText = "-" + ls.t.seminfo.r.ToString(); next(ls); return true; } else return false; } case '{': { enterlevel(ls); bool bBreak = false; next(ls); int nAutoIndex = 1; while (!bBreak) { c = ls.t.token; if (c == '}') { // end of table leavelevel(ls); next(ls); bBreak = true; } else if (c == (int)NPLLex.RESERVED.TK_NAME) { XmlElement node = doc.CreateElement(ls.t.seminfo.ts); // by name assignment, such as name = data|table next(ls); if (ls.t.token == '=') { next(ls); if (!FillDataToXmlElement(doc, ls, node)) return false; testnext(ls, ','); ParentNode.AppendChild(node); } else return false; } else if (c == '[') { // by integer or string key assignment, such as [number|String] = data|table next(ls); XmlElement node = null; if (ls.t.token == (int)NPLLex.RESERVED.TK_NUMBER) { // verify that it is an integer, instead of a floating value. node = doc.CreateElement("param"); node.SetAttribute("index", Convert.ToInt16(ls.t.seminfo.r).ToString()); } else if (ls.t.token == (int)NPLLex.RESERVED.TK_STRING) { // verify that the string is a value key(non-empty); if (ls.t.seminfo.ts.Length == 0) return false; node = doc.CreateElement(ls.t.seminfo.ts); } else return false; next(ls); if (ls.t.token == ']') { next(ls); if (ls.t.token == '=') { next(ls); if (!FillDataToXmlElement(doc, ls, node)) return false; testnext(ls, ','); ParentNode.AppendChild(node); } else return false; } } /// Fixed: 2008.6.3 LiXizhi /// the following is for auto indexed table items {"string1", "string2\r\n", 213, nil,["A"]="B", true, false, {"another table", "field1"}} else if (c == (int)NPLLex.RESERVED.TK_STRING || c == (int)NPLLex.RESERVED.TK_NUMBER || c == (int)NPLLex.RESERVED.TK_NIL || c == (int)NPLLex.RESERVED.TK_FALSE || c == (int)NPLLex.RESERVED.TK_TRUE || c == '{') { XmlElement node = doc.CreateElement("param"); node.SetAttribute("index", nAutoIndex.ToString()); if (!FillDataToXmlElement(doc, ls, node)) return false; testnext(ls, ','); ParentNode.AppendChild(node); nAutoIndex++; } else { return false; } }; return true; } default: return false; } }