fcp-js-analytic.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /**
  2. * 注册命名空间:baidu.jsAnalytic
  3. */
  4. baidu.namespace.register("baidu.jsAnalytic");
  5. /**
  6. * Javascript代码词法分析
  7. * @author lichengyin (FCP:PHP代码)
  8. * @cover zhaoxianlie (FCPHelper:将PHP代码重写为Javascript代码)
  9. */
  10. baidu.jsAnalytic = function(){
  11. this.parsePos = 0;
  12. this.content = '';
  13. this.contentLength = 0;
  14. this._output = [];
  15. this._whitespace = /[\n\r\t\s]/g;
  16. this._wordchar = /[a-zA-Z0-9_\$]/g;
  17. this._digits = /[0-9]/g;
  18. this._punct = /\+|-|\*|\/|%|&|\+\+|\-\-|=|\+=|\-=|\*=|\/=|%=|==|===|!=|!==|>|<|>=|<=|>>|<<|>>>|>>>=|>>=|<<=|&&|&=|\||\|\||!|!!|,|:|\?|\^|\^=|_|\|=|::/g;
  19. /**
  20. * 主方法
  21. * @param {Object} $content
  22. */
  23. this.run = function($content){
  24. this.content = $content.trim().replace(/\r\n/g, "\n");
  25. this.contentLength = this.content.length;
  26. this.tokenAnalytic();
  27. return this._output;
  28. };
  29. /**
  30. * 此法分析器
  31. */
  32. this.tokenAnalytic = function(){
  33. while (true){
  34. $token = this.getNextToken();
  35. if ($token){
  36. if ($token[1] === baidu.FL.FL_EOF) break;
  37. this._output.push($token);
  38. }
  39. }
  40. };
  41. /**
  42. * 检测$char是否在$array中
  43. * @param {Object} $char
  44. * @param {Object} $array
  45. */
  46. this._is_match = function($char,$reg){
  47. return $reg.test($char);
  48. };
  49. /**
  50. * 单个此法分析
  51. */
  52. this.getNextToken = function(){
  53. if (this.parsePos >= this.contentLength){
  54. return ['', baidu.FL.FL_EOF];
  55. }
  56. var $char = this.content[this.parsePos];
  57. var $result,$tokenCount,$lastText,$lastType;
  58. this.parsePos++;
  59. while (this._is_match($char, this._whitespace)){
  60. if (this.parsePos >= this.contentLength){
  61. return ['', baidu.FL.FL_EOF];
  62. }
  63. if ($char === "\x0d") return '';
  64. if ($char === "\x0a"){
  65. return [$char, baidu.FL.FL_NEW_LINE];
  66. }
  67. $char = this.content[this.parsePos];
  68. this.parsePos++;
  69. }
  70. //处理正常的字符
  71. if (this._is_match($char, this._wordchar)){
  72. $result = this._getWordToken($char);
  73. if ($result) return $result;
  74. }
  75. switch (true){
  76. case $char === '(' || $char === '[' : return [$char, baidu.FL.JS_START_EXPR];
  77. case $char === ')' || $char === ']' : return [$char, baidu.FL.JS_END_EXPR];
  78. case $char === '{' : return [$char, baidu.FL.JS_START_BLOCK];
  79. case $char === '}' : return [$char, baidu.FL.JS_END_BLOCK];
  80. case $char === ';' : return [$char, baidu.FL.JS_SEMICOLON];
  81. }
  82. //注释或者正则
  83. if ($char === '/'){
  84. //注释
  85. $result = this._getCommentToken($char);
  86. if ($result) return $result;
  87. //正则
  88. $tokenCount = this._output.length;
  89. if ($tokenCount){
  90. var _tem = this._output[$tokenCount - 1];
  91. $lastText = _tem[0];
  92. $lastType = _tem[1];
  93. }else {
  94. $lastType = baidu.FL.JS_START_EXPR;
  95. }
  96. if (($lastType === baidu.FL.JS_WORD && ($lastText === 'return' || $lastText === 'to'))
  97. || ($lastType === baidu.FL.JS_START_EXPR
  98. || $lastType === baidu.FL.JS_START_BLOCK
  99. || $lastType === baidu.FL.JS_END_BLOCK
  100. || $lastType === baidu.FL.JS_OPERATOR
  101. || $lastType === baidu.FL.JS_EQUALS
  102. || $lastType === baidu.FL.JS_SEMICOLON
  103. || $lastType === baidu.FL.FL_EOF
  104. )){
  105. $result = this._getRegexpToken($char);
  106. if ($result) return $result;
  107. }
  108. }
  109. //引号
  110. if ($char === '"' || $char === "'"){
  111. $result = this._getQuoteToken($char);
  112. if ($result) return $result;
  113. }
  114. //sharp variables
  115. if ($char === '#'){
  116. $result = this._getSharpVariblesToken($char);
  117. if ($result) return $result;
  118. }
  119. //操作符
  120. if (this._is_match($char, this._punct)){
  121. $result = this._getPunctToken($char);
  122. if ($result) return $result;
  123. }
  124. return [$char, baidu.FL.FL_NORMAL];
  125. };
  126. /**
  127. * 正常的字符
  128. * @param {Object} $char
  129. */
  130. this._getWordToken = function($char){
  131. var $sign,$t;
  132. while (this._is_match(this.content[this.parsePos], this._wordchar)
  133. && this.parsePos < this.contentLength){
  134. $char += this.content[this.parsePos];
  135. this.parsePos++;
  136. }
  137. //处理带E的数字,如:20010E+10,0.10E-10
  138. if ((this.content[this.parsePos] === '+' || this.content[this.parsePos] === '-')
  139. && /^[0-9]+[Ee]$/.test()
  140. && this.parsePos < this.contentLength){
  141. $sign = this.content[this.parsePos];
  142. this.parsePos++;
  143. $t = this.getNextToken();
  144. $char += $sign . $t[0];
  145. return [$char, baidu.FL.JS_WORD];
  146. }
  147. //for in operator
  148. if ($char === 'in'){
  149. return [$char , baidu.FL.JS_OPERATOR];
  150. }
  151. return [$char, baidu.FL.JS_WORD];
  152. };
  153. /**
  154. * 注释
  155. * @param {Object} $char
  156. */
  157. this._getCommentToken = function($char){
  158. var $comment = '';
  159. var $lineComment = true;
  160. var $c = this.content[this.parsePos];
  161. var $cc,$lineComment;
  162. //单行或者多行注释
  163. if($c === '*'){
  164. this.parsePos++;
  165. while (!(this.content[this.parsePos] === '*'
  166. && this.content[this.parsePos + 1]
  167. && this.content[this.parsePos + 1] === '/')
  168. && this.parsePos < this.contentLength){
  169. $cc = this.content[this.parsePos];
  170. $comment += $cc;
  171. //\x0d为\r, \x0a为\n
  172. if ($cc === "\x0d" || $cc === "\x0a"){
  173. $lineComment = false;
  174. }
  175. this.parsePos++;
  176. }
  177. this.parsePos += 2;
  178. //ie下的条件编译
  179. if ($comment.indexOf('@cc_on') === 0){
  180. return ['/*' + $comment + '*/', baidu.FL.JS_IE_CC];
  181. }
  182. if ($lineComment){
  183. return ['/*' + $comment + '*/', baidu.FL.JS_INLINE_COMMENT];
  184. }else{
  185. return ['/*' + $comment + '*/', baidu.FL.JS_BLOCK_COMMENT];
  186. }
  187. }
  188. //单行注释
  189. if ($c === '/'){
  190. $comment = $char;
  191. //\x0d为\r, \x0a为\n
  192. while (this.content[this.parsePos] !== "\x0d"
  193. && this.content[this.parsePos] !== "\x0a"
  194. && this.parsePos < this.contentLength){
  195. $comment += this.content[this.parsePos];
  196. this.parsePos++;
  197. }
  198. this.parsePos++;
  199. return [$comment, baidu.FL.JS_COMMENT];
  200. }
  201. };
  202. /**
  203. * 引号
  204. * @param {Object} $char
  205. */
  206. this._getQuoteToken = function($char){
  207. var $sep = $char;
  208. var $escape = false;
  209. var $resultString = $char;
  210. while (this.content[this.parsePos] !== $sep || $escape){
  211. $resultString += this.content[this.parsePos];
  212. $escape = !$escape ? (this.content[this.parsePos] === "\\") : false;
  213. this.parsePos++;
  214. if (this.parsePos >= this.contentLength){
  215. return [$resultString, baidu.FL.JS_STRING];
  216. }
  217. }
  218. this.parsePos++;
  219. $resultString += $sep;
  220. return [$resultString, baidu.FL.JS_STRING];
  221. };
  222. /**
  223. * 正则
  224. * @param {Object} $char
  225. */
  226. this._getRegexpToken = function($char){
  227. var $sep = $char;
  228. var $escape = false;
  229. var $resultString = $char;
  230. var $inCharClass = false;
  231. while ($escape || $inCharClass || this.content[this.parsePos] !== $sep){
  232. $resultString += this.content[this.parsePos];
  233. if (!$escape){
  234. $escape = (this.content[this.parsePos] === "\\");
  235. if (this.content[this.parsePos] === '['){
  236. $inCharClass = true;
  237. }else if(this.content[this.parsePos] === ']'){
  238. $inCharClass = false;
  239. }
  240. }else {
  241. $escape = false;
  242. }
  243. this.parsePos++;
  244. if (this.parsePos >= this.contentLength){
  245. return [$resultString, baidu.FL.JS_REGEXP];
  246. }
  247. }
  248. this.parsePos++;
  249. $resultString += $sep;
  250. while (this._is_match(this.content[this.parsePos], this._wordchar)
  251. && this.parsePos < this.contentLength ) {
  252. $resultString += this.content[this.parsePos];
  253. this.parsePos++;
  254. }
  255. return [$resultString, baidu.FL.JS_REGEXP];
  256. };
  257. /**
  258. * sharp varibles
  259. * @param {Object} $char
  260. */
  261. this._getSharpVariblesToken = function($char){
  262. var $sharp = $char;
  263. var $c,$next;
  264. if (this._is_match(this.content[this.parsePos], this._digits)){
  265. do{
  266. $c = this.content[this.parsePos];
  267. $sharp += $c;
  268. this.parsePos++;
  269. }while ($c !== '#' && $c !== '=' && this.parsePos < this.contentLength);
  270. $next = this.content.substr( this.parsePos, 2);
  271. if ($next === '[]' || $next === '{}'){
  272. $sharp += $next;
  273. this.parsePos += 2;
  274. }
  275. return [$sharp, baidu.FL.JS_WORD];
  276. }
  277. };
  278. /**
  279. * 操作符
  280. * @param {Object} $char
  281. */
  282. this._getPunctToken = function($char){
  283. while (this._is_match($char + this.content[this.parsePos], this._punct)
  284. && this.parsePos < this.contentLength){
  285. $char += this.content[this.parsePos];
  286. this.parsePos++;
  287. }
  288. return [$char, $char === '=' ? baidu.FL.JS_EQUALS : baidu.FL.JS_OPERATOR];
  289. };
  290. }