quote symbol expected 异常处理

本文详细阐述了在使用JSP技术时遇到的解析异常问题,主要表现为缺少引号导致的错误。通过分析日志信息,定位到具体错误位置,并给出了解决方案,即在指定行加入缺失的引号。提醒开发者在编写JSP页面时要仔细检查语法,避免类似错误的出现。

写好的页面 突然就不行了~

抛出了 这么 一大串 异常 :


重要的 只是第一行啦 


严重: Servlet.service() for servlet jsp threw exception
org.apache.jasper.JasperException: /show.jsp(87,33) quote symbol expected

    at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:40)
    at org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:407)
    at org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:88)
    at org.apache.jasper.compiler.Parser.parseAttribute(Parser.java:198)
    at org.apache.jasper.compiler.Parser.parseAttributes(Parser.java:148)
    at org.apache.jasper.compiler.Parser.parseUseBean(Parser.java:929)
    at org.apache.jasper.compiler.Parser.parseStandardAction(Parser.java:1112)
    at org.apache.jasper.compiler.Parser.parseElements(Parser.java:1421)
    at org.apache.jasper.compiler.Parser.parse(Parser.java:130)
    at org.apache.jasper.compiler.ParserController.doParse(ParserController.java:255)
    at org.apache.jasper.compiler.ParserController.parse(ParserController.java:103)
    at org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:185)
    at org.apache.jasper.compiler.Compiler.compile(Compiler.java:347)
    at org.apache.jasper.compiler.Compiler.compile(Compiler.java:327)
    at org.apache.jasper.compiler.Compiler.compile(Compiler.java:314)
    at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:592)
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:326)
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:436)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:374)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
    at WEB.BeanTest.doGet(BeanTest.java:50)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:864)
    at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:579)
    at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1665)
    at java.lang.Thread.run(Thread.java:619)
2012-11-1 9:39:11 org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet testBean threw exception
org.apache.jasper.JasperException: /show.jsp(87,33) quote symbol expected
    at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:40)
    at org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:407)
    at org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:88)
    at org.apache.jasper.compiler.Parser.parseAttribute(Parser.java:198)
    at org.apache.jasper.compiler.Parser.parseAttributes(Parser.java:148)
    at org.apache.jasper.compiler.Parser.parseUseBean(Parser.java:929)
    at org.apache.jasper.compiler.Parser.parseStandardAction(Parser.java:1112)
    at org.apache.jasper.compiler.Parser.parseElements(Parser.java:1421)
    at org.apache.jasper.compiler.Parser.parse(Parser.java:130)
    at org.apache.jasper.compiler.ParserController.doParse(ParserController.java:255)
    at org.apache.jasper.compiler.ParserController.parse(ParserController.java:103)
    at org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:185)
    at org.apache.jasper.compiler.Compiler.compile(Compiler.java:347)
    at org.apache.jasper.compiler.Compiler.compile(Compiler.java:327)
    at org.apache.jasper.compiler.Compiler.compile(Compiler.java:314)
    at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:592)
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:326)
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:436)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:374)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
    at WEB.BeanTest.doGet(BeanTest.java:50)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:864)
    at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:579)
    at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1665)
    at java.lang.Thread.run(Thread.java:619)
2012-11-1 9:39:59 org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet jsp threw exception
org.apache.jasper.JasperException: /Test.jsp(87,33) quote symbol expected
    at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:40)
    at org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:407)
    at org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:88)
    at org.apache.jasper.compiler.Parser.parseAttribute(Parser.java:198)
    at org.apache.jasper.compiler.Parser.parseAttributes(Parser.java:148)
    at org.apache.jasper.compiler.Parser.parseUseBean(Parser.java:929)
    at org.apache.jasper.compiler.Parser.parseStandardAction(Parser.java:1112)
    at org.apache.jasper.compiler.Parser.parseElements(Parser.java:1421)
    at org.apache.jasper.compiler.Parser.parse(Parser.java:130)
    at org.apache.jasper.compiler.ParserController.doParse(ParserController.java:255)
    at org.apache.jasper.compiler.ParserController.parse(ParserController.java:103)
    at org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:185)
    at org.apache.jasper.compiler.Compiler.compile(Compiler.java:347)
    at org.apache.jasper.compiler.Compiler.compile(Compiler.java:327)
    at org.apache.jasper.compiler.Compiler.compile(Compiler.java:314)
    at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:592)
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:326)
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:864)
    at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:579)
    at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1665)
    at java.lang.Thread.run(Thread.java:619)


org.apache.jasper.JasperException: /show.jsp(87,33) quote symbol expected


这一行表明 : show.jsp 的87行33列少了一个 引号,行数可能有偏差,我的偏差了一行,实际是 88行少了一个引号~


把引号加上就 OK啦~ 以后记住细心哟!



import time import random import requests import json import logging import socket from pathlib import Path from openpyxl import load_workbook from selenium import webdriver from selenium.webdriver.edge.service import Service from selenium.webdriver.edge.options import Options from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.action_chains import ActionChains from selenium.common.exceptions import TimeoutException, WebDriverException from fake_useragent import UserAgent, FakeUserAgentError # -------------------------- 新增:手动指定Edge浏览器和驱动路径 -------------------------- EDGE_BINARY_PATH = r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" # 浏览器路径 EDGE_DRIVER_PATH = r"C:\Users\27570\Desktop\edgedriver_win32\msedgedriver.exe" # 驱动路径,需下载并指定 # ------------------------------------------------------------------------------------- # 配置日志 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler("ip_query.log"), logging.StreamHandler() ] ) # -------------------------- 优化:整合网络连接检查 -------------------------- def check_internet_connection(): """检查网络连接是否正常,尝试多种连接方式提高可靠性""" try: # 尝试连接到Google的公共DNS服务器 socket.create_connection(("8.8.8.8", 53), timeout=5) logging.info("网络连接测试通过 (DNS)") return True except OSError: logging.warning("无法连接到DNS服务器,尝试HTTP请求...") try: # 尝试HTTP请求到百度 response = requests.get("https://www.baidu.com", timeout=5) if response.status_code == 200: logging.info("网络连接测试通过 (HTTP)") return True except requests.RequestException: logging.warning("HTTP请求失败,尝试HTTPS请求...") try: # 尝试HTTPS请求到百度 response = requests.get("https://www.baidu.com", timeout=5) if response.status_code == 200: logging.info("网络连接测试通过 (HTTPS)") return True except requests.RequestException: logging.error("HTTPS请求失败") return False # ------------------------------------------------------------------------------------- def build_query_url(base_url, ip_address, path_format="{ip}/", use_params=True, param_name="ip"): """构建IP查询URL,支持路径参数和查询参数两种格式""" if not base_url.startswith(('http://', 'https://')): base_url = 'https://' + base_url base_url = base_url.rstrip('/') try: if '.' in ip_address: # IPv4 socket.inet_pton(socket.AF_INET, ip_address) elif ':' in ip_address: # IPv6 socket.inet_pton(socket.AF_INET6, ip_address) else: raise ValueError("无效的IP地址") if ':' in ip_address: ip_address = f"[{ip_address}]" if use_params: # 使用查询参数的方式构造URL from urllib.parse import urlencode # 添加固定参数action=2 params = {param_name: ip_address, "action": 2} return f"{base_url}?{urlencode(params)}" else: # 原有的路径参数方式 from urllib.parse import quote encoded_ip = quote(ip_address) return f"{base_url}/{path_format.format(ip=encoded_ip)}" except socket.error: logging.error(f"无效的IP地址格式: {ip_address}") return None except Exception as e: logging.error(f"构建查询URL时出错: {str(e)}") return None # 手动配置的固定请求头 MANUAL_HEADERS = { 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'zh-CN,zh;q=0.9', 'cache-control': 'max-age=0', 'connection': 'keep-alive', 'cookie': '_c_WBKFRo=NWgPw1zeBaW3I2CtOcadfhJJw33TcEYmWMtyGzTE; Hm_lvt_f4f76646cd877e538aa1fbbdf351c548=1753560343,1753617545,1753793389,1753862286; HMACCOUNT=96B6BD9DE68EFF3B; PHPSESSID=o9fnnscr7sofru4b8r1khlde3f; Hm_lvt_f4f76646cd877e538aa1fbbdf351c548=1754123598; HMACCOUNT=96B6BD9DE68EFF3B; Hm_lpvt_f4f76646cd877e538aa1fbbdf351c548=1754611428; Hm_lpvt_f4f76646cd877e538aa1fbbdf351c548=1754613370', 'host': 'www.ip138.com', 'referer': 'https://www.ip138.com/iplookup.php?ip=27.154.214.154&action=2', 'sec-ch-ua': '"Not)A;Brand";v="8", "Chromium";v="138", "Microsoft Edge";v="138"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-dest': 'document', 'sec-fetch-mode': 'navigate', 'sec-fetch-site': 'same-origin', 'sec-fetch-user': '?1', 'upgrade-insecure-requests': '1', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0' } def configure_driver(max_retries=5): """配置Edge浏览器驱动""" for attempt in range(max_retries): try: # 先检查网络连接 if not check_internet_connection(): raise Exception("网络连接不可用") # 创建Edge选项 edge_options = Options() # 1. 基础配置 edge_options.binary_location = EDGE_BINARY_PATH # 手动指定浏览器路径 edge_options.add_argument("--disable-blink-features=AutomationControlled") # 核心反检测 edge_options.add_experimental_option("excludeSwitches", ["enable-automation"]) edge_options.add_experimental_option("useAutomationExtension", False) edge_options.add_argument("--start-maximized") # 最大化窗口 # 2. 增强反检测 edge_options.add_argument("--disable-extensions") edge_options.add_argument("--disable-plugins-discovery") edge_options.add_argument("--disable-web-security") # 3. 随机化配置 features_to_disable = [ "AutomationControlled", "InterestCohort", "BlinkGenPropertyTrees" ] edge_options.add_argument(f"--disable-features={','.join(random.sample(features_to_disable, random.randint(2, 4)))}") screen_sizes = [(1366, 768), (1920, 1080), (1536, 864)] width, height = random.choice(screen_sizes) edge_options.add_argument(f"--window-size={width},{height}") if random.random() > 0.5: edge_options.add_argument("--disable-gpu") else: edge_options.add_argument("--enable-gpu-rasterization") # 4. 资源加载控制 prefs = { "profile.managed_default_content_settings.images": 2, "profile.managed_default_content_settings.stylesheets": 2, } edge_options.add_experimental_option("prefs", prefs) edge_options.page_load_strategy = 'eager' # 只等待DOM加载 # 5. 使用手动指定的驱动路径 try: service = Service(EDGE_DRIVER_PATH) # 手动指定驱动路径 logging.info(f"使用手动指定的驱动路径: {EDGE_DRIVER_PATH}") except Exception as e: logging.error(f"驱动路径配置错误: {str(e)}") raise # 6. 创建浏览器实例 driver = webdriver.Edge(service=service, options=edge_options) # 7. 隐藏自动化特征 driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", { "source": """ // 核心:隐藏webdriver标志 Object.defineProperty(navigator, 'webdriver', { get: () => undefined }); // 模拟Chrome特征 window.chrome = { runtime: {} }; // 模拟时区 Intl.DateTimeFormat().resolvedOptions().timeZone = ['Asia/Shanghai', 'Asia/Beijing'][Math.floor(Math.random() * 2)]; """ }) # 8. 设置超时 driver.set_page_load_timeout(30) driver.set_script_timeout(30) # 9. 应用手动配置的请求头 logging.info(f"应用手动配置的请求头: {json.dumps(MANUAL_HEADERS, indent=2)[:100]}...") driver.execute_cdp_cmd("Network.setUserAgentOverride", { "userAgent": MANUAL_HEADERS["user-agent"], "accept": MANUAL_HEADERS["accept"], "acceptLanguage": MANUAL_HEADERS["accept-language"], }) logging.info(f"浏览器驱动初始化成功 (尝试 {attempt+1}/{max_retries})") return driver except Exception as e: logging.error(f"配置浏览器驱动失败 (尝试 {attempt+1}/{max_retries}): {str(e)}") if attempt < max_retries - 1: wait_time = 2 ** attempt + random.uniform(5, 10) logging.info(f"将在 {wait_time:.2f} 秒后重试") time.sleep(wait_time) logging.critical("达到最大重试次数,无法初始化浏览器驱动") return None def change_user_agent(driver): """更换为手动配置的请求头""" logging.info(f"应用手动配置的请求头: {json.dumps(MANUAL_HEADERS, indent=2)[:100]}...") driver.execute_cdp_cmd("Network.setUserAgentOverride", { "userAgent": MANUAL_HEADERS["user-agent"], "accept": MANUAL_HEADERS["accept"], "acceptLanguage": MANUAL_HEADERS["accept-language"], }) driver.refresh() time.sleep(random.uniform(2, 4)) def handle_cookies(driver): """处理和保存Cookie""" cookies = driver.get_cookies() logging.info(f"获取到 {len(cookies)} 个Cookie") return cookies def is_banned(driver): """检测是否被封禁""" try: banned_xpaths = [ '//div[contains(text(), "访问被阻止")]', '//div[contains(text(), "验证码")]', '//div[contains(text(), "您的IP已被封禁")]', ] for xpath in banned_xpaths: if WebDriverWait(driver, 5).until( EC.presence_of_element_located((By.XPATH, xpath)) ): logging.warning("检测到封禁页面") return True return False except: return False def check_dynamic_element(driver, xpaths): """检查网页上是否存在任一动态XPath的元素""" for i, xpath in enumerate(xpaths, 1): try: WebDriverWait(driver, 5).until( EC.presence_of_element_located((By.XPATH, xpath)) ) logging.info(f"使用动态元素XPath {i}: {xpath}") return True except: continue return False def get_result_element(driver, xpaths): """尝试获取任一结果元素""" for i, xpath in enumerate(xpaths, 1): try: element = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, xpath)) ) logging.info(f"使用结果元素XPath {i}: {xpath}") return element except: continue return None def simulate_human_behavior(driver): """模拟人类浏览行为""" try: # 随机滚动页面 scroll_height = driver.execute_script("return document.body.scrollHeight") scroll_steps = random.randint(3, 7) for i in range(scroll_steps): scroll_to = int(scroll_height * (i + 1) / scroll_steps) driver.execute_script(f"window.scrollTo(0, {scroll_to})") time.sleep(random.uniform(0.5, 1.5)) # 随机移动鼠标 actions = ActionChains(driver) elements = driver.find_elements(By.TAG_NAME, "a") if elements: for _ in range(random.randint(1, 3)): element = random.choice(elements) actions.move_to_element(element).perform() time.sleep(random.uniform(0.3, 0.8)) except Exception as e: logging.warning(f"模拟人类行为时出错: {e}") def query_ip(driver, ip_address, base_url, xpath_expressions, dynamic_xpaths, max_retries=5): """查询IP信息,添加封禁检测和处理""" if not ip_address or not isinstance(ip_address, str) or ip_address.strip() == "": logging.warning(f"无效的IP地址: {ip_address}") return "无效IP" ip_address = ip_address.strip() for attempt in range(max_retries): try: if attempt > 0: wait_time = 2 ** attempt + random.uniform(3, 7) logging.info(f"第 {attempt+1} 次重试前等待 {wait_time:.2f} 秒...") time.sleep(wait_time) change_user_agent(driver) query_url = build_query_url(base_url, ip_address) if not query_url: logging.error(f"无法构建有效的查询URL,IP: {ip_address}") return "无效URL" logging.info(f"访问查询URL (尝试 {attempt+1}/{max_retries}): {query_url}") try: driver.get(query_url) time.sleep(random.uniform(8, 15)) if is_banned(driver): logging.warning(f"IP {ip_address} 查询时被封禁") driver.quit() time.sleep(5) driver = configure_driver() time.sleep(5) continue current_url = driver.current_url if current_url == "data:," or "about:blank" in current_url: raise Exception("浏览器加载了空白页面") simulate_human_behavior(driver) time.sleep(random.uniform(2, 5)) handle_cookies(driver) except TimeoutException: logging.warning(f"页面加载超时,尝试重新加载") driver.refresh() time.sleep(15) continue if check_dynamic_element(driver, dynamic_xpaths): logging.info(f"检测到动态元素,结果将设为'动态'") return "动态" result_element = get_result_element(driver, xpath_expressions) if result_element: return result_element.text.strip() else: raise Exception("无法找到结果元素") except WebDriverException as e: logging.error(f"WebDriver错误 (尝试 {attempt+1}/{max_retries}): {str(e)}") if "ERR_EMPTY_RESPONSE" in str(e) or "ERR_CONNECTION_RESET" in str(e): logging.warning("检测到连接错误,尝试重启浏览器...") driver.quit() time.sleep(15) driver = configure_driver() time.sleep(10) else: time.sleep(2 ** attempt + random.uniform(5, 10)) continue except Exception as e: logging.error(f"查询IP {ip_address} 失败 (尝试 {attempt+1}/{max_retries}): {str(e)}") time.sleep(2 ** attempt + random.uniform(5, 10)) continue logging.error(f"IP {ip_address} 查询失败,已达到最大重试次数") driver.save_screenshot(f"error_{ip_address}.png") return "查询失败" def is_row_hidden(worksheet, row_idx): """检查Excel行是否被隐藏""" return worksheet.row_dimensions[row_idx].hidden def process_excel(input_file, base_url, xpath_expressions, dynamic_xpaths, ip_column='A', result_column='I', start_row=2): """处理Excel文件""" wb = load_workbook(input_file) ws = wb.active has_filter = ws.auto_filter.ref is not None logging.info(f"检测到筛选: {has_filter}") driver = configure_driver() if not driver: logging.critical("无法初始化浏览器驱动,退出程序") return visible_rows = [] for row_idx in range(start_row, ws.max_row + 1): row_dim = ws.row_dimensions.get(row_idx) if not row_dim or not row_dim.hidden: visible_rows.append(row_idx) logging.info(f"可见行共{len(visible_rows)}行") total_visible = len(visible_rows) processed_count = 0 try: for i, row in enumerate(visible_rows, 1): ip_address = ws[f"{ip_column}{row}"].value if not ip_address: logging.info(f"第 {row} 行IP地址为空,跳过") continue logging.info(f"正在查询IP: {ip_address} ({i}/{total_visible})") result = query_ip(driver, ip_address, base_url, xpath_expressions, dynamic_xpaths) ws[f"{result_column}{row}"] = result processed_count += 1 if i % 3 == 0 or i == total_visible: wb.save(input_file) logging.info(f"已保存进度: {i}/{total_visible} 到 {input_file}") wait_time = random.uniform(20,40) logging.info(f"等待 {wait_time:.2f} 秒后继续...") time.sleep(wait_time) if i % 10 == 0: extra_wait = random.uniform(40,60) logging.info(f"已处理 {i} 个IP,额外休息 {extra_wait:.2f} 秒...") time.sleep(extra_wait) if i % 20 == 0: logging.info(f"已处理 {i} 个IP,重启浏览器以避免被检测...") driver.quit() time.sleep(15) driver = configure_driver() if not driver: logging.critical("无法重新初始化浏览器驱动,退出程序") return except Exception as e: logging.critical(f"处理过程中发生意外错误: {str(e)}") finally: if driver: driver.quit() wb.save(input_file) logging.info(f"已保存最终结果到 {input_file}") logging.info(f"处理完成!共处理 {processed_count}/{total_visible} 个可见IP地址") if __name__ == "__main__": INPUT_FILE = r"C:\Users\27570\Desktop\飞塔-福建-简版-更新版20250730.xlsx" # 修改为新的基础URL BASE_URL = "https://www.ip138.com/iplookup.php" # 配置两种XPath表达式 XPATH_EXPRESSIONS = [ '/html/body/div/div[2]/div[1]/div/table/tbody/tr[2]/td[2]', '/html/body/div/div[2]/div[2]/div/div[2]/div[1]/div/div[2]/div[2]/div[2]/table/tbody/tr[2]/td[2]' ] DYNAMIC_XPATHS = [ '/html/body/div/div[2]/div[1]/div/p/a', '/html/body/div/div[2]/div[2]/div/div[2]/div[1]/div/div[2]/div[2]/div[1]/p[1]/a' ] max_main_retries = 3 for main_attempt in range(max_main_retries): try: logging.info(f"开始处理Excel文件 (尝试 {main_attempt+1}/{max_main_retries})") process_excel(INPUT_FILE, BASE_URL, XPATH_EXPRESSIONS, DYNAMIC_XPATHS) break except Exception as e: logging.critical(f"主程序执行失败 (尝试 {main_attempt+1}/{max_main_retries}): {str(e)}") if main_attempt < max_main_retries - 1: wait_time = 10 + random.uniform(10, 30) logging.info(f"将在 {wait_time:.2f} 秒后重试") time.sleep(wait_time) else: logging.critical("达到最大重试次数,程序终止") 以上代码在运行时出现了以下问题,解决问题并给我完整代码 Message: session not created: probably user data directory is already in use, please specify a unique value for --user-data-dir argument, or don't use --user-data-dir; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#sessionnotcreatedexception Stacktrace: GetHandleVerifier [0x0xf6d593+37219] (No symbol) [0x0xe1a716] (No symbol) [0x0xbe51ce] (No symbol) [0x0xc0d881] (No symbol) [0x0xc08a43] (No symbol) [0x0xc3d78b] (No symbol) [0x0xc3d22a] (No symbol) [0x0xc324f6] (No symbol) [0x0xc13327] (No symbol) [0x0xc12723] (No symbol) [0x0xc13144] sqlite3_dbdata_init [0x0x105a89c+518364] sqlite3_dbdata_init [0x0x1141ab0+1465072] sqlite3_dbdata_init [0x0x11413e5+1463333] sqlite3_dbdata_init [0x0x11328ec+1403180] sqlite3_dbdata_init [0x0x11422d2+1467154] (No symbol) [0x0xe31d9d] (No symbol) [0x0xe25108] (No symbol) [0x0xe252fb] (No symbol) [0x0xe0a649] BaseThreadInitThunk [0x0x75525d49+25] RtlInitializeExceptionChain [0x0x7706d1ab+107] RtlGetAppContainerNamedObjectPath [0x0x7706d131+561]
08-09
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> // 单词类型枚举 typedef enum { CONSTTK, INTTK, CHARTK, VOIDTK, MAINTK, RETURNTK, PRINTFTK, IDENFR, INTCON, CHARCON, STRCON, ASSIGN, MINU, PLUS, MULT, DIV, COMMA, SEMICN, LPARENT, RPARENT, LBRACE, RBRACE, EOFTK // 文件结束标记 } TokenType; // 单词结构体 typedef struct { TokenType type; char value[1024]; int line; // 行号,用于错误处理 } Token; // 全局变量 Token *tokens; // 存储所有单词 int tokenCount = 0; // 单词总数 int tokenPtr = 0; // 当前单词指针 FILE *fout; // 输出文件流 int outputEnabled = 1; // 控制输出是否开启 // 关键字映射表(不区分大小写) typedef struct { const char *name; TokenType type; } Keyword; Keyword keywords[] = { {"const", CONSTTK}, {"int", INTTK}, {"char", CHARTK}, {"void", VOIDTK}, {"main", MAINTK}, {"return", RETURNTK}, {"printf", PRINTFTK}, {NULL, EOFTK} // 结束标记 }; // 将TokenType转换为字符串 const char* tokenTypeToString(TokenType type) { switch (type) { case CONSTTK: return "CONSTTK"; case INTTK: return "INTTK"; case CHARTK: return "CHARTK"; case VOIDTK: return "VOIDTK"; case MAINTK: return "MAINTK"; case RETURNTK: return "RETURNTK"; case PRINTFTK: return "PRINTFTK"; case IDENFR: return "IDENFR"; case INTCON: return "INTCON"; case CHARCON: return "CHARCON"; case STRCON: return "STRCON"; case ASSIGN: return "ASSIGN"; case MINU: return "MINU"; case PLUS: return "PLUS"; case MULT: return "MULT"; case DIV: return "DIV"; case COMMA: return "COMMA"; case SEMICN: return "SEMICN"; case LPARENT: return "LPARENT"; case RPARENT: return "RPARENT"; case LBRACE: return "LBRACE"; case RBRACE: return "RBRACE"; default: return ""; } } // 检查是否为关键字(不区分大小写) int isKeyword(const char *id, TokenType *type) { char lowerId[1024]; int i; for (i = 0; id[i] != '\0'; i++) { lowerId[i] = tolower(id[i]); } lowerId[i] = '\0'; for (int j = 0; keywords[j].name != NULL; j++) { if (strcmp(lowerId, keywords[j].name) == 0) { *type = keywords[j].type; return 1; } } return 0; } // 处理转义字符 char escapeChar(char c) { switch (c) { case 'n': return '\n'; case 't': return '\t'; case 'r': return '\r'; case '\\': return '\\'; case '\'': return '\''; case '\"': return '\"'; default: return c; } } // 词法分析函数 void lexAnalyze(const char *filename) { FILE *fin = fopen(filename, "r"); if (!fin) { fprintf(stderr, "无法打开文件: %s\n", filename); exit(1); } // 初始化 tokens 数组 tokens = (Token*)malloc(1024 * sizeof(Token)); if (!tokens) { fprintf(stderr, "内存分配失败\n"); exit(1); } char c; int line = 1; int capacity = 1024; while ((c = fgetc(fin)) != EOF) { if (c == '\n') { line++; continue; } // 跳过空白字符 if (isspace(c)) { continue; } // 处理注释 if (c == '/') { char next = fgetc(fin); if (next == '/') { // 单行注释,跳过直到行尾 while ((c = fgetc(fin)) != EOF && c != '\n'); if (c == '\n') line++; continue; } else if (next == '*') { // 多行注释 while ((c = fgetc(fin)) != EOF) { if (c == '\n') line++; if (c == '*') { char next2 = fgetc(fin); if (next2 == '/') break; else ungetc(next2, fin); } } continue; } else { // 不是注释,是除号 ungetc(next, fin); } } // 识别标识符或关键字 if (isalpha(c) || c == '_') { if (tokenCount >= capacity) { capacity *= 2; tokens = (Token*)realloc(tokens, capacity * sizeof(Token)); if (!tokens) { fprintf(stderr, "内存分配失败\n"); exit(1); } } int i = 0; tokens[tokenCount].value[i++] = c; while ((c = fgetc(fin)) != EOF && (isalnum(c) || c == '_')) { tokens[tokenCount].value[i++] = c; } tokens[tokenCount].value[i] = '\0'; ungetc(c, fin); // 回退一个字符 // 检查是否为关键字 TokenType type; if (isKeyword(tokens[tokenCount].value, &type)) { tokens[tokenCount].type = type; } else { tokens[tokenCount].type = IDENFR; } tokens[tokenCount].line = line; tokenCount++; continue; } // 识别数字 if (isdigit(c)) { if (tokenCount >= capacity) { capacity *= 2; tokens = (Token*)realloc(tokens, capacity * sizeof(Token)); if (!tokens) { fprintf(stderr, "内存分配失败\n"); exit(1); } } int i = 0; tokens[tokenCount].value[i++] = c; while ((c = fgetc(fin)) != EOF && isdigit(c)) { tokens[tokenCount].value[i++] = c; } tokens[tokenCount].value[i] = '\0'; ungetc(c, fin); // 回退一个字符 tokens[tokenCount].type = INTCON; tokens[tokenCount].line = line; tokenCount++; continue; } // 识别字符常量 if (c == '\'') { if (tokenCount >= capacity) { capacity *= 2; tokens = (Token*)realloc(tokens, capacity * sizeof(Token)); if (!tokens) { fprintf(stderr, "内存分配失败\n"); exit(1); } } char ch = fgetc(fin); // 处理转义字符 if (ch == '\\') { char esc = fgetc(fin); ch = escapeChar(esc); } tokens[tokenCount].value[0] = ch; tokens[tokenCount].value[1] = '\0'; tokens[tokenCount].type = CHARCON; tokens[tokenCount].line = line; tokenCount++; // 消耗 closing quote char closing = fgetc(fin); if (closing != '\'') { // 如果不是单引号,回退 ungetc(closing, fin); } continue; } // 识别字符串常量 if (c == '"') { if (tokenCount >= capacity) { capacity *= 2; tokens = (Token*)realloc(tokens, capacity * sizeof(Token)); if (!tokens) { fprintf(stderr, "内存分配失败\n"); exit(1); } } int i = 0; while ((c = fgetc(fin)) != EOF && c != '"') { if (c == '\\') { // 处理转义字符 char esc = fgetc(fin); tokens[tokenCount].value[i++] = escapeChar(esc); } else { tokens[tokenCount].value[i++] = c; } } tokens[tokenCount].value[i] = '\0'; tokens[tokenCount].type = STRCON; tokens[tokenCount].line = line; tokenCount++; continue; } // 识别运算符和分隔符 if (tokenCount >= capacity) { capacity *= 2; tokens = (Token*)realloc(tokens, capacity * sizeof(Token)); if (!tokens) { fprintf(stderr, "内存分配失败\n"); exit(1); } } switch (c) { case '=': tokens[tokenCount].type = ASSIGN; strcpy(tokens[tokenCount].value, "="); break; case '-': tokens[tokenCount].type = MINU; strcpy(tokens[tokenCount].value, "-"); break; case '+': tokens[tokenCount].type = PLUS; strcpy(tokens[tokenCount].value, "+"); break; case '*': tokens[tokenCount].type = MULT; strcpy(tokens[tokenCount].value, "*"); break; case '/': tokens[tokenCount].type = DIV; strcpy(tokens[tokenCount].value, "/"); break; case ',': tokens[tokenCount].type = COMMA; strcpy(tokens[tokenCount].value, ","); break; case ';': tokens[tokenCount].type = SEMICN; strcpy(tokens[tokenCount].value, ";"); break; case '(': tokens[tokenCount].type = LPARENT; strcpy(tokens[tokenCount].value, "("); break; case ')': tokens[tokenCount].type = RPARENT; strcpy(tokens[tokenCount].value, ")"); break; case '{': tokens[tokenCount].type = LBRACE; strcpy(tokens[tokenCount].value, "{"); break; case '}': tokens[tokenCount].type = RBRACE; strcpy(tokens[tokenCount].value, "}"); break; default: // 跳过未知字符而不是退出 continue; } tokens[tokenCount].line = line; tokenCount++; } // 添加文件结束标记 if (tokenCount >= capacity) { tokens = (Token*)realloc(tokens, (capacity + 1) * sizeof(Token)); } tokens[tokenCount].type = EOFTK; tokens[tokenCount].value[0] = '\0'; tokens[tokenCount].line = line; tokenCount++; fclose(fin); } // 输出当前单词 void outputCurrentToken() { if (outputEnabled && tokenPtr < tokenCount && tokens[tokenPtr].type != EOFTK) { const char* typeStr = tokenTypeToString(tokens[tokenPtr].type); // 对于字符串常量,需要特殊处理输出格式 if (tokens[tokenPtr].type == STRCON) { fprintf(fout, "%s \"%s\"\n", typeStr, tokens[tokenPtr].value); } else if (tokens[tokenPtr].type == CHARCON) { fprintf(fout, "%s '%s'\n", typeStr, tokens[tokenPtr].value); } else { fprintf(fout, "%s %s\n", typeStr, tokens[tokenPtr].value); } } } // 输出语法成分 void outputSyntaxComponent(const char *component) { if (outputEnabled) { fprintf(fout, "%s\n", component); } } // 匹配当前单词,如果匹配则前进,否则报错 int match(TokenType expected) { if (tokenPtr < tokenCount && tokens[tokenPtr].type == expected) { outputCurrentToken(); // 输出当前单词 tokenPtr++; return 1; } return 0; } // 查看当前token类型 TokenType currentTokenType() { if (tokenPtr < tokenCount) { return tokens[tokenPtr].type; } return EOFTK; } // 递归子程序声明 void program(); void constDeclaration(); void constDefinition(TokenType type); void integer(); void unsignedInteger(); void varDeclaration(); void varDefinition(TokenType type); void functionDefinitionWithReturn(); void declarationHead(TokenType returnType); void parameterList(); void compoundStatement(); void statementList(); void statement(); void assignmentStatement(); void returnStatement(); void writeStatement(); void mainFunction(); void expression(); void term(); void factor(); void functionCallWithReturn(); void valueParameterList(); void stringLiteral(); // 递归子程序实现 void program() { // 处理所有可能的常量说明 while (tokenPtr < tokenCount && tokens[tokenPtr].type == CONSTTK) { constDeclaration(); } // 处理所有可能的变量说明 while (tokenPtr < tokenCount && (tokens[tokenPtr].type == INTTK || tokens[tokenPtr].type == CHARTK)) { // 检查是否是函数定义 if (tokenPtr + 2 < tokenCount && tokens[tokenPtr + 1].type == IDENFR && tokens[tokenPtr + 2].type == LPARENT) { break; // 是函数定义,跳出变量说明处理 } varDeclaration(); } // 处理有返回值函数定义(除了主函数) while (tokenPtr < tokenCount && (tokens[tokenPtr].type == INTTK || tokens[tokenPtr].type == CHARTK)) { functionDefinitionWithReturn(); } // 处理主函数 if (tokenPtr < tokenCount && tokens[tokenPtr].type == VOIDTK) { if (tokenPtr + 1 < tokenCount && tokens[tokenPtr + 1].type == MAINTK) { mainFunction(); } } outputSyntaxComponent("<程序>"); } void constDeclaration() { // 常量说明 -> const 类型 常量定义 { , 常量定义 } ; match(CONSTTK); TokenType type; if (tokens[tokenPtr].type == INTTK) { type = INTTK; match(INTTK); } else if (tokens[tokenPtr].type == CHARTK) { type = CHARTK; match(CHARTK); } else { // 类型错误,跳过 return; } constDefinition(type); while (tokenPtr < tokenCount && tokens[tokenPtr].type == COMMA) { match(COMMA); constDefinition(type); } match(SEMICN); outputSyntaxComponent("<常量说明>"); } void constDefinition(TokenType type) { // 常量定义 -> 标识符 = 整数 | 标识符 = 字符常量 if (!match(IDENFR)) return; if (!match(ASSIGN)) return; if (type == INTTK) { integer(); } else if (type == CHARTK) { if (currentTokenType() == CHARCON) { match(CHARCON); } else { // 字符常量期望错误,跳过 tokenPtr++; } } outputSyntaxComponent("<常量定义>"); } void integer() { // 整数 -> [+-] 无符号整数 | 无符号整数 if (tokenPtr < tokenCount && (tokens[tokenPtr].type == MINU || tokens[tokenPtr].type == PLUS)) { outputCurrentToken(); tokenPtr++; } unsignedInteger(); outputSyntaxComponent("<整数>"); } void unsignedInteger() { // 无符号整数 -> 数字 { 数字 } if (match(INTCON)) { outputSyntaxComponent("<无符号整数>"); } } void varDeclaration() { // 变量说明 -> 类型 变量定义 { , 变量定义 } ; TokenType type; if (tokens[tokenPtr].type == INTTK) { type = INTTK; match(INTTK); } else if (tokens[tokenPtr].type == CHARTK) { type = CHARTK; match(CHARTK); } else { // 类型错误,跳过 return; } varDefinition(type); while (tokenPtr < tokenCount && tokens[tokenPtr].type == COMMA) { match(COMMA); varDefinition(type); } match(SEMICN); outputSyntaxComponent("<变量说明>"); } void varDefinition(TokenType type) { // 变量定义 -> 标识符 [ = 整数 | = 字符常量 ] if (!match(IDENFR)) return; if (tokenPtr < tokenCount && tokens[tokenPtr].type == ASSIGN) { match(ASSIGN); if (type == INTTK) { integer(); } else if (type == CHARTK) { if (currentTokenType() == CHARCON) { match(CHARCON); } else { // 字符常量期望错误,跳过 tokenPtr++; } } } outputSyntaxComponent("<变量定义>"); } void functionDefinitionWithReturn() { // 有返回值函数定义 -> 类型 声明头部 ( 参数表 ) 复合语句 TokenType returnType; if (tokens[tokenPtr].type == INTTK) { returnType = INTTK; match(INTTK); } else if (tokens[tokenPtr].type == CHARTK) { returnType = CHARTK; match(CHARTK); } else { // 返回类型错误,跳过 return; } declarationHead(returnType); if (!match(LPARENT)) return; parameterList(); if (!match(RPARENT)) return; compoundStatement(); outputSyntaxComponent("<有返回值函数定义>"); } void declarationHead(TokenType returnType) { // 声明头部 -> 标识符 match(IDENFR); outputSyntaxComponent("<声明头部>"); } void parameterList() { // 参数表 -> 类型 标识符 { , 类型 标识符 } if (tokenPtr < tokenCount && (tokens[tokenPtr].type == INTTK || tokens[tokenPtr].type == CHARTK)) { // 处理第一个参数 if (tokens[tokenPtr].type == INTTK) { match(INTTK); } else { match(CHARTK); } match(IDENFR); // 处理后续参数 while (tokenPtr < tokenCount && tokens[tokenPtr].type == COMMA) { match(COMMA); if (tokens[tokenPtr].type == INTTK) { match(INTTK); } else if (tokens[tokenPtr].type == CHARTK) { match(CHARTK); } else { break; } match(IDENFR); } } outputSyntaxComponent("<参数表>"); } void compoundStatement() { // 复合语句 -> { 语句列 } if (!match(LBRACE)) return; statementList(); if (!match(RBRACE)) return; outputSyntaxComponent("<复合语句>"); } void statementList() { // 语句列 -> 语句 { 语句 } while (tokenPtr < tokenCount && tokens[tokenPtr].type != RBRACE && tokens[tokenPtr].type != EOFTK) { statement(); } outputSyntaxComponent("<语句列>"); } void statement() { // 语句 -> 赋值语句 | 返回语句 | 写语句 | 复合语句 if (tokenPtr + 1 < tokenCount && tokens[tokenPtr].type == IDENFR && tokens[tokenPtr + 1].type == ASSIGN) { assignmentStatement(); } else if (tokenPtr < tokenCount && tokens[tokenPtr].type == RETURNTK) { returnStatement(); } else if (tokenPtr < tokenCount && tokens[tokenPtr].type == PRINTFTK) { writeStatement(); } else if (tokenPtr < tokenCount && tokens[tokenPtr].type == LBRACE) { compoundStatement(); } else { // 其他类型的语句,这里简化处理 if (tokenPtr < tokenCount && tokens[tokenPtr].type == SEMICN) { match(SEMICN); // 空语句 } else { // 尝试解析表达式语句 expression(); if (tokenPtr < tokenCount && tokens[tokenPtr].type == SEMICN) { match(SEMICN); } } } outputSyntaxComponent("<语句>"); } void assignmentStatement() { // 赋值语句 -> 标识符 = 表达式 ; if (!match(IDENFR)) return; if (!match(ASSIGN)) return; expression(); if (!match(SEMICN)) return; outputSyntaxComponent("<赋值语句>"); } void returnStatement() { // 返回语句 -> return ( 表达式 ) ; if (!match(RETURNTK)) return; if (!match(LPARENT)) return; expression(); if (!match(RPARENT)) return; if (!match(SEMICN)) return; outputSyntaxComponent("<返回语句>"); } void writeStatement() { // 写语句 -> printf ( 表达式 | 字符串 ) ; if (!match(PRINTFTK)) return; if (!match(LPARENT)) return; if (currentTokenType() == STRCON) { stringLiteral(); } else { expression(); } if (!match(RPARENT)) return; if (!match(SEMICN)) return; outputSyntaxComponent("<写语句>"); } void mainFunction() { // 主函数 -> void main ( ) 复合语句 if (!match(VOIDTK)) return; if (!match(MAINTK)) return; if (!match(LPARENT)) return; if (!match(RPARENT)) return; compoundStatement(); outputSyntaxComponent("<主函数>"); } void expression() { // 表达式 -> 项 { + 项 | - 项 } term(); while (tokenPtr < tokenCount && (tokens[tokenPtr].type == PLUS || tokens[tokenPtr].type == MINU)) { if (tokens[tokenPtr].type == PLUS) { match(PLUS); } else { match(MINU); } term(); } outputSyntaxComponent("<表达式>"); } void term() { // 项 -> 因子 { * 因子 | / 因子 } factor(); while (tokenPtr < tokenCount && (tokens[tokenPtr].type == MULT || tokens[tokenPtr].type == DIV)) { if (tokens[tokenPtr].type == MULT) { match(MULT); } else { match(DIV); } factor(); } outputSyntaxComponent("<项>"); } void factor() { // 因子 -> 标识符 | 整数 | ( 表达式 ) | 有返回值函数调用语句 if (currentTokenType() == IDENFR) { // 检查是否是函数调用 if (tokenPtr + 1 < tokenCount && tokens[tokenPtr + 1].type == LPARENT) { functionCallWithReturn(); } else { match(IDENFR); } } else if (currentTokenType() == INTCON || currentTokenType() == MINU || currentTokenType() == PLUS) { integer(); } else if (currentTokenType() == LPARENT) { match(LPARENT); expression(); match(RPARENT); } else { // 因子期望错误,跳过 if (tokenPtr < tokenCount) tokenPtr++; } outputSyntaxComponent("<因子>"); } void functionCallWithReturn() { // 有返回值函数调用语句 -> 标识符 ( [值参数表] ) if (!match(IDENFR)) return; if (!match(LPARENT)) return; if (currentTokenType() != RPARENT) { valueParameterList(); } if (!match(RPARENT)) return; outputSyntaxComponent("<有返回值函数调用语句>"); } void valueParameterList() { // 值参数表 -> 表达式 { , 表达式 } expression(); while (tokenPtr < tokenCount && tokens[tokenPtr].type == COMMA) { match(COMMA); expression(); } outputSyntaxComponent("<值参数表>"); } void stringLiteral() { // 字符串 -> 字符串常量 if (match(STRCON)) { outputSyntaxComponent("<字符串>"); } } int main() { // 进行词法分析 lexAnalyze("testfile.txt"); // 打开输出文件 fout = fopen("output.txt", "w"); if (!fout) { fprintf(stderr, "无法打开输出文件: output.txt\n"); return 1; } // 进行语法分析 program(); // 释放资源 fclose(fout); free(tokens); return 0; }//检查代码并提高准确率
最新发布
11-03
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值