All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ajaxjs.js.jsonparser.lexer.Lexer Maven / Gradle / Ivy

Go to download

AJAXJS aims to full-stack, not only the server-side framework, but also integrates the front-end library. It'€™s written in HTML5 + Java, a successor to the JVM platform, efficient, secure, stable, cross-platform and many other advantages, but it abandoned the traditional enterprise architecture brought about by the large and bloated, emphasizing the lightweight, and fast, very suitable for the Internet fast application.

There is a newer version: 1.2.6
Show newest version
/**
 * Copyright Sp42 [email protected] 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.ajaxjs.js.jsonparser.lexer;

import java.util.Stack;

import com.ajaxjs.js.jsonparser.JSONParser;
import com.ajaxjs.js.jsonparser.JsonParseException;

/**
 * 词法分析器
 */
public class Lexer {
	/**
	 * 当前行号
	 */
	private int lineNum;

	/**
	 * 用于记录每一行的起始位置
	 */
	private Stack colMarks = new Stack<>();

	/**
	 * 用于报错的行游标
	 */
	private int startLine;

	/**
	 * 用于报错的列游标
	 */
	private int startCol;

	/**
	 * 当前字符游标
	 */
	private int cur = -1;
	/**
	 * 保存当前要解析的字符串
	 */
	private String str;

	/**
	 * 保存当前要解析的字符串的长度
	 */
	private int len;

	/**
	 * JsonLex构造函数
	 * 
	 * @param str 要解析的字符串
	 */
	public Lexer(String str) {
		this.str = str;
		this.len = str.length();
		this.startLine = 0;
		this.startCol = 0;
		this.cur = -1;
		this.lineNum = 0;
		this.colMarks.push(0);
	}

	/**
	 * 获取当前游标所在的字符
	 * 
	 * @return 当前字符
	 */
	public char getCurChar() {
		return cur >= len - 1 ? 0 : str.charAt(cur);
	}

	/**
	 * 检查字符串是否结束
	 */
	private void checkEnd() {
		if (cur >= len - 1)
			throw exceptionFactory("未预期的结束,字符串未结束");
	}

	// str \"(\\\"|[^\"])*\"
	// def [_a-zA-Z][_a-zA-Z0-9]*
	// num -?[0-9]+(\.[0-9]+)?
	// space [ \t\n]+
	/**
	 * 获取下一个Token的主函数 Next这个方法循环调用nextChar获取下一个字符,碰见某种类型的初始字符,就开始进入相应Token类型的处理函数中
	 * @return 最终返回Token类型的对象
	 */
	public Token next() {
		if (lineNum == 0) {
			lineNum = 1;
			return Tokens.BGN;
		}

		char c;
		while ((c = nextChar()) != 0) {
			startLine = lineNum;
			startCol = getColNum();

			if (c == '"' || c == '\'') {
				String s = getStrValue(c);
				return new StringToken(s);
			} else if (JSONParser.isLetterUnderline(c)) {
				return getDefToken();
			} else if (JSONParser.isNum(c) || c == '-') {
				return new NumberToken(getNumValue());
			} else if (JSONParser.isSpace(c)) {
				continue;
			} else {
				return parseSymbol(c);
			}
		}

		if (c == 0)
			return Tokens.EOF;

		return null;
	}

	/**
	 * 获取字符串的值
	 * 
	 * @param s 传入的字符
	 * @return 字符串的值
	 */
	private String getStrValue(char s) {
		int start = cur;
		char c;

		while ((c = nextChar()) != 0) {
			if (c == '\\') {// 跳过斜杠以及后面的字符
				c = nextChar();
			} else if (s == c) { // 遇到结束的 引号 结束了 返回这个字符串
				return str.substring(start + 1, cur);
			}
		}

		checkEnd();
		return null;
	}

	/**
	 * 获取数字的值
	 * 
	 * @return 数字的值
	 */
	private String getNumValue() {
		int start = cur;
		char c;

		while ((c = nextChar()) != 0) {
			if (!JSONParser.isDecimal(c))
				return str.substring(start, revertChar());
		}

		checkEnd();
		return null;
	}

	/**
	 * 用来处理 true、false、null 和对象 key 的值
	 * 
	 * @return true、false、null 的 Token
	 */
	private Token getDefToken() {
		int start = cur;
		char c;

		while ((c = nextChar()) != 0) {
			if (!JSONParser.isNumLetterUnderline(c)) {
				String value = str.substring(start, revertChar());

				if ("true".equals(value)) {
					return Tokens.TRUE;
				} else if ("false".equals(value)) {
					return Tokens.FALSE;
				} else if ("null".equals(value)) {
					return Tokens.NIL;
				} else {
					return new StringToken(value); // 对象的 KEY 提示:StringToken 的二义性,既可作对象的 KEY,又可作字符串
				}
			}
		}

		checkEnd();
		return null;
	}

	/**
	 * 解析符号
	 * 
	 * @param c 字符
	 * @return Token
	 */
	private Token parseSymbol(char c) {
		switch (c) {
		case '[':
			return Tokens.ARRS;
		case ']':
			return Tokens.ARRE;
		case '{':
			return Tokens.OBJS;
		case '}':
			return Tokens.OBJE;
		case ',':
			return Tokens.SPLIT;
		case ':':
			return Tokens.DESC;
		default:
			return null;
		}
	}

	/**
	 * 获取下一个字节,同时进行 行、列 计数
	 * 
	 * @return 下一个字节,结束时返回 0
	 */
	private char nextChar() {
		if (cur >= len - 1)
			return 0;

		++cur;
		char c = str.charAt(cur);

		if (c == '\n') { // 遇到换行,记录一下所在行数,用于调试
			++lineNum;
			colMarks.push(cur);
		}

		return c;
	}

	/**
	 * 撤回一个字节,同时进行 行、列 计数,返回撤回前的字符游标 为什么要撤回?因为要先获取下一个字节才能得知是什么情况,知道之后,撤回。
	 * 
	 * @return 下一个字节,结束时返回0
	 */
	private int revertChar() {
		if (cur <= 0)
			return 0;

		int rcur = cur--;
		char c = str.charAt(rcur);

		if (c == '\n') {
			--lineNum;
			colMarks.pop();
		}

		return rcur;
	}

	/**
	 * 抛出一个 JsonParseException 异常
	 * 
	 * @param msg 异常信息
	 * @return JsonParseException 异常
	 */
	public JsonParseException exceptionFactory(String msg) {
		return new JsonParseException(cur, startLine, startCol, msg);
	}

	/**
	 * 抛出一个 JsonParseException 异常
	 * 
	 * @param msg 异常信息
	 * @param e 异常对象
	 * @return JsonParseException 异常
	 */
	public JsonParseException exceptionFactory(String msg, Throwable e) {
		return new JsonParseException(cur, startLine, startCol, msg, e);
	}

	public int getLineNum() {
		return lineNum;
	}

	public int getColNum() {
		return cur - colMarks.peek();
	}

	public int getCur() {
		return cur;
	}

	public String getStr() {
		return str;
	}

	public int getLen() {
		return len;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy