Пример #1
0
void Scan( void )
{
    if( !scan_string ) {
        while( isspace( *ScanPtr ) ) {
            ++ScanPtr;
        }
        TokenStart = ScanPtr;
        if( ExprTokens != NULL ) {
            if( ScanExprDelim( ExprTokens->delims ) )     return;
        }
        if( ScanCmdLnDelim() )      return;   /*sf do this if the others fail */
        if( ScanRealNum() )         return;
        if( ScanNumber() )          return;
        if( ScanId() ) {
            if( ExprTokens != NULL && CurrToken == T_NAME ) {
                ScanKeyword( ExprTokens->keywords );
            }
            return;
        }
        ++ScanPtr;
        CurrToken = T_UNKNOWN;
    } else {
        RawScan();
    }
}
Пример #2
0
TokenPtr Scanner::ScanToken()
{
    std::string spell;

    /* Scan identifier */
    if (std::isalpha(UChr()) || Is('_'))
        return ScanIdentifier();

    /* Scan number */
    if (std::isdigit(UChr()))
        return ScanNumber();

    /* Scan operators, punctuation, special characters and brackets */
    switch (chr_)
    {
        case '+': return Make( Token::Types::AddOp,         true );
        case '-': return Make( Token::Types::SubOp,         true );
        case '*': return Make( Token::Types::MulOp,         true );
        case '/': return Make( Token::Types::DivOp,         true );
        case '^': return Make( Token::Types::PowOp,         true );
        case ',': return Make( Token::Types::Comma,         true );
        case '=': return Make( Token::Types::Equal,         true );
        case '!': return Make( Token::Types::FactOp,        true );
        case '|': return Make( Token::Types::NormOp,        true );
        case '(': return Make( Token::Types::OpenBracket,   true );
        case ')': return Make( Token::Types::CloseBracket,  true );
        case '[': return Make( Token::Types::OpenParen,     true );
        case ']': return Make( Token::Types::CloseParen,    true );
        case '{': return Make( Token::Types::OpenCurly,     true );
        case '}': return Make( Token::Types::CloseCurly,    true );
    }

    if (Is('<') || Is('>'))
        return ScanShiftOperator(chr_);
        
    /* Scan punctuation, special characters and brackets */
    if (Is('('))
        return Make(Token::Types::OpenBracket, true);
    if (Is(')'))
        return Make(Token::Types::CloseBracket, true);
    if (Is('\n'))
        return Make(Token::Types::EndOfStream, true);

    ErrorUnexpected();

    return nullptr;
}
Пример #3
0
void CSerialModem::DoCommand() {
	cmdbuf[cmdpos] = 0;
	cmdpos = 0;			//Reset for next command
	upcase(cmdbuf);
	LOG_MSG("Command sent to modem: ->%s<-\n", cmdbuf);
	/* Check for empty line, stops dialing and autoanswer */
	if (!cmdbuf[0]) {
		reg[0]=0;	// autoanswer off
		return;
	}
	//else {
		//MIXER_Enable(mhd.chan,false);
	//	dialing = false;
	//	SendRes(ResNOCARRIER);
	//	goto ret_none;
	//}
	/* AT command set interpretation */

	if ((cmdbuf[0] != 'A') || (cmdbuf[1] != 'T')) {
		SendRes(ResERROR);
		return;
	}
	if (strstr(cmdbuf,"NET0")) {
		telnetmode = false;
		SendRes(ResOK);
		return;
	}
	else if (strstr(cmdbuf,"NET1")) {
		telnetmode = true;
		SendRes(ResOK);
		return;
	}

	char * scanbuf = &cmdbuf[2];
	while (1) {
		// LOG_MSG("loopstart ->%s<-",scanbuf);
		char chr = GetChar(scanbuf);
		switch (chr) {
		case 'D': { // Dial
			char * foundstr=&scanbuf[0];
			if (*foundstr=='T' || *foundstr=='P') foundstr++;
			// Small protection against empty line and long string
			if ((!foundstr[0]) || (strlen(foundstr)>100)) {
				SendRes(ResERROR);
				return;
			}
			char* helper;
			// scan for and remove spaces; weird bug: with leading spaces in the string,
			// SDLNet_ResolveHost will return no error but not work anyway (win)
			while(foundstr[0]==' ') foundstr++;
			helper=foundstr;
			helper+=strlen(foundstr);
			while(helper[0]==' ') {
				helper[0]=0;
				helper--;
			}
			if (strlen(foundstr) >= 12) {
				// Check if supplied parameter only consists of digits
				bool isNum = true;
				for (Bitu i=0; i<strlen(foundstr); i++)
					if (foundstr[i] < '0' || foundstr[i] > '9') isNum = false;
				if (isNum) {
					// Parameter is a number with at least 12 digits => this cannot
					// be a valid IP/name
					// Transform by adding dots
					char buffer[128];
					Bitu j = 0;
					for (Bitu i=0; i<strlen(foundstr); i++) {
						buffer[j++] = foundstr[i];
						// Add a dot after the third, sixth and ninth number
						if (i == 2 || i == 5 || i == 8)
							buffer[j++] = '.';
						// If the string is longer than 12 digits,
						// interpret the rest as port
						if (i == 11 && strlen(foundstr)>12)
							buffer[j++] = ':';
					}
					buffer[j] = 0;
					foundstr = buffer;
				}
			}
			Dial(foundstr);
			return;
		}
		case 'I': // Some strings about firmware
			switch (ScanNumber(scanbuf)) {
			case 3: SendLine("DosBox Emulated Modem Firmware V1.00"); break;
			case 4: SendLine("Modem compiled for DosBox version " VERSION); break;
			}
			break;
		case 'E': // Echo on/off
			switch (ScanNumber(scanbuf)) {
			case 0: echo = false; break;
			case 1: echo = true; break;
			}
			break;
		case 'V':
			switch (ScanNumber(scanbuf)) {
			case 0: numericresponse = true; break;
			case 1: numericresponse = false; break;
			}
			break;
		case 'H': // Hang up
			switch (ScanNumber(scanbuf)) {
			case 0:
				if (connected) {
					SendRes(ResNOCARRIER);
					EnterIdleState();
					return;
				}
				// else return ok
			}
			break;
		case 'O': // Return to data mode
			switch (ScanNumber(scanbuf)) {
			case 0:
				if (clientsocket) {
					commandmode = false;
					return;
				} else {
					SendRes(ResERROR);
					return;
				}
			}
			break;
		case 'T': // Tone Dial
		case 'P': // Pulse Dial
			break;
		case 'M': // Monitor
		case 'L': // Volume
			ScanNumber(scanbuf);
			break;
		case 'A': // Answer call
			if (waitingclientsocket) {
				AcceptIncomingCall();
			} else {
				SendRes(ResERROR);
				return;
			}
			return;
		case 'Z': { // Reset and load profiles
			// scan the number away, if any
			ScanNumber(scanbuf);
			if (clientsocket) SendRes(ResNOCARRIER);
			Reset();
			break;
		}
		case ' ': // skip space
			break;
		case 'Q': {
			// Response options
			// 0 = all on, 1 = all off,
			// 2 = no ring and no connect/carrier in answermode
			Bitu val = ScanNumber(scanbuf);	
			if(!(val>2)) {
				doresponse=val;
				break;
			} else {
				SendRes(ResERROR);
				return;
			}
		}
		case 'S': { // Registers	
			Bitu index=ScanNumber(scanbuf);
			if(index>=SREGS) {
				SendRes(ResERROR);
				return; //goto ret_none;
			}
			
			while(scanbuf[0]==' ') scanbuf++;	// skip spaces
			
			if(scanbuf[0]=='=') {	// set register
				scanbuf++;
				while(scanbuf[0]==' ') scanbuf++;	// skip spaces
				Bitu val = ScanNumber(scanbuf);
				reg[index]=val;
				break;
			}
			else if(scanbuf[0]=='?') {	// get register
				SendNumber(reg[index]);
				scanbuf++;
				break;
			}
			//else LOG_MSG("print reg %d with %d",index,reg[index]);
		}
		break;
		case '&': { // & escaped commands
			char cmdchar = GetChar(scanbuf);
			switch(cmdchar) {
				case 'K': {
					Bitu val = ScanNumber(scanbuf);
					if(val<5) flowcontrol=val;
					else {
						SendRes(ResERROR);
						return;
					}
					break;
				}
				case '\0':
					// end of string
					SendRes(ResERROR);
					return;
				default:
					LOG_MSG("Modem: Unhandled command: &%c%d",cmdchar,ScanNumber(scanbuf));
					break;
			}
			break;
		}
		case '\\': { // \ escaped commands
			char cmdchar = GetChar(scanbuf);
			switch(cmdchar) {
				case 'N':
					// error correction stuff - not emulated
					if (ScanNumber(scanbuf) > 5) {
						SendRes(ResERROR);
						return;
					}
					break;
				case '\0':
					// end of string
					SendRes(ResERROR);
					return;
				default:
					LOG_MSG("Modem: Unhandled command: \\%c%d",cmdchar, ScanNumber(scanbuf));
					break;
			}
			break;
		}
		case '\0':
			SendRes(ResOK);
			return;
		default:
			LOG_MSG("Modem: Unhandled command: %c%d",chr,ScanNumber(scanbuf));
			break;
		}
	}
}
void HLSLTokenizer::Next(const bool EOLSkipping)
{
    m_bufferPrevious = m_buffer;

    while( SkipWhitespace(EOLSkipping) || SkipComment(&m_buffer, EOLSkipping) || ScanLineDirective() || SkipPragmaDirective() )
    {
    }

    if (m_error)
    {
        m_token = HLSLToken_EndOfStream;
        return;
    }

    if (!EOLSkipping && m_buffer[0] == '\n')
    {
        m_token = HLSLToken_EndOfLine;
        return;
    }

    m_tokenLineNumber = m_lineNumber;

    if (m_buffer >= m_bufferEnd || *m_buffer == '\0')
    {
        m_token = HLSLToken_EndOfStream;
        return;
    }

    const char* start = m_buffer;

    // +=, -=, *=, /=, ==, <=, >=
    if (m_buffer[0] == '+' && m_buffer[1] == '=')
    {
        m_token = HLSLToken_PlusEqual;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '-' && m_buffer[1] == '=')
    {
        m_token = HLSLToken_MinusEqual;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '*' && m_buffer[1] == '=')
    {
        m_token = HLSLToken_TimesEqual;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '/' && m_buffer[1] == '=')
    {
        m_token = HLSLToken_DivideEqual;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '=' && m_buffer[1] == '=')
    {
        m_token = HLSLToken_EqualEqual;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '!' && m_buffer[1] == '=')
    {
        m_token = HLSLToken_NotEqual;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '<' && m_buffer[1] == '=')
    {
        m_token = HLSLToken_LessEqual;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '>' && m_buffer[1] == '=')
    {
        m_token = HLSLToken_GreaterEqual;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '&' && m_buffer[1] == '&')
    {
        m_token = HLSLToken_AndAnd;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '|' && m_buffer[1] == '|')
    {
        m_token = HLSLToken_BarBar;
        m_buffer += 2;
        return;
    }

    // ++, --
    if ((m_buffer[0] == '-' || m_buffer[0] == '+') && (m_buffer[1] == m_buffer[0]))
    {
        m_token = (m_buffer[0] == '+') ? HLSLToken_PlusPlus : HLSLToken_MinusMinus;
        m_buffer += 2;
        return;
    }

    // Check for the start of a number.
    if (ScanNumber())
    {
        return;
    }
    
    if (GetIsSymbol(m_buffer[0]))
    {
        m_token = static_cast<unsigned char>(m_buffer[0]);
        ++m_buffer;
        return;
    }

    // Must be an identifier or a reserved word.
    while (m_buffer < m_bufferEnd && m_buffer[0] != 0 && !GetIsSymbol(m_buffer[0]) && !isspace(m_buffer[0]))
    {
        ++m_buffer;
    }

    size_t length = m_buffer - start;
    memcpy(m_identifier, start, length);
    m_identifier[length] = 0;
    
    const int numReservedWords = sizeof(_reservedWords) / sizeof(const char*);
    for (int i = 0; i < numReservedWords; ++i)
    {
        if (strcmp(_reservedWords[i], m_identifier) == 0)
        {
            m_token = 256 + i;
            return;
        }
    }

    m_token = HLSLToken_Identifier;

}
Пример #5
0
globle void GetToken(
 void *theEnv,
 const char *logicalName,
 struct token *theToken)
 {
   int inchar;
   unsigned short type;

   /*=======================================*/
   /* Set Unknown default values for token. */
   /*=======================================*/

   theToken->type = UNKNOWN_VALUE;
   theToken->value = NULL;
   theToken->printForm = "unknown";
   ScannerData(theEnv)->GlobalPos = 0;
   ScannerData(theEnv)->GlobalMax = 0;

   /*==============================================*/
   /* Remove all white space before processing the */
   /* GetToken() request.                          */
   /*==============================================*/

   inchar = EnvGetcRouter(theEnv,logicalName);
   while ((inchar == ' ') || (inchar == '\n') || (inchar == '\f') ||
          (inchar == '\r') || (inchar == ';') || (inchar == '\t'))
     {
      /*=======================*/
      /* Remove comment lines. */
      /*=======================*/

      if (inchar == ';')
        {
         inchar = EnvGetcRouter(theEnv,logicalName);
         while ((inchar != '\n') && (inchar != '\r') && (inchar != EOF) )
           { inchar = EnvGetcRouter(theEnv,logicalName); }
        }
      inchar = EnvGetcRouter(theEnv,logicalName);
     }

   /*==========================*/
   /* Process Symbolic Tokens. */
   /*==========================*/

   if (isalpha(inchar) || IsUTF8MultiByteStart(inchar))
     {
      theToken->type = SYMBOL;
      EnvUngetcRouter(theEnv,inchar,logicalName);
      theToken->value = (void *) ScanSymbol(theEnv,logicalName,0,&type);
      theToken->printForm = ValueToString(theToken->value);
     }

   /*===============================================*/
   /* Process Number Tokens beginning with a digit. */
   /*===============================================*/

   else if (isdigit(inchar))
     {
      EnvUngetcRouter(theEnv,inchar,logicalName);
      ScanNumber(theEnv,logicalName,theToken);
     }

   else switch (inchar)
     {
      /*========================*/
      /* Process String Tokens. */
      /*========================*/

      case '"':
         theToken->value = (void *) ScanString(theEnv,logicalName);
         theToken->type = STRING;
         theToken->printForm = StringPrintForm(theEnv,ValueToString(theToken->value));
         break;

      /*=======================================*/
      /* Process Tokens that might be numbers. */
      /*=======================================*/

      case '-':
      case '.':
      case '+':
         EnvUngetcRouter(theEnv,inchar,logicalName);
         ScanNumber(theEnv,logicalName,theToken);
         break;

      /*===================================*/
      /* Process ? and ?<variable> Tokens. */
      /*===================================*/

       case '?':
          inchar = EnvGetcRouter(theEnv,logicalName);
          if (isalpha(inchar) || IsUTF8MultiByteStart(inchar)
#if DEFGLOBAL_CONSTRUCT
              || (inchar == '*'))
#else
              )
#endif
            {
             EnvUngetcRouter(theEnv,inchar,logicalName);
             theToken->value = (void *) ScanSymbol(theEnv,logicalName,0,&type);
             theToken->type = SF_VARIABLE;
#if DEFGLOBAL_CONSTRUCT
             if ((ValueToString(theToken->value)[0] == '*') &&
                 (((int) strlen(ValueToString(theToken->value))) > 1) &&
                 (ValueToString(theToken->value)[strlen(ValueToString(theToken->value)) - 1] == '*'))
               {
                size_t count;

                theToken->type = GBL_VARIABLE;
                theToken->printForm = AppendStrings(theEnv,"?",ValueToString(theToken->value));
                count = strlen(ScannerData(theEnv)->GlobalString);
                ScannerData(theEnv)->GlobalString[count-1] = EOS;
                theToken->value = EnvAddSymbol(theEnv,ScannerData(theEnv)->GlobalString+1);
                ScannerData(theEnv)->GlobalString[count-1] = (char) inchar;

               }
             else
#endif
             theToken->printForm = AppendStrings(theEnv,"?",ValueToString(theToken->value));
            }
          else
            {
             theToken->type = SF_WILDCARD;
             theToken->value = (void *) EnvAddSymbol(theEnv,"?");
             EnvUngetcRouter(theEnv,inchar,logicalName);
             theToken->printForm = "?";
            }
          break;

      /*=====================================*/
      /* Process $? and $?<variable> Tokens. */
      /*=====================================*/

      case '$':
         if ((inchar = EnvGetcRouter(theEnv,logicalName)) == '?')
           {
            inchar = EnvGetcRouter(theEnv,logicalName);
            if (isalpha(inchar) || IsUTF8MultiByteStart(inchar)
#if DEFGLOBAL_CONSTRUCT
                 || (inchar == '*'))
#else
                 )
#endif
              {
               EnvUngetcRouter(theEnv,inchar,logicalName);
               theToken->value = (void *) ScanSymbol(theEnv,logicalName,0,&type);
               theToken->type = MF_VARIABLE;
#if DEFGLOBAL_CONSTRUCT
             if ((ValueToString(theToken->value)[0] == '*') &&
                 ((int) (strlen(ValueToString(theToken->value))) > 1) &&
                 (ValueToString(theToken->value)[strlen(ValueToString(theToken->value)) - 1] == '*'))
               {
                size_t count;

                theToken->type = MF_GBL_VARIABLE;
                theToken->printForm = AppendStrings(theEnv,"$?",ValueToString(theToken->value));
                count = strlen(ScannerData(theEnv)->GlobalString);
                ScannerData(theEnv)->GlobalString[count-1] = EOS;
                theToken->value = EnvAddSymbol(theEnv,ScannerData(theEnv)->GlobalString+1);
                ScannerData(theEnv)->GlobalString[count-1] = (char) inchar;
               }
             else
#endif
               theToken->printForm = AppendStrings(theEnv,"$?",ValueToString(theToken->value));
              }
            else
              {
nsXFormsXPathScanner::XPATHTOKEN
nsXFormsXPathScanner::NextToken()
{
  if (mState != WHITESPACE)
    mLast = mState;
  mOffset = mOffset + mLength;
  mLength = 0;

  PRUnichar c = PeekChar();
  if (c == '\0') {
    mState = XPATHEOF;
  } else if (nsXFormsXPathXMLUtil::IsDigit(c)) {
    mState = ScanNumber();
  } else if (c == '_' || nsXFormsXPathXMLUtil::IsLetter(c)) {
    mState = ScanQName();
  } else if (c == '"' || c == '\'') {
    mState = ScanLiteral();
  } else {
    switch (c) {
    case '(':
      mState = LPARAN;
      PopChar();
      break;
      
    case ')':
      mState = RPARAN;
      PopChar();
      break;
      
    case '[':
      mState = LBRACK;
      PopChar();
      break;
      
    case ']':
      mState = RBRACK;
      PopChar();
      break;
      
    case '@':
      mState = AT;
      PopChar();
      break;
      
    case ',':
      mState = COMMA;
      PopChar();
      break;
      
    case ':':
      PopChar();
      if (PeekChar() == ':') {
        mState = COLONCOLON;
        PopChar();
      } else
        mState = ERRORXPATHTOKEN;
      break;
      
    case '.':
      PopChar();
      if (PeekChar() == '.') {
        mState = DOTDOT;
        PopChar();
      } else if (nsXFormsXPathXMLUtil::IsDigit(PeekChar()))
        mState = ScanNumber();
      else
        mState = DOT;
      break;
      
    case '$':
      mState = ScanVariable();
      break;
      
    case '/':
      PopChar();
      if (PeekChar() == '/') {
        mState = SLASHSLASH;
        PopChar();
      } else
        mState = SLASH;
      break;
      
    case '|':
      PopChar();
      mState = UNION;
      break;
      
    case '+':
      PopChar();
      mState = PLUS;
      break;
      
    case '-':
      PopChar();
      mState = MINUS;
      break;
      
    case '=':
      PopChar();
      mState = EQUAL;
      break;
      
    case '!':
      PopChar();
      if (PeekChar() == '=') {
        mState = NOTEQUAL;
        PopChar();
      } else
        mState = ERRORXPATHTOKEN;
      break;
      
    case '<':
      PopChar();
      if (PeekChar() == '=') {
        mState = LEQUAL;
        PopChar();
      } else
        mState = LESS;
      break;
      
    case '>':
      PopChar();
      if (PeekChar() == '=') {
        mState = GEQUAL;
        PopChar();
      } else
        mState = GREATER;
      break;
      
    case '*':
      PopChar();
      mState = SolveStar();
      break;
      
    case '\r':
    case '\n':
    case '\t':
    case ' ':
      mState = ScanWhitespace();
      break;
      
    default:
      PopChar();
      mState = ERRORXPATHTOKEN;
    }
  }

  return mState;
}
Пример #7
0
Lexer::TokenType Lexer::NextToken()
{
	m_lastTokenRange = m_thisTokenRange;
	NextChar();

	// Skip blanks and comments
	SkipBlanks();
	SkipComments();

	// Start remembering this token
	int start = CharPosition();
	m_thisTokenRange.m_start = start;

	tp = m_token;
	char ch = m_cc;

	*tp++ = ch;

	if (!ch)
	{
		// Hit EOF straightaway - so be careful not to write another Null term into the token
		// as this would involve writing off the end of the token buffer
		m_tokenType = Eof;
		m_thisTokenRange.m_stop = start;
		m_thisTokenRange.m_start = start + 1;
	}
	else
	{
		if (isIdentifierFirst(ch))
		{
			ScanIdentifierOrKeyword();
		}

		else if (isdigit(ch))
		{
			ScanNumber();
		}

		else if (ch == '-' && isdigit(PeekAtChar()))
		{
			Step();
			ScanNumber();
			if (m_tokenType == SmallIntegerConst)
				m_integer *= -1;
		}
		else if (ch == LITERAL)
		{
			ScanLiteral();
		}

		else if (ch == STRINGDELIM)
		{
			int stringStart = CharPosition();
			// String constant; remove quote
			tp--;
			ScanString(stringStart);

			m_tokenType = StringConst;
		}

		else if (ch == CHARLITERAL)
		{
			ScanLiteralCharacter();
		}

		else if (ch == '^')
		{
			m_tokenType = Return;
		}

		else if (ch == ':')
		{
			if (PeekAtChar() == '=')
			{
				m_tokenType = Assignment;
				*tp++ = NextChar();
			}
			else
				m_tokenType = Special;
		}

		else if (ch == ')')
		{
			m_tokenType = CloseParen;
		}

		else if (ch == '.')
		{
			m_tokenType = CloseStatement;
		}

		else if (ch == ']')
		{
			m_tokenType = CloseSquare;
		}

		else if (ch == ';')
		{
			m_tokenType = Cascade;
		}

		else if (IsASingleBinaryChar(ch))
		{
			// Single binary expressions
			m_tokenType = Binary;
		}

		else if (isAnsiBinaryChar(ch))
		{
			m_tokenType = Binary;
		}
		else
		{
			int pos = CharPosition();
			CompileError(TEXTRANGE(pos, pos), LErrBadChar);
		}

		*tp = '\0';
	}

	m_thisTokenRange.m_stop = CharPosition();
	return m_tokenType;
}
Пример #8
0
TokenPtr SLScanner::ScanToken()
{
    std::string spell;

    /* Scan directive (beginning with '#') */
    if (Is('#'))
        return ScanDirective();

    /* Scan identifier */
    if (std::isalpha(UChr()) || Is('_'))
        return ScanIdentifier();

    /* Scan number */
    if (Is('.'))
        return ScanNumberOrDot();
    if (std::isdigit(UChr()))
        return ScanNumber();

    /* Scan string literal */
    if (Is('\"'))
        return ScanStringLiteral();

    /* Scan operators */
    if (Is('='))
    {
        spell += TakeIt();
        if (Is('='))
            return Make(Tokens::BinaryOp, spell, true);
        return Make(Tokens::AssignOp, spell);
    }

    if (Is('~'))
        return Make(Tokens::UnaryOp, spell, true);

    if (Is('!'))
    {
        spell += TakeIt();
        if (Is('='))
            return Make(Tokens::BinaryOp, spell, true);
        return Make(Tokens::UnaryOp, spell);
    }

    if (Is('%'))
    {
        spell += TakeIt();
        if (Is('='))
            return Make(Tokens::AssignOp, spell, true);
        return Make(Tokens::BinaryOp, spell);
    }

    if (Is('*'))
    {
        spell += TakeIt();
        if (Is('='))
            return Make(Tokens::AssignOp, spell, true);
        return Make(Tokens::BinaryOp, spell);
    }

    if (Is('^'))
    {
        spell += TakeIt();
        if (Is('='))
            return Make(Tokens::AssignOp, spell, true);
        return Make(Tokens::BinaryOp, spell);
    }

    if (Is('+'))
        return ScanPlusOp();
    if (Is('-'))
        return ScanMinusOp();

    if (Is('<') || Is('>'))
        return ScanAssignShiftRelationOp(Chr());

    if (Is('&'))
    {
        spell += TakeIt();
        if (Is('='))
            return Make(Tokens::AssignOp, spell, true);
        if (Is('&'))
            return Make(Tokens::BinaryOp, spell, true);
        return Make(Tokens::BinaryOp, spell);
    }

    if (Is('|'))
    {
        spell += TakeIt();
        if (Is('='))
            return Make(Tokens::AssignOp, spell, true);
        if (Is('|'))
            return Make(Tokens::BinaryOp, spell, true);
        return Make(Tokens::BinaryOp, spell);
    }

    if (Is(':'))
    {
        spell += TakeIt();
        if (Is(':'))
            return Make(Tokens::DColon, spell, true);
        return Make(Tokens::Colon, spell);
    }

    /* Scan punctuation, special characters and brackets */
    switch (Chr())
    {
        case ';': return Make(Tokens::Semicolon, true); break;
        case ',': return Make(Tokens::Comma,     true); break;
        case '?': return Make(Tokens::TernaryOp, true); break;
        case '(': return Make(Tokens::LBracket,  true); break;
        case ')': return Make(Tokens::RBracket,  true); break;
        case '{': return Make(Tokens::LCurly,    true); break;
        case '}': return Make(Tokens::RCurly,    true); break;
        case '[': return Make(Tokens::LParen,    true); break;
        case ']': return Make(Tokens::RParen,    true); break;
    }

    ErrorUnexpected();

    return nullptr;
}