<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def scan(s):
 """Return a list of tokens, or throw SyntaxError on failure. """

    line = 1
    linepos = 1
    pos = 0
    toks = []
    while pos < len(s):
        matched = False
        for (tokname, r) in patterns:
            m = r.match(s, pos)
            if m is not None:
                # found a matching token
                v = m.group(0)
                prec = _preceding_token(toks)
                if tokname == 'STAR' and prec is not None and _is_special(prec):
                    # XPath 1.0 spec, 3.7 special rule 1a
                    # interpret '*' as a wildcard
                    tok = XPathTok('wildcard', v, line, linepos)
                elif (tokname == 'name' and
                      prec is not None and not _is_special(prec) and
                      v in operators):
                    # XPath 1.0 spec, 3.7 special rule 1b
                    # interpret the name as an operator
                    tok = XPathTok(operators[v], v, line, linepos)
                elif tokname == 'name':
                    # check if next token is '('
                    if re_open_para.match(s, pos + len(v)):
                        # XPath 1.0 spec, 3.7 special rule 2
                        if v in node_types:
                            # XPath 1.0 spec, 3.7 special rule 2a
                            tok = XPathTok('node_type', v, line, linepos)
                        else:
                            # XPath 1.0 spec, 3.7 special rule 2b
                            tok = XPathTok('function_name', v, line, linepos)
                    # check if next token is '::'
                    elif re_axis.match(s, pos + len(v)):
                        # XPath 1.0 spec, 3.7 special rule 3
                        if v in axes:
                            tok = XPathTok('axis', v, line, linepos)
                        else:
                            e = "unknown axis %s" % v
                            raise XPathError(e, line, linepos)
                    else:
                        tok = XPathTok('name', v, line, linepos)
                else:
                    tok = XPathTok(tokname, v, line, linepos)
                if tokname == '_whitespace':
                    n = v.count('\n')
                    if n > 0:
                        line = line + n
                        linepos = len(v) - v.rfind('\n')
                    else:
                        linepos += len(v)
                else:
                    linepos += len(v)
                pos += len(v)
                toks.append(tok)
                matched = True
                break
        if matched == False:
            # no patterns matched
            raise XPathError('syntax error', line, linepos)
    return toks