3636
3737import java .io .IOException ;
3838import java .io .Reader ;
39+ import java .math .BigInteger ;
3940
4041import static com .igormaznitsa .prologparser .tokenizer .TokenizerState .*;
4142import static com .igormaznitsa .prologparser .utils .StringUtils .isCharAllowedForUnquotedAtom ;
@@ -273,6 +274,8 @@ TokenizerResult readNextToken() {
273274
274275 PrologTerm .QuotingType quoting = PrologTerm .QuotingType .NO_QUOTED ;
275276
277+ int radix = 10 ;
278+
276279 TokenizerState state = LOOK_FOR ;
277280 boolean specCharDetected = false ;
278281 boolean charCodeAsInt = false ;
@@ -309,16 +312,16 @@ TokenizerResult readNextToken() {
309312 push ('.' );
310313 // it is Integer
311314 return this .tokenizerResultPool .find ().setData (
312- makeTermFromString (strBuffer .toStringExcludeLastChar (), quoting , TokenizerState .INTEGER ),
313- TokenizerState .ATOM ,
315+ makeTermFromString (strBuffer .toStringExcludeLastChar (), radix , quoting , TokenizerState .INTEGER ),
316+ TokenizerState .INTEGER ,
314317 getLastTokenLine (),
315318 getLastTokenPos ()
316319 );
317320 } else {
318321 // it is just integer number or an atom
319322 final String text = strBuffer .toString ();
320323 return this .tokenizerResultPool .find ().setData (
321- makeTermFromString (text , PrologTerm .findAppropriateQuoting (text ), state ),
324+ makeTermFromString (text , radix , PrologTerm .findAppropriateQuoting (text ), state ),
322325 state ,
323326 getLastTokenLine (),
324327 getLastTokenPos ()
@@ -348,7 +351,7 @@ TokenizerResult readNextToken() {
348351 case OPERATOR : {
349352 if (lastFoundFullOperator == null ) {
350353 return this .tokenizerResultPool .find ().setData (
351- makeTermFromString (strBuffer .toString (), quoting , state ),
354+ makeTermFromString (strBuffer .toString (), radix , quoting , state ),
352355 state ,
353356 getLastTokenLine (),
354357 getLastTokenPos ()
@@ -459,7 +462,7 @@ TokenizerResult readNextToken() {
459462 }
460463
461464 return this .tokenizerResultPool .find ().setData (
462- makeTermFromString (text , PrologTerm .findAppropriateQuoting (text ), state ),
465+ makeTermFromString (text , radix , PrologTerm .findAppropriateQuoting (text ), state ),
463466 state ,
464467 getLastTokenLine (),
465468 getLastTokenPos ());
@@ -482,7 +485,7 @@ TokenizerResult readNextToken() {
482485 }
483486 }
484487 return this .tokenizerResultPool .find ().setData (
485- makeTermFromString (text , PrologTerm .findAppropriateQuoting (text ), state ),
488+ makeTermFromString (text , radix , PrologTerm .findAppropriateQuoting (text ), state ),
486489 state ,
487490 getLastTokenLine (),
488491 getLastTokenPos ());
@@ -493,7 +496,7 @@ TokenizerResult readNextToken() {
493496 }
494497 break ;
495498 case INTEGER : {
496- if (Character . isDigit (chr )) {
499+ if (isCharAllowedForRadix (chr , radix )) {
497500 foundUnderscoreInNumber = false ;
498501 strBuffer .append (chr );
499502 } else if (chr == '_' ) {
@@ -515,14 +518,33 @@ TokenizerResult readNextToken() {
515518 throw new PrologParserException ("Unexpected underscore" , this .prevLine , this .prevPos );
516519 }
517520
518- if (this .zeroSingleQuotationAllowed && chr == '\'' && strBuffer .isSingleChar ('0' )) {
519- state = STRING ;
520- charCodeAsInt = true ;
521- strBuffer .clear ();
521+ if (chr == '\'' ) {
522+ if (strBuffer .isSingleChar ('0' )) {
523+ if (this .zeroSingleQuotationAllowed ) {
524+ state = STRING ;
525+ charCodeAsInt = true ;
526+ strBuffer .clear ();
527+ } else {
528+ push (chr );
529+ return this .tokenizerResultPool .find ().setData (
530+ makeTermFromString (strBuffer .toString (), radix , quoting , state ),
531+ TokenizerState .INTEGER ,
532+ getLastTokenLine (),
533+ getLastTokenPos ());
534+ }
535+ } else {
536+ radix = Integer .parseInt (strBuffer .toString ());
537+ if (radix < 2 || radix > 36 ) {
538+ throw new PrologParserException ("Radix must be 2..36: " + radix ,
539+ getLastTokenLine (),
540+ getLastTokenPos ());
541+ }
542+ strBuffer .clear ();
543+ }
522544 } else {
523545 push (chr );
524546 return this .tokenizerResultPool .find ().setData (
525- makeTermFromString (strBuffer .toString (), quoting , state ),
547+ makeTermFromString (strBuffer .toString (), radix , quoting , state ),
526548 TokenizerState .INTEGER ,
527549 getLastTokenLine (),
528550 getLastTokenPos ());
@@ -548,7 +570,7 @@ TokenizerResult readNextToken() {
548570 } else {
549571 push (chr );
550572 return this .tokenizerResultPool .find ().setData (
551- makeTermFromString (strBuffer .toString (), quoting , TokenizerState .FLOAT ),
573+ makeTermFromString (strBuffer .toString (), radix , quoting , TokenizerState .FLOAT ),
552574 TokenizerState .FLOAT ,
553575 getLastTokenLine (),
554576 getLastTokenPos ());
@@ -563,7 +585,7 @@ TokenizerResult readNextToken() {
563585 } else {
564586 push (chr );
565587 return this .tokenizerResultPool .find ().setData (
566- makeTermFromString (strBuffer .toStringExcludeLastChar (), quoting , TokenizerState .FLOAT ),
588+ makeTermFromString (strBuffer .toStringExcludeLastChar (), radix , quoting , TokenizerState .FLOAT ),
567589 TokenizerState .FLOAT ,
568590 getLastTokenLine (),
569591 getLastTokenPos ());
@@ -580,14 +602,14 @@ TokenizerResult readNextToken() {
580602 // it was an integer
581603 push ('.' );
582604 return this .tokenizerResultPool .find ().setData (
583- makeTermFromString (strBuffer .toStringExcludeLastChar (), quoting , TokenizerState .INTEGER ),
605+ makeTermFromString (strBuffer .toStringExcludeLastChar (), radix , quoting , TokenizerState .INTEGER ),
584606 TokenizerState .INTEGER ,
585607 getLastTokenLine (),
586608 getLastTokenPos ());
587609 } else {
588610 // it is float
589611 return this .tokenizerResultPool .find ().setData (
590- makeTermFromString (strBuffer .toString (), quoting , state ),
612+ makeTermFromString (strBuffer .toString (), radix , quoting , state ),
591613 state ,
592614 getLastTokenLine (),
593615 getLastTokenPos ()
@@ -613,7 +635,7 @@ TokenizerResult readNextToken() {
613635 );
614636 } else {
615637 return this .tokenizerResultPool .find ().setData (
616- makeTermFromString (textInBuffer , quoting , ATOM ),
638+ makeTermFromString (textInBuffer , radix , quoting , ATOM ),
617639 ATOM ,
618640 getLastTokenLine (),
619641 getLastTokenPos ()
@@ -687,7 +709,7 @@ state, getLastTokenLine(),
687709 strBuffer .append ('\n' );
688710 if (charCodeAsInt ) {
689711 return this .tokenizerResultPool .find ().setData (
690- makeTermFromString (strBuffer .toString (), quoting , state ),
712+ makeTermFromString (strBuffer .toString (), radix , quoting , state ),
691713 state ,
692714 getLastTokenLine (),
693715 getLastTokenPos ()
@@ -717,7 +739,7 @@ state, getLastTokenLine(),
717739 case '\'' :
718740 if (quoting == PrologTerm .QuotingType .SINGLE_QUOTED ) {
719741 return this .tokenizerResultPool .find ().setData (
720- makeTermFromString (strBuffer .toString (), quoting , state ),
742+ makeTermFromString (strBuffer .toString (), radix , quoting , state ),
721743 state ,
722744 getLastTokenLine (),
723745 getLastTokenPos ()
@@ -738,7 +760,7 @@ state, getLastTokenLine(),
738760 case '`' :
739761 if (quoting == PrologTerm .QuotingType .BACK_QUOTED ) {
740762 return this .tokenizerResultPool .find ().setData (
741- makeTermFromString (strBuffer .toString (), quoting , state ),
763+ makeTermFromString (strBuffer .toString (), radix , quoting , state ),
742764 state ,
743765 getLastTokenLine (),
744766 getLastTokenPos ()
@@ -759,7 +781,7 @@ state, getLastTokenLine(),
759781 case '\"' :
760782 if (quoting == PrologTerm .QuotingType .DOUBLE_QUOTED ) {
761783 return this .tokenizerResultPool .find ().setData (
762- makeTermFromString (strBuffer .toString (), quoting , state ),
784+ makeTermFromString (strBuffer .toString (), radix , quoting , state ),
763785 state ,
764786 getLastTokenLine (),
765787 getLastTokenPos ()
@@ -827,13 +849,30 @@ state, getLastTokenLine(),
827849 }
828850 }
829851
830- PrologTerm makeTermFromString (final String str , final PrologTerm .QuotingType quotingType , final TokenizerState state ) {
852+ private static boolean isCharAllowedForRadix (final char chr , final int radix ) {
853+ if (radix == 10 ) {
854+ return Character .isDigit (chr );
855+ } else if (radix < 10 ) {
856+ return chr >= '0' && chr < ('0' + radix );
857+ } else {
858+ if (chr >= '0' && chr <= '9' ) {
859+ return true ;
860+ }
861+ final int diff = radix - 10 ;
862+ if (chr >= 'A' && chr < ('A' + diff )) {
863+ return true ;
864+ }
865+ return chr >= 'a' && chr < ('a' + diff );
866+ }
867+ }
868+
869+ PrologTerm makeTermFromString (final String str , final int radix , final PrologTerm .QuotingType quotingType , final TokenizerState state ) {
831870 PrologTerm result ;
832871
833872 switch (state ) {
834873 case INTEGER : {
835874 try {
836- result = new PrologInt (str );
875+ result = radix == 10 ? new PrologInt (str ) : new PrologInt ( new BigInteger ( str , radix ) );
837876 } catch (NumberFormatException ex ) {
838877 result = null ;
839878 }
0 commit comments