यह एक ऐसी समस्या है जिसे मैंने सोचा था कि हल हो गया है, लेकिन जाहिर है कि मुझे अभी भी यहां और वहां छोटे कीड़े हैं। नीचे दिया गया कोड वह है जिसका उपयोग मैं एक बनाई गई भाषा का उपयोग करके एक टेक्स्ट फ़ाइल को पार्स करने के लिए कर रहा हूं जिसे मैं प्रोटोटाइप माइक्रोकंट्रोलर के लिए विकसित कर रहा हूं। मूल रूप से, जब भी मैं अर्धविराम तक पहुंचता हूं, मैं बाद में किसी भी पाठ को एक टिप्पणी के रूप में मानता हूं और इसे अनदेखा करता हूं:

   `//Get characters from .j FILE`
    while (fgets(line, 1000, IN) != NULL)
    {
        //Get each line of .j file


        //Compute length of each line
        len = strlen(line);

        //If length is zero or if there is newline escape sequnce
        if (len > 0 && line[len-1] == '\n')
        {
            //Replace with null
            line[len-1] = '\0';
        }

        //Search for semicolons in .J FILE
        semi_token = strpbrk(line, ";\r\n\t");

        //Replace with null terminator
        if (semi_token) 
        {
            *semi_token = '\0';
        }
        printf("line is %s\n",line );

        //Copy each line
        assign = line;

        // printf("line is %s\n",line );

        // len = strlen(line);

        // printf("line length is %d\n",len );

        // parse_tok = strtok(line, "\r ");

    }   

उपरोक्त कोड जबकि लूप है जो टेक्स्ट फ़ाइल से प्रत्येक पंक्ति प्राप्त करता है। अगर मेरे पास नीचे दिए गए प्रारूप में एक फ़ाइल है, तो सब कुछ ठीक काम करता है:

;;
;; Basic
;;

defun test arg3 arg2 arg1 min return 
;defun love arg2 arg1 * return
;defun func_1 6 6 eq return
;defun func_2 20 100 / return

defun main
0 -200 55 test printnum endl
;1 2 3 test printnum endl
;38 23 8 test printnum endl
;5 6 7 love printnum endl
;love printnum endl
;func_1 printnum endl
;func_2 printnum endl
return

आउटपुट का निरीक्षण करें:

line is 
line is 
line is 
line is 
line is defun test arg3 arg2 arg1 min return 
line is 
line is 
line is 
line is 
line is defun main
line is 0 -200 55 test printnum endl
line is 
line is 
line is 
line is 
line is 
line is 
line is return

समस्या तब होती है जब मेरी टेक्स्ट फ़ाइल में उस मामले में टैब होते हैं जहां नेस्टेड स्टेटमेंट होते हैं:

;;
;; program to test nested ifs
;;

defun testIfs ;; called with one parameter n

arg1           ; get n to the top of the stack

dup 16 gt
if   ; 16 > n

    dup 8 gt
    if  ; 8 > n

        dup 4 gt
    if  ; 4 > n
        0
    else        ; 4 <= n
        1
    endif

    else        ; 8 <= n
       2
    endif

else        ; 16 <= n

     dup 24 gt
     if ; 24 > n

        dup 20 gt
    if  ; 20 > n
           3
        else        ; 20 <= n
           4
    endif

     else           ; 24 <= n

        dup 32 gt
        if  ; 32 > n
           5
    else
        -10
        endif

     endif

endif

return


defun main 
5 testIfs printnum endl
11 testIfs printnum endl
28 testIfs printnum endl
35 testIfs printnum endl
return

आउटपुट का निरीक्षण करें:

line is 
line is 
line is 
line is 
line is defun testIfs 
line is 
line is arg1           
line is 
line is dup 16 gt
line is if   
line is 
line is     dup 8 gt
line is     if
line is 
line is     
line is 
line is 
line is 
line is 
line is 
line is 
line is     else
line is        2
line is     endif
line is 
line is else
line is 
line is      dup 24 gt
line is      if
line is 
line is      
line is 
line is            3
line is         else   
line is            4
line is 
line is 
line is      else   
line is 
line is         dup 32 gt
line is         if
line is            5
line is 
line is 
line is         endif
line is 
line is      endif
line is 
line is endif
line is 
line is return
line is 
line is 
line is defun main 
line is 5 testIfs printnum endl
line is 11 testIfs printnum endl
line is 28 testIfs printnum endl
line is 35 testIfs printnum endl
line is return

जैसा कि आप देख सकते हैं, यह कुछ पंक्तियों को छोड़ देता है (प्रतीत होता है कि बेतरतीब ढंग से) टैब किए गए हैं और मुझे नहीं पता कि यह ऐसा क्यों कर रहा है। मेरे कोड में क्या संशोधित करने की आवश्यकता है ताकि यह बेतरतीब ढंग से टैब की गई कुछ पंक्तियों को न छोड़े? किसी भी मदद की सराहना की जाती है!

0
J_code 22 जुलाई 2018, 19:52
मिले पहले टैब पर आप पूरी लाइन को ट्रैश कर रहे हैं। इसका मतलब है कि इंडेंटेशन टैब को टिप्पणी सीमांकक के रूप में पहचाना जाता है और शेष पंक्ति को छोड़ दिया जाता है। आपको टिप्पणी सीमांकक से रिक्त स्थान, यानी टैब और रिक्त स्थान के लिए दिए गए मान को फ़िल्टर करना होगा।
 – 
Frankie_C
22 जुलाई 2018, 20:04
रिक्त स्थान के लिए दिए गए मान को फ़िल्टर करके, पंक्ति नहीं है: 'semi_token = strpbrk(line, ";\r\n\t");' इसे करें? भ्रमित करने वाली बात यह है कि अन्य लाइनें हैं जिन्हें टैब किया जा रहा है लेकिन फिर भी मेरे कोड द्वारा पता लगाया जा रहा है
 – 
J_code
22 जुलाई 2018, 20:13
आपका कोड टैब, न्यूलाइन और कैरिज रिटर्न के लिए रुक जाता है, और उन सभी के लिए आप लाइन को शून्य कर देते हैं। आप जांच सकते हैं कि क्या पाया गया है और उनमें से प्रत्येक के लिए एक अलग क्रिया को क्रियान्वित कर सकते हैं, या आप केवल अर्धविराम की तलाश करने का प्रयास कर सकते हैं। कोड को semi_token = strpbrk(line, ";\r\n"); में बदलें
 – 
Frankie_C
23 जुलाई 2018, 00:32

2 जवाब

यहाँ वह हिस्सा है जो अर्धविराम की तलाश करता है:

    //Search for semicolons in .J FILE
    semi_token = strpbrk(line, ";\r\n\t");

यह स्पष्ट रूप से टैब वर्णों को अर्धविराम के समान मानता है, अर्थात एक टिप्पणी शुरू करना। बग हमेशा क्यों नहीं होता है - मुझे लगता है कि कभी-कभी आपका संपादक आपकी *.J इनपुट फ़ाइल में एक टैब (\t) वर्ण को रिक्त स्थान में परिवर्तित करता है।

4
anatolyg 22 जुलाई 2018, 20:03

जैसा कि अन्य लोगों ने बताया है, strpbrk (line, ";\r\n\t"); का आपका उपयोग line में पहले ';', '\r', '\n' या \t' पर एक सूचक लौटाएगा। यदि आपकी फ़ाइल में इंडेंटेशन के लिए टैब वर्ण शामिल हैं (जो इसे तब तक नहीं करना चाहिए जब तक कि यह मेकफ़ाइल न हो), तो आप संभवतः शुरुआत में ही अपनी लाइन को नल-टर्मिनेट कर सकते हैं। यह वह नहीं है जो आप चाहते हैं।

हालांकि, आपकी पसंद strpbrk कार्य के लिए अच्छी है। यदि आप अपने स्वीकार वर्णों के सेट से '\t' को हटा देते हैं, तो आप अपने इच्छित लक्ष्य को प्राप्त करने के करीब पहुंच जाएंगे। (आप '\r' को हटा सकते हैं और साथ ही लाइन-एंडिंग्स को पढ़ने पर '\n' में बदल दिया जाएगा)

अपने कोड के एक बहुत ही सरल संस्करण में जहां आप अंतिम गैर-व्हाट्सएप वर्ण और फिर टिप्पणी की शुरुआत (या पंक्ति के अंत) के बीच किसी भी पिछली सफेद जगह को ट्रिम करने के बारे में चिंता नहीं करते हैं, आप कुछ सरल कर सकते हैं जैसे strpbrk द्वारा लौटाए गए पॉइंटर पर nul-टर्मिनेटिंग लाइन, उदाहरण के लिए

#include <stdio.h>
#include <string.h>

#define MAXC 1024

int main (void) {

    char line[MAXC] = "";
    size_t lineno = 0;

    /* read each line from stdin (e.g. redirect file, ./prog <file) */
    while (fgets(line, MAXC, stdin) != NULL)
    {
        char *p = NULL;         /* pointer for strchr return */

        /* Search for semicolons in line or newline */
        if ((p = strpbrk (line, ";\n")))
            *p = 0;             /* nul-terminate at ';' or '\n' */

        /* output line (single-quotes simply show trim of whitespace) */
        printf ("%3zu: '%s'\n", ++lineno, line);
    }

    return 0;
}

उदाहरण उपयोग/आउटपुट

ध्यान दें: आउटपुट के चारों ओर सिंगल-कोट्स शामिल किए गए हैं, ताकि पिछली खाली जगह को दिखाया जा सके।

$ ./bin/parsesemisimple <dat/semicmtfile.txt
  1: ''
  2: ''
  3: ''
  4: ''
  5: 'defun testIfs '
  6: ''
  7: 'arg1           '
  ...

ध्यान दें कि arg1 के अंत के बाद पंक्ति "arg1 ; get n to the top of the stack" में 10-रिक्त स्थान हैं और टिप्पणी वर्ण। लटकती हुई सफेद जगह को छोड़ना कभी अच्छा विचार नहीं है।

पिछली सफेद जगह को हटाने के लिए, आप ctype.h शामिल कर सकते हैं और यह जांचने के लिए isspace फ़ंक्शन का उपयोग कर सकते हैं कि टिप्पणी से पहले कोई भी वर्ण व्हाइटस्पेस है, और यदि कुछ है, तो आप देर से मिलने तक बस बैक अप लेते रहें गैर-व्हाट्सएप चरित्र। एक बार जब आपको अंतिम गैर-व्हाट्सएप वर्ण मिल जाता है, तो आप उसे बाद समाप्त कर देते हैं।

ऐसा करने के लिए आप अपने strpbrk सशर्त कोड की कुछ पंक्तियाँ जोड़ सकते हैं। ध्यान दें: बैकअप लेते समय, आप हमेशा यह सुनिश्चित करना चाहते हैं कि (p > line) ताकि आप line की शुरुआत से पहले बैकअप न लें, और आपको यह भी पता हो कि क्या p line से बड़ा नहीं है, टिप्पणी वहीं से शुरू होती है या यह एक खाली लाइन थी। आप निम्न की तरह कुछ कर सकते हैं:

#include <ctype.h>
...
        /* Search for semicolons in line or newline */
        if ((p = strpbrk (line, ";\n"))) {
            if (p > line) {         /* test characters in line */
                /* remove all trailing whitespace */
                while (p > line && isspace (*--p)) {}
                *++p = 0;   /* nul-terminate after last non-whitespace char */
            }               /* before ';' or end of line */
            else
                *p = 0;     /* otherwise nul-terminate at ';' */
        }

(यदि आप C ऑपरेटर वरीयता से परिचित नहीं हैं, तो अब यह अच्छा होगा इसके साथ दोस्ती करने का अवसर। यह बताने वाले कॉलम पर ध्यान दें कि क्या जुड़ाव right to left या left to right है, इससे फर्क पड़ता है)

उदाहरण उपयोग/आउटपुट

अब आप पूर्ण आउटपुट की जांच कर सकते हैं और पुष्टि कर सकते हैं कि टिप्पणियों और सभी पिछली सफेद जगहों को हटा दिया गया है। (जब आप संतुष्ट हों तो आप सिंगल-कोट्स को हटा सकते हैं, जैसा कि इसे करना चाहिए)

$ ./bin/parsesemicmt <dat/semicmtfile.txt
  1: ''
  2: ''
  3: ''
  4: ''
  5: 'defun testIfs'
  6: ''
  7: 'arg1'
  8: ''
  9: 'dup 16 gt'
 10: 'if'
 11: ''
 12: '    dup 8 gt'
 13: '    if'
 14: ''
 15: '        dup 4 gt'
 16: '    if'
 17: '        0'
 18: '    else'
 19: '        1'
 20: '    endif'
 21: ''
 22: '    else'
 23: '       2'
 24: '    endif'
 25: ''
 26: 'else'
 27: ''
 28: '     dup 24 gt'
 29: '     if'
 30: ''
 31: '        dup 20 gt'
 32: '    if'
 33: '           3'
 34: '        else'
 35: '           4'
 36: '    endif'
 37: ''
 38: '     else'
 39: ''
 40: '        dup 32 gt'
 41: '        if'
 42: '           5'
 43: '    else'
 44: '        -10'
 45: '        endif'
 46: ''
 47: '     endif'
 48: ''
 49: 'endif'
 50: ''
 51: 'return'
 52: ''
 53: ''
 54: 'defun main'
 55: '5 testIfs printnum endl'
 56: '11 testIfs printnum endl'
 57: '28 testIfs printnum endl'
 58: '35 testIfs printnum endl'
 59: 'return'

ध्यान दें: जैसा कि आपके द्वारा टिप्पणी किए गए कोड में दर्शाया गया है, यदि आप strtok को कॉल करना चाहते हैं, तो पिछली खाली जगह को हटाने की कोई आवश्यकता नहीं है। यदि आप line को टोकन करते समय एक स्थान को टोकन में से एक के रूप में शामिल करते हैं, तो सभी अनुक्रमिक घटनाओं को एक एकल टोकन माना जाएगा और वहां से हटा दिया जाएगा।

चीजों को देखें और मुझे बताएं कि क्या आपका कोई प्रश्न है। अगर मैंने आपके प्रश्न का गलत अर्थ निकाला है, तो मुझे बताएं और मुझे आगे परीक्षण करने में खुशी होगी।

1
David C. Rankin 23 जुलाई 2018, 03:33