Expr atom() {
		Tok tok = peek();
		switch (tok.sym) {
		case LPAREN:
			move();
			Expr expr = expr();
			match(Sym.RPAREN);
			return expr;
		case ID:
			move();
			return new Id(tok.value());
		case STR:
			move();
			return new Const(tok.sym, tok.value());
		case INT:
		case LONG:
		case FLOAT:
		case DOUBLE:
			move();
			return new Const(tok.sym, ((NumTok)tok).getNumberValue());
		case TRUE:
			move();
			return Const.TRUE;
		case FALSE:
			move();
			return Const.FALSE;
		case NULL:
			move();
			return Const.NULL;
		case COMMA:
		case SEMICOLON:
		case QUESTION:	// support "c ?? ? a : b"
		case AND: case OR: case EQUAL: case NOTEQUAL:	// support "a.b ?? && expr"
		case RPAREN:	// support "(a.b ??)"
		case RBRACK:	// support "[start .. end ??]"
		case RBRACE:	// support "{key : value ??}"
		case RANGE:		// support "[start ?? .. end]"
		case COLON:		// support "c ? a ?? : b"
		case EOF:
			return null;
		default :
			throw new ParseException("Expression error: can not match the symbol \"" + tok.value() + "\"", location);
		}
	}
Expr atom ( ) { Tok tok = peek ( ) ; switch ( tok . sym ) { case LPAREN : move ( ) ; Expr expr = expr ( ) ; match ( Sym . RPAREN ) ; return expr ; case ID : move ( ) ; return new Id ( tok . value ( ) ) ; case STR : move ( ) ; return new Const ( tok . sym , tok . value ( ) ) ; case INT : case LONG : case FLOAT : case DOUBLE : move ( ) ; return new Const ( tok . sym , ( ( NumTok ) tok ) . getNumberValue ( ) ) ; case TRUE : move ( ) ; return Const . TRUE ; case FALSE : move ( ) ; return Const . FALSE ; case NULL : move ( ) ; return Const . NULL ; case COMMA : case SEMICOLON : case QUESTION : case AND : case OR : case EQUAL : case NOTEQUAL : case RPAREN : case RBRACK : case RBRACE : case RANGE : case COLON : case EOF : return null ; default : throw new ParseException ( "Expression error: can not match the symbol \"" + tok . value ( ) + "\"" , location ) ; } }
atom : '(' expr ')' | ID | STR | 'true' | 'false' | 'null'
| INT | LONG | FLOAT | DOUBLE