Преобразование VBScript в Javascript, как правильно разбирать исходный код? - PullRequest
2 голосов
/ 24 декабря 2010

Меня попросили преобразовать некоторый код VB6 / VBScript в javascript, поэтому после поиска в Google и не найдя ничего, что я мог бы использовать, я написал небольшую функцию javascript, чтобы помочь мне выполнить преобразование;он такой грубый и только конвертирует (некоторые из) синтаксис, но он работал на меня для той работы, которую я выполнял ... теперь я думаю об ее улучшении, но метод, который я использовал, настолько примитивен (сравнение и замена регулярных выражений).Итак ... мой вопрос: как правильно разобрать исходный код?Есть ли какой-нибудь (не такой сложный) способ сделать это?и я не хочу использовать Exe, это должно быть сделано полностью в Javascript.Я не ищу готовый исходный код (я не думаю, что он существует!), Но я хочу узнать, как можно начинать с исходного кода и превращать его в объекты (я думаю, что это противоположно сериализации)?).

//here is the code:

var strs=[];

function vbsTojs(vbs){


    var s = vbs;

    s = HideStrings(s);

    //only function block
    s = s.match(/Function[\w\W]+End\s+Function/gim)[0];

    //line-continuation char
    s = s.replace(/_\n/gm,"");

    //replace ":" with CRLF
    s = s.replace(/:/gm,"\n");

    //move inline comment to its own line
    s = s.replace(/^(.+)'(.*)$/gim,"'$2\n$1");

    //single line if -> multiple line
    s = s.replace(/\bthen\b[ \t](.+)/gi,"then\n$1\nEnd If");

    //alert(s);

    var Vars='';
    var Fx='';
    var FxHead='';
    var Args = '';

    a=s.split('\n');

    //trim
    for(i=0;i<a.length;i++){
        a[i]=a[i].replace(/^\s+|\s+$/,"");
    }
     //remove empty items
    a=a.filter(function(val) { return val !== ""; });


    //alert(a.join('\n'));


    //function
    a[0]=a[0].replace(/function\s+/i,"");
    Fx = a[0].match(/^\w+/)[0];
    a[0]=a[0].replace(Fx,"").replace(/[\(\)]/g,"");
    a[0]=a[0].replace(/\bbyval\b/gi,"").replace(/\bbyref\b/gi,"").replace(/\boptional\b/gi,"");
    a[0]=a[0].replace(/\bas\s+\w+\b/gi,"");
    a[0]=a[0].replace(/\s+/g,"");
    a[0]=a[0].replace(/,/gi,", ");
    FxHead = "function " + Fx+ " ("+ a[0] + "){";
    a[0]="";

    //end function
    a.length = a.length-1;

    for(i=1;i<a.length;i++){

        //Vars
        if(a[i].search(/^dim\s+/i)>-1){
            a[i]=a[i].replace(/dim\s*/i,"");
            Vars += a[i] + ",";
            a[i]='';

        //FOR
        }else if(a[i].search(/^\bFOR\b\s+/i)>-1){
            a[i]=a[i].replace(/^\bFOR\b\s+/i,"");
            counter = a[i].match(/^\w+/)[0];
            from = a[i].match(/=\s*[\w\(\)]+/)[0];
            from=from.replace(/=/,"").replace(/\s+/g,"");
            a[i]=a[i].replace(counter,"").replace(from,"").replace(/\bTO\b/i,"");
            to = a[i].match(/\s*[\w\(\)]+\s*/)[0];
            to=to.replace(/=/,"").replace(/\s+/g,"");
            a[i] = "for(" + counter + "=" + from + "; " + counter + "<=" + to + "; " + counter + "++){"

        //NEXT
        }else if(a[i].search(/^NEXT\b/i)>-1){
            a[i] = "}";
        //EXIT FOR
        }else if(a[i].search(/\bEXIT\b\s*\bFOR\b/i)>-1){
            a[i] = "break";

        //IF
        }else if(a[i].search(/^\bIF\b\s+/i)>-1){
            a[i]=a[i].replace(/^\bIF\b\s+/i,"");
            a[i]=a[i].replace(/\bTHEN$\b/i,"");
            a[i]=a[i].replace(/=/g,"==").replace(/<>/g,"!=");                 //TODO: it should not replace if inside a string! <---------------
            a[i]=a[i].replace(/\bOR\b/gi,"||").replace(/\bAND\b/gi,"&&");     //TODO: it should not replace if inside a string! <---------------
            a[i] = "if(" + a[i] + "){";

        //ELSE
        }else if(a[i].search(/^ELSE/i)>-1){
            a[i] = "}else{";

        //END IF
        }else if(a[i].search(/^END\s*IF/i)>-1){
            a[i] = "}";

        //WHILE
        }else if(a[i].search(/^WHILE\s/i)>-1){
            a[i] = a[i].replace(/^WHILE(.+)/i,"while($1){");
        //WEND
        }else if(a[i].search(/^WEND/i)>-1){
            a[i] = "}";

        //DO WHILE
        }else if(a[i].search(/^DO\s+WHILE\s/i)>-1){
            a[i] = a[i].replace(/^DO\s+WHILE(.+)/i,"while($1){");
        //LOOP
        }else if(a[i].search(/^LOOP$/i)>-1){
            a[i] = "}";

        //EXIT FUNCTION
        }else if(a[i].search(/\bEXIT\b\s*\bFUNCTION\b/i)>-1){
            a[i] = "return";

        //SELECT CASE
        }else if(a[i].search(/^SELECT\s+CASE(.+$)/i)>-1){
            a[i]=a[i].replace(/^SELECT\s+CASE(.+$)/i,"switch($1){");
        }else if(a[i].search(/^END\s+SELECT/i)>-1){
            a[i] = "}";
        }else if(a[i].search(/^CASE\s+ELSE/i)>-1){
            a[i] = "default:";
        }else if(a[i].search(/^CASE[\w\W]+$/i)>-1){
            a[i] = a[i] + ":" ;
        }
        //CONST
        else if(a[i].search(/^CONST/i)>-1){
            a[i] = a[i].replace(/^CONST/i,"const");
        }

        else{
            //alert(a[i]);
        }

        //COMMENT
        if(a[i].search(/^\'/)>-1){
            a[i]=a[i].replace(/^\'/,"//");
        }else if(a[i].search(/\'.*$/)>-1){
            a[i]=a[i].replace(/\'(.*)$/,"//$1");
        }
    }

    //alert(a.join("*"));   

    Vars = Vars.replace(/\s*AS\s+\w+\s*/gi,"");
    if(Vars!="") Vars = "var " + Vars.replace(/,$/,";").replace(/,/g,", ");
    FxHead  + '\n' + Vars;

    a=a.filter(function(val) { return val !== ""; }) //remove empty items

    for(i=0;i<a.length;i++){
        if (a[i].search(/[^}{:]$/)>-1) a[i]+=";";
    }

    ss = FxHead + '\n' + Vars + '\n' + a.join('\n') + '\n}';

    ss = ss.replace(new RegExp(Fx+"\\s*=\\s*","gi"),"return ");

    ss = UnHideStrings(ss);

    return jsIndenter(ss);
}




//-----------------------------------------------------

function jsIndenter(js){

    var a=js.split('\n');
    var margin=0;
    var s = '';

    //trim
    for(i=0;i<a.length;i++){ a[i]=a[i].replace(/^\s+|\s+$/,""); }
     //remove empty items
    a=a.filter(function(val) { return val !== ""; });


    for(var i=1;i<a.length;i++){

        if(a[i-1].indexOf("{")>-1) margin += 4 ;

        if(a[i].indexOf("}")>-1) { margin -= 4; }

        if(margin<0) margin = 0;

        a[i] = StrFill(margin," ") + a[i] ;
    }
    return a.join('\n');
}


function StrFill(Count,StrToFill){
    var objStr,idx;
    if(StrToFill=="" || Count==0){
        return "";
    }
    objStr="";
        for(idx=1;idx<=Count;idx++){
        objStr += StrToFill;
    }
    return objStr;
}

function HideStrings(text){

    const x = String.fromCharCode(7);
    const xxx = String.fromCharCode(8);

    text = text.replace(/"""/gim, '"'+xxx);  //hide 3 quotes " " "
    var idx=0, f=0;
    while(f>-1){
        f = text.search(/".+?"/gim);
        if(f>-1){
            strs.push(text.match(/".+?"/)[0]);
            //alert(strs[idx]);
            text = text.replace(/".+?"/, x+idx+x);
            idx++;
        }
    }
    //alert(text);
    return text;
}

function UnHideStrings(text){
    for(var i=0; i<strs.length; i++){
        text = text.replace(new RegExp("\\x07"+i+"\\x07"), strs[i]);
    }
    //Unhide 3 quotes " " " ***BUG: causes unterminated string if triple-quotes are at the end of the string
    text = text.replace(/\x08/gim,'\\"');
    text = text.replace(/""/gi,'\\"');    
    return text;
}

Ответы [ 2 ]

4 голосов
/ 24 декабря 2010

Правильный способ разбора исходного кода для любого языка программирования - использовать parser .Регулярные выражения являются полезными part (некоторыми) синтаксическими анализаторами, но анализатор - это совсем другое.В литературе по информатике есть целый ряд исследований и методик на предмет анализа, и это увлекательное занятие для изучения.

«Преобразование» набора кода Visual Basic в Javascript - это проект, который кажетсяпо своей сути чреват опасностями и тайнами.Анализатор Visual Basic будет лишь первым значительным препятствием для преодоления.После этого вам необходимо выяснить, как семантически представлять операции Visual Basic в Javascript.В зависимости от исходного контекста кода это может быть несколько странно.(Вы ничего не упоминаете о , где этот код выполняется.)

Как бы полезен ни был опыт обучения, весьма вероятно, что перевод кода вручную будет (вконец) займет меньше времени и даст лучшие результаты.Это особенно верно, если вы только сейчас узнаете, что существует такая вещь, как «парсер».

0 голосов
/ 24 декабря 2010

Отличная работа. Похоже, ты сделал что-то, что могло бы быть не идеальным, но это сделало свою работу.

Я бы порекомендовал изучить парсеры и грамматики, если вы хотите сделать его более сложным. Есть много генераторов парсеров, которые могли бы вам помочь. Вам нужно будет придумать грамматику для исходного языка, сгенерировать лексер / парсер, а затем использовать ее для создания абстрактного синтаксического дерева (AST). Как только у вас есть это, вы можете пройти AST и попросить его выдать любой код, который вы хотите.

Это выполнимо, но, как говорит Одед, это не тривиально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...