nancy.liao
1 天以前 11f2f2e329ef404d0e9c022cb2f9fbbb45bae285
完成了SCPI命令语法分析器的完整规则
5个文件已修改
1个文件已添加
1个文件已删除
737 ■■■■ 已修改文件
libscpi/inc/scpi/externinterface.cpp 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/inc/scpi/externinterface.h 257 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/inc/scpi/types.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/externinterface.cpp 350 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/parser.c 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/utils.c 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/utils_private.h 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/inc/scpi/externinterface.cpp
File was deleted
libscpi/inc/scpi/externinterface.h
@@ -1,253 +1,34 @@
#ifndef EXTERNINTERFACE_H
#define EXTERNINTERFACE_H
#include <iostream>
#include<vector>
//这个类用在做SCPI命令的语法分析,会将词法匹配的结果返回给SCPI库
#ifdef __cplusplus
extern "C"
{
#endif
namespace SCPIPASER
typedef struct
{
class Segment {
public:
    //必填
    bool is_required = false;
    //变量 [:Measure] 这种的为变量 会置为TRUE
    bool is_variable = false;
    //是否有嵌套形式
    bool is_nested = false;
    // 可选组的数量
    int variableSize = 0;
    std::vector<std::string> options;
    // std::vector<Segment> sub_segments; // 用于存储嵌套的可选组
};
    int is_required;
    int is_variable;
    int is_nested;
    int variableSize;
    char** options;
    int options_count;
} CSegment;
class PatternParser
typedef struct
{
private:
    static void trim_whitespace(std::string& str)
    {
        auto not_space = [](int ch) { return !std::isspace(ch); };
        str.erase(str.begin(), std::find_if(str.begin(), str.end(), not_space));
        str.erase(std::find_if(str.rbegin(), str.rend(), not_space).base(), str.end());
    }
    static std::vector<std::string> split_options(const std::string& input) {
        std::vector<std::string> result;
        size_t start = 0;
        size_t end = input.find('|');
        while (end != std::string::npos) {
            std::string token = input.substr(start, end - start);
            trim_whitespace(token);
            //token = remove_colon(token); // 移除冒号
            if (!token.empty()) result.push_back(token);
            start = end + 1;
            end = input.find('|', start);
        }
        std::string last_token = input.substr(start);
        trim_whitespace(last_token);
        last_token = remove_colon(last_token); // 移除冒号
        if (!last_token.empty()) result.push_back(last_token);
        return result;
    }
    static std::string remove_colon(const std::string& input) {
        std::string result;
        for (char ch : input) {
            if (ch != ':') {
                result += ch;
            }
        }
        return result;
    }
public:
    static std::vector<std::string> parse_input_data(const std::string& input)
    {
        std::vector<std::string> result;
        size_t start = 0;
        size_t end = input.find(':');
        while (end != std::string::npos)
        {
            result.push_back(input.substr(start, end - start));
            start = end + 1;
            end = input.find(':', start);
        }
        result.push_back(input.substr(start));
        return result;
    }
    static bool match_all_segments(std::vector<std::string> stringList, std::vector<Segment> vecSegment)
    {
        int currentIndex = 0;
        for (int i =0;i<vecSegment.size();i++)
        {
            auto currentSegment = vecSegment[i];
            //严格匹配
            if (currentSegment.is_required)
            {
                for (auto option : currentSegment.options)
                {
                    if (stringList[currentIndex] != option)
                    {
                        //std::cout << "参数匹配失败  " << stringList[currentIndex] << "   option :  " << option;
                        return false;
                    }
                    else
                    {
                        //std::cout << "参数匹配成功 " << stringList[currentIndex] << "   option :  " << option<<std::endl;
                        currentIndex += 1;
                    }
                    break;
                }
            }
            //可选组
            else if (currentSegment.is_variable)
            {
                //如果有可选组的情况下 且参数长度一直 则匹配可选项内容 否则的话跳过
                if (stringList.size() == vecSegment.size())
                {
                    auto vecTempSegments = currentSegment.options;
                    for (auto option : vecTempSegments)
                    {
                        if (stringList[currentIndex] != option)
                        {
                            //std::cout << "参数匹配失败  " << stringList[currentIndex] << "   option :  " << option;
                            return false;
                        }
                        else
                        {
                            //std::cout << "参数匹配成功 " << stringList[currentIndex] << "   option :  " << option << std::endl;
                            currentIndex += 1;
                        }
                        break;
                    }
                }
            }
            //可变参
            else
            {
                //std::cout << "可变参数: "<< stringList[currentIndex] << " " << currentSegment.options[0] << std::endl;
                currentIndex += 1;
            }
        }
        return true;
    }
    CSegment* segments;
    int segments_count;
} CPatternResult;
    static std::vector<Segment> extract_all_segments(const std::string& pattern)
    {
        std::vector<Segment> segments;
        size_t pos = 0;
        const size_t len = pattern.length();
        while (pos < len)
        {
            while (pos < len && std::isspace(pattern[pos])) ++pos;
            if (pos >= len) break;
            if (pattern[pos] == '<') {
                size_t end_pos = pattern.find('>', pos);
                if (end_pos == std::string::npos) break;
                std::string content = pattern.substr(pos + 1, end_pos - pos - 1);
                trim_whitespace(content);
                Segment segment;
                segment.is_variable = false; // `<...>` 不被视为变量
                segment.options = split_options(content);
                // 检查是否包含 `:`
                if (content.find(':') != std::string::npos) {
                    segment.is_required = true; // 如果包含 `:`
                }
                else {
                    segment.is_required = false; // 如果不包含 `:`
                }
                segments.push_back(segment);
                pos = end_pos + 1;
            }
            else if (pattern[pos] == '[')
            {
                size_t end_pos = pattern.find(']', pos);
                if (end_pos == std::string::npos) break;
                std::string content = pattern.substr(pos + 1, end_pos - pos - 1);
                trim_whitespace(content);
                Segment segment;
                segment.variableSize += 1;
                segment.is_required = false;
                segment.is_variable = true;
                segment.options = split_options(content);
                segments.push_back(segment);
                pos = end_pos + 1;
            }
            else
            {
                size_t next_lt = pattern.find('<', pos);
                size_t next_lb = pattern.find('[', pos);
                size_t next_special = std::min(next_lt, next_lb);
                std::string content;
                if (next_special != std::string::npos)
                {
                    content = pattern.substr(pos, next_special - pos);
                }
                else
                {
                    content = pattern.substr(pos);
                }
                trim_whitespace(content);
                if (!content.empty())
                {
                    // 用 ':' 拆分参数
                    size_t start = 0;
                    size_t end = content.find(':');
                    while (end != std::string::npos)
                    {
                        std::string token = content.substr(start, end - start);
                        trim_whitespace(token);
                        if (!token.empty())
                        {
                            Segment segment;
                            segment.is_required = true; // 明确标记为必填项
                            segment.is_variable = false; // 普通文本不视为变量
                            segment.options.push_back(token);
                            segments.push_back(segment);
                        }
                        start = end + 1;
                        end = content.find(':', start);
                    }
                    // 处理最后一个部分
                    std::string last_token = content.substr(start);
                    trim_whitespace(last_token);
                    if (!last_token.empty())
                    {
                        Segment segment;
                        segment.is_required = true;
                        segment.is_variable = false;
                        segment.options.push_back(last_token);
                        segments.push_back(segment);
                    }
                }
                pos = (next_special != std::string::npos) ? next_special : len;
            }
        }
        return segments;
    }
};
}
int match_segments_global(const char* input, int pattern_index);
void parse_pattern_global(const char* pattern);
int get_pattern_count();
void clear_global_patterns();
#ifdef __cplusplus
}
#endif
#endif // EXTERNINTERFACE_H
libscpi/inc/scpi/types.h
@@ -435,6 +435,7 @@
    };
    struct _scpi_t {
        //命令表的指针
        const scpi_command_t * cmdlist;
@@ -474,9 +475,8 @@
        int SCPIerror;
        //增加了一个命令列表的长度 防止非法越界
        int cmdlistSize;
    };
    enum _scpi_array_format_t {
        SCPI_FORMAT_ASCII = 0,
libscpi/src/externinterface.cpp
New file
@@ -0,0 +1,350 @@
#include "scpi/externinterface.h"
#include <vector>
#include <string>
#include <algorithm>
#include <cstring>
// 全局变量定义
CPatternResult* g_pattern_results = nullptr;
int g_pattern_count = 0;
class Segment {
public:
    bool is_required = false;
    bool is_variable = false;
    bool is_nested = false;
    int variableSize = 0;
    std::vector<std::string> options;
};
class PatternParser
{
private:
    //清除空格
    static void trim_whitespace(std::string& str)
    {
        auto not_space = [](int ch) { return !std::isspace(ch); };
        str.erase(str.begin(), std::find_if(str.begin(), str.end(), not_space));
        str.erase(std::find_if(str.rbegin(), str.rend(), not_space).base(), str.end());
    }
    //拆分可选参数
    static std::vector<std::string> split_options(const std::string& input)
    {
        std::vector<std::string> result;
        size_t start = 0;
        size_t end = input.find('|');
        while (end != std::string::npos)
        {
            std::string token = input.substr(start, end - start);
            trim_whitespace(token);
            if (!token.empty()) result.push_back(token);
            start = end + 1;
            end = input.find('|', start);
        }
        std::string last_token = input.substr(start);
        trim_whitespace(last_token);
        last_token = remove_colon(last_token);
        if (!last_token.empty()) result.push_back(last_token);
        return result;
    }
    //删掉可能携带的:分割符
    static std::string remove_colon(const std::string& input)
    {
        std::string result;
        for (char ch : input)
        {
            if (ch != ':') {
                result += ch;
            }
        }
        return result;
    }
public:
    static std::vector<std::string> parse_input_data(const std::string& input)
    {
        std::vector<std::string> result;
        size_t start = 0;
        size_t end = input.find(':');
        while (end != std::string::npos)
        {
            result.push_back(input.substr(start, end - start));
            start = end + 1;
            end = input.find(':', start);
        }
        result.push_back(input.substr(start));
        return result;
    }
    static bool match_all_segments(const std::vector<std::string>& stringList,
                                   const std::vector<Segment>& vecSegment)
    {
        int currentIndex = 0;
        for (size_t i = 0; i < vecSegment.size(); i++)
        {
            auto currentSegment = vecSegment[i];
            if (currentSegment.is_required) {
                for (const auto& option : currentSegment.options)
                {
                    //当索引index超过输入参数的词组大小 则表示命令不匹配
                    if(currentIndex >= stringList.size())
                    {
                        return false;
                    }
                    if (stringList[currentIndex] != option)
                    {
                        return false;
                    } else {
                        currentIndex += 1;
                    }
                    break;
                }
            }
            else if (currentSegment.is_variable)
            {
                if (stringList.size() == vecSegment.size())
                {
                    auto vecTempSegments = currentSegment.options;
                    for (const auto& option : vecTempSegments)
                    {
                        if (stringList[currentIndex] != option)
                        {
                            return false;
                        } else {
                            currentIndex += 1;
                        }
                        break;
                    }
                }
            }
            else {
                currentIndex += 1;
            }
        }
        return true;
    }
    static std::vector<Segment> extract_all_segments(const std::string& pattern)
    {
        std::vector<Segment> segments;
        size_t pos = 0;
        const size_t len = pattern.length();
        while (pos < len)
        {
            while (pos < len && std::isspace(pattern[pos])) ++pos;
            if (pos >= len) break;
            if (pattern[pos] == '<')
            {
                size_t end_pos = pattern.find('>', pos);
                if (end_pos == std::string::npos) break;
                std::string content = pattern.substr(pos + 1, end_pos - pos - 1);
                trim_whitespace(content);
                Segment segment;
                segment.is_variable = false;
                segment.options = split_options(content);
                if (content.find(':') != std::string::npos)
                {
                    segment.is_required = true;
                } else
                {
                    segment.is_required = false;
                }
                segments.push_back(segment);
                pos = end_pos + 1;
            }
            else if (pattern[pos] == '[')
            {
                size_t end_pos = pattern.find(']', pos);
                if (end_pos == std::string::npos) break;
                std::string content = pattern.substr(pos + 1, end_pos - pos - 1);
                trim_whitespace(content);
                Segment segment;
                segment.variableSize += 1;
                segment.is_required = false;
                segment.is_variable = true;
                segment.options = split_options(content);
                segments.push_back(segment);
                pos = end_pos + 1;
            }
            else
            {
                size_t next_lt = pattern.find('<', pos);
                size_t next_lb = pattern.find('[', pos);
                size_t next_special = std::min(next_lt, next_lb);
                std::string content;
                if (next_special != std::string::npos)
                {
                    content = pattern.substr(pos, next_special - pos);
                } else
                {
                    content = pattern.substr(pos);
                }
                trim_whitespace(content);
                if (!content.empty())
                {
                    size_t start = 0;
                    size_t end = content.find(':');
                    while (end != std::string::npos)
                    {
                        std::string token = content.substr(start, end - start);
                        trim_whitespace(token);
                        if (!token.empty())
                        {
                            Segment segment;
                            segment.is_required = true;
                            segment.is_variable = false;
                            segment.options.push_back(token);
                            segments.push_back(segment);
                        }
                        start = end + 1;
                        end = content.find(':', start);
                    }
                    std::string last_token = content.substr(start);
                    trim_whitespace(last_token);
                    if (!last_token.empty())
                    {
                        Segment segment;
                        segment.is_required = true;
                        segment.is_variable = false;
                        segment.options.push_back(last_token);
                        segments.push_back(segment);
                    }
                }
                pos = (next_special != std::string::npos) ? next_special : len;
            }
        }
        return segments;
    }
};
// 全局管理函数实现
void add_pattern_to_global(const std::vector<Segment>& segments)
{
    // 重新分配内存
    CPatternResult* new_results = new CPatternResult[g_pattern_count + 1];
    // 复制旧数据
    for (int i = 0; i < g_pattern_count; ++i)
    {
        new_results[i] = g_pattern_results[i];
    }
    // 添加新数据
    CPatternResult& new_item = new_results[g_pattern_count];
    new_item.segments_count = static_cast<int>(segments.size());
    new_item.segments = new CSegment[segments.size()];
    for (size_t i = 0; i < segments.size(); ++i)
    {
        const auto& seg = segments[i];
        new_item.segments[i].is_required = seg.is_required;
        new_item.segments[i].is_variable = seg.is_variable;
        new_item.segments[i].is_nested = seg.is_nested;
        new_item.segments[i].variableSize = seg.variableSize;
        new_item.segments[i].options_count = static_cast<int>(seg.options.size());
        new_item.segments[i].options = new char*[seg.options.size()];
        for (size_t j = 0; j < seg.options.size(); ++j)
        {
            new_item.segments[i].options[j] = strdup(seg.options[j].c_str());
        }
    }
    // 释放旧内存并更新指针
    delete[] g_pattern_results;
    g_pattern_results = new_results;
    g_pattern_count++;
}
void clear_global_patterns() {
    for (int i = 0; i < g_pattern_count; ++i)
    {
        for (int j = 0; j < g_pattern_results[i].segments_count; ++j)
        {
            for (int k = 0; k < g_pattern_results[i].segments[j].options_count; ++k)
            {
                free(g_pattern_results[i].segments[j].options[k]);
            }
            delete[] g_pattern_results[i].segments[j].options;
        }
        delete[] g_pattern_results[i].segments;
    }
    delete[] g_pattern_results;
    g_pattern_results = nullptr;
    g_pattern_count = 0;
}
int get_pattern_count() { return g_pattern_count; }
void parse_pattern_global(const char* pattern)
{
    auto segments = PatternParser::extract_all_segments(pattern);
    add_pattern_to_global(segments);
}
int match_segments_global(const char* input, int pattern_index)
{
    if (pattern_index < 0 || pattern_index >= g_pattern_count)
    {
        return 0;
    }
    std::string inputStr(input);
    inputStr.erase(std::remove(inputStr.begin(), inputStr.end(), '\n'), inputStr.end());
    std::vector<std::string> inputList;
    size_t start = 0;
    size_t end = inputStr.find(':');
    while (end != std::string::npos)
    {
        inputList.push_back(inputStr.substr(start, end - start));
        start = end + 1;
        end = inputStr.find(':', start);
    }
    inputList.push_back(inputStr.substr(start));
    std::vector<Segment> segments;
    CPatternResult& pattern = g_pattern_results[pattern_index];
    for (int i = 0; i < pattern.segments_count; ++i)
    {
        Segment seg;
        seg.is_required = pattern.segments[i].is_required;
        seg.is_variable = pattern.segments[i].is_variable;
        seg.is_nested = pattern.segments[i].is_nested;
        seg.variableSize = pattern.segments[i].variableSize;
        for (int j = 0; j < pattern.segments[i].options_count; ++j)
        {
            seg.options.push_back(pattern.segments[i].options[j]);
        }
        segments.push_back(seg);
    }
    return PatternParser::match_all_segments(inputList, segments) ? 1 : 0;
}
libscpi/src/parser.c
@@ -37,6 +37,7 @@
#include <ctype.h>
#include <string.h>
#include "scpi/externinterface.h"
#include "scpi/config.h"
#include "scpi/parser.h"
@@ -45,7 +46,7 @@
#include "scpi/error.h"
#include "scpi/constants.h"
#include "scpi/utils.h"
#include "scpi/externinterface.h"
/**
 * Write data to SCPI output
 * @param context
@@ -183,21 +184,13 @@
scpi_bool_t findCommandHeader(scpi_t * context, const char * header, int len)
{
    int32_t i;
    const scpi_command_t * cmd = NULL;
    for (i = 0; i<context->cmdlistSize; i++) {
        cmd = &context->cmdlist[i];
        bool result =test_match(cmd->pattern, header);
        if(result)
    for(int i=0;i<get_pattern_count();i++)
    {
        if( match_segments_global(header,i) )
        {
             context->param_list.cmd = &context->cmdlist[i];
            context->param_list.cmd = &context->cmdlist[i];
            return TRUE;
        }
        // if (matchCommand(cmd->pattern, header, len, NULL, 0, 0)) {
        //     context->param_list.cmd = cmd;
        //     return TRUE;
        // }
    }
    context->SCPIerror = RETURN_NotFind;
    return FALSE;
libscpi/src/utils.c
@@ -1144,100 +1144,3 @@
           ((val & 0x00FF000000000000ull) >> 40) |
           ((val & 0xFF00000000000000ull) >> 56);
}
// 用于提取并处理选项的函数
int extract_required_options(const char* pattern, char options[MAX_TAGS][MAX_OPTION_LEN][MAX_OPTION_LEN], int max_tags) {
    const char* start = strchr(pattern, '<');  // 查找第一个 '<'
    const char* end = NULL;
    int tag_count = 0;
    // 处理 <...> 内的选项
    while (start != NULL && tag_count < max_tags)
    {
        end = strchr(start, '>');  // 查找对应的 '>'
        if (end == NULL) {
            break;  // 如果没有找到 '>',则退出
        }
        // 提取 <...> 中的内容
        int len = end - start - 1;
        if (len > 0 && len < MAX_OPTION_LEN) {
            char buffer[MAX_OPTION_LEN];
            strncpy(buffer, start + 1, len);  // 复制 '<' 和 '>' 之间的内容
            buffer[len] = '\0';  // 结束符
            // 处理 | 分隔符,提取多个选项
            char* token = strtok(buffer, "|");
            int option_count = 0;
            while (token && option_count < MAX_OPTION_LEN) {
                // 去除 token 中的 "[:", "]" 和空格
                char* p = token;
                while (*p == ' ' || *p == '[' || *p == ':') p++;  // 去除前导空格和 [:
                char* q = p + strlen(p) - 1;
                while (q > p && (*q == ' ' || *q == ']')) q--;  // 去除尾随空格和 ]
                *(q + 1) = '\0';  // 确保结尾是'\0'
                // 拷贝选项到 options 数组
                if (option_count < MAX_OPTION_LEN) {  // 确保不会越界
                    strncpy(options[tag_count][option_count], p, MAX_OPTION_LEN - 1);
                    options[tag_count][option_count][MAX_OPTION_LEN - 1] = '\0';  // 确保结束符
                    option_count++;
                }
                token = strtok(NULL, "|");
            }
        }
        // 移动到下一个 '<' 位置,继续查找
        start = strchr(end + 1, '<');
        tag_count++;
    }
    return tag_count;
}
// 用于检查输入是否能匹配每一组选项
int match_input_to_options(const char* input, char options[MAX_TAGS][MAX_OPTION_LEN][MAX_OPTION_LEN], int num_tags) {
    char input_copy[MAX_INPUT_LEN];
    strncpy(input_copy, input, MAX_INPUT_LEN - 1);
    input_copy[MAX_INPUT_LEN - 1] = '\0';  // 确保结尾是'\0'
    // 拆分输入字符串,按 ":" 分割
    char* token = strtok(input_copy, ":");
    int group_idx = 0;
    // 对每一组进行匹配
    while (token != NULL && group_idx < num_tags) {
        int match_found = 0;
        // 检查当前组的每个选项是否与输入的 token 匹配
        printf("Checking input token: '%s' against group %d options\n", token, group_idx + 1); // Debug info
        for (int i = 0; i < MAX_OPTION_LEN && options[group_idx][i][0] != '\0'; i++) {
            printf("  Comparing with option: '%s'\n", options[group_idx][i]); // Debug info
            if (strcmp(options[group_idx][i], token) == 0) {
                match_found = 1;
                break;
            }
        }
        // 如果当前组的某个选项没有匹配上,返回 false
        if (!match_found) {
            return 0;  // 不匹配
        }
        // 处理下一个输入部分
        token = strtok(NULL, ":");
        group_idx++;
    }
    return (group_idx == num_tags);
}
// 测试匹配函数
bool test_match(const char* pattern, const char* command)
{
    char options[MAX_TAGS][MAX_OPTION_LEN][MAX_OPTION_LEN] = { {{0}} };
    int num_tags = extract_required_options(pattern, options, MAX_TAGS);
    return match_input_to_options(command, options, num_tags);
}
libscpi/src/utils_private.h
@@ -79,14 +79,6 @@
scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current) LOCAL;
#define MAX_OPTION_LEN 256
#define MAX_TAGS 10
#define MAX_INPUT_LEN 256
int extract_required_options(const char* pattern, char options[MAX_TAGS][MAX_OPTION_LEN][MAX_OPTION_LEN], int max_tags);
int match_input_to_options(const char* input, char options[MAX_TAGS][MAX_OPTION_LEN][MAX_OPTION_LEN], int num_tags);
bool test_match(const char* pattern, const char* command);
#define SCPI_DTOSTRE_UPPERCASE   1
#define SCPI_DTOSTRE_ALWAYS_SIGN 2
#define SCPI_DTOSTRE_PLUS_SIGN   4