Przeprowadziliśmy eksperymenty, aby zbadać gramatykę skryptów wsadowych. Zbadaliśmy również różnice między trybem wsadowym a trybem wiersza poleceń.
Parser wiersza wsadu:
Oto krótki przegląd faz w parserze linii pliku wsadowego:
Faza 0) Linia odczytu:
Faza 1) Procentowa ekspansja:
Faza 2) Przetwarzaj znaki specjalne, tokenizuj i twórz buforowany blok poleceń: jest to złożony proces, na który wpływają takie rzeczy, jak cudzysłowy, znaki specjalne, ograniczniki tokenów i znaki specjalne.
Faza 3) Powtórz przeanalizowane polecenie (polecenia) Tylko wtedy, gdy blok poleceń nie rozpoczął się @
, a funkcja ECHO była WŁĄCZONA na początku poprzedniego kroku.
Faza 4) %X
Rozszerzenie zmiennej FOR : Tylko wtedy, gdy polecenie FOR jest aktywne i polecenia po DO są przetwarzane.
Faza 5) Opóźniona ekspansja: Tylko jeśli opóźniona ekspansja jest włączona
Faza 5.3) Przetwarzanie potoku : tylko wtedy, gdy polecenia są po obu stronach rury
Faza 5.5) Wykonaj przekierowanie:
Faza 6) Przetwarzanie wywołania / podwojenie karetki: Tylko jeśli token polecenia to CALL
Faza 7) Wykonaj: Polecenie jest wykonywane
Oto szczegóły dla każdej fazy:
Zauważ, że fazy opisane poniżej to tylko model działania parsera wsadowego. Rzeczywiste wewnętrzne funkcje cmd.exe mogą nie odzwierciedlać tych faz. Ale ten model jest skuteczny w przewidywaniu zachowania skryptów wsadowych.
Faza 0) Czytaj linię: Odczytaj najpierw linię wejściową <LF>
.
- Podczas odczytywania wiersza do przeanalizowania jako polecenia,
<Ctrl-Z>
(0x1A) jest odczytywane jako <LF>
(LineFeed 0x0A)
- Gdy GOTO lub CALL odczytuje linie podczas skanowania przez: etykiety
<Ctrl-Z>
, działa jako samo - to nie przekształca się<LF>
Faza 1) Procentowa ekspansja:
- Podwójny
%%
zostaje zastąpiony pojedynczym%
- Rozbudowa argumentów (
%*
, %1
, %2
, itd.)
- Ekspansja
%var%
, jeśli var nie istnieje, zastąp je niczym
- Linia jest początkowo obcięta, a
<LF>
nie wewnątrz%var%
rozwijania
- Aby uzyskać pełne wyjaśnienie, przeczytaj pierwszą połowę tego z dbenham Ten sam wątek: Percent Phase
Faza 2) Przetwarzaj znaki specjalne, tokenizuj i stwórz buforowany blok poleceń: jest to złożony proces, na który wpływają takie rzeczy, jak cudzysłowy, znaki specjalne, ograniczniki tokenów i znaki daszka. Poniżej przedstawiono przybliżenie tego procesu.
Istnieją koncepcje, które są ważne na tym etapie.
- Token to po prostu ciąg znaków, który jest traktowany jako jednostka.
- Tokeny są oddzielone ogranicznikami znaczników. Standardowymi ogranicznikami tokenów są
<space>
<tab>
;
,
=
<0x0B>
<0x0C>
i<0xFF>
kolejne ograniczniki tokenów są traktowane jako jeden - między ogranicznikami tokenów nie ma pustych tokenów
- W ciągu ujętym w cudzysłów nie ma ograniczników znaczników. Cały cytowany ciąg jest zawsze traktowany jako część pojedynczego tokenu. Pojedynczy token może składać się z kombinacji ciągów znaków w cudzysłowie i znaków niecytowanych.
Następujące znaki mogą mieć specjalne znaczenie w tej fazie, w zależności od kontekstu: <CR>
^
(
@
&
|
<
>
<LF>
<space>
<tab>
;
,
=
<0x0B>
<0x0C>
<0xFF>
Spójrz na każdą postać od lewej do prawej:
- Jeśli
<CR>
to usuń go, jakby nigdy go tam nie było (z wyjątkiem dziwnego zachowania przekierowania )
- Jeśli daszek (
^
), następny znak jest zmieniany, a uciekający znak jest usuwany. Postacie, którym uciekł, tracą wszelkie specjalne znaczenie (z wyjątkiem <LF>
).
- Jeśli quote (
"
), przełącz flagę quote. Jeśli flaga cudzysłowu jest aktywna, to tylko "
i<LF>
są specjalne. Wszystkie inne znaki tracą swoje specjalne znaczenie, dopóki następny cytat nie wyłączy flagi cytatu. Nie można uciec od notowania zamykającego. Wszystkie cytowane znaki zawsze znajdują się w tym samym tokenie.
<LF>
zawsze wyłącza flagę cytatu. Inne zachowania różnią się w zależności od kontekstu, ale cytaty nigdy nie zmieniają zachowania<LF>
.
- Uciekł
<LF>
<LF>
jest pozbawiony
- Następna postać jest uciekana. Jeśli bufor znajduje się na końcu linii, to następna linia jest odczytywana i przetwarzana przez fazy 1 i 1.5 i dołączana do bieżącej przed przejściem na następny znak. Jeśli następny znak to
<LF>
, to jest traktowany jako literał, co oznacza, że ten proces nie jest rekurencyjny.
- Bez znaku zmiany znaczenia
<LF>
nie w nawiasach
<LF>
jest usuwany i analizowanie bieżącej linii jest przerywane.
- Wszelkie pozostałe znaki w buforze linii są po prostu ignorowane.
- Bez znaku zmiany znaczenia
<LF>
w bloku FOR IN w nawiasach
<LF>
jest konwertowany na <space>
- Jeśli na końcu bufora linii, to następna linia jest odczytywana i dołączana do bieżącej.
- Bez znaku zmiany znaczenia
<LF>
w bloku poleceń w nawiasach
<LF>
jest konwertowany na <LF><space>
, a <space>
jest traktowany jako część następnego wiersza bloku poleceń.
- Jeśli na końcu bufora linii, to następna linia jest odczytywana i dodawana do spacji.
- Jeśli jeden ze znaków specjalnych
&
|
<
lub >
, podziel linię w tym miejscu, aby obsłużyć potoki, konkatenację poleceń i przekierowanie.
- W przypadku rury (
|
) każda strona jest oddzielnym poleceniem (lub blokiem poleceń), które otrzymuje specjalną obsługę w fazie 5.3
- W przypadku
&
, &&
lub ||
polecenia konkatenacji z każdej strony łączenie jest traktowany jako osobna polecenia.
- W przypadku
<
, <<
, >
lub >>
przekierowania klauzula przekierowania jest analizowany czasowo usunięty, a następnie dodawana na końcu zadanego prądu. Klauzula przekierowania składa się z opcjonalnej cyfry uchwytu pliku, operatora przekierowania i tokenu miejsca docelowego przekierowania.
- Jeśli token poprzedzający operator przekierowania jest pojedynczą cyfrą bez znaku zmiany znaczenia, wówczas cyfra określa uchwyt pliku, który ma zostać przekierowany. Jeśli token uchwytu nie zostanie znaleziony, przekierowanie wyjścia jest domyślnie ustawione na 1 (stdout), a przekierowanie wejścia domyślnie na 0 (stdin).
- Jeśli pierwszy token tego polecenia (przed przeniesieniem przekierowania na koniec) zaczyna się od
@
, to @
ma specjalne znaczenie. ( @
nie jest wyjątkowy w żadnym innym kontekście)
- Oferta specjalna
@
została usunięta.
- Jeśli ECHO jest włączone, to polecenie, wraz z następującymi po nim połączonymi poleceniami w tej linii, jest wykluczone z echa fazy 3. Jeśli
@
jest przed otwarciem (
, cały blok umieszczony w nawiasach jest wykluczony z echa fazy 3.
- Nawias procesowy (zawiera instrukcje złożone w wielu wierszach):
- Jeśli parser nie szuka tokenu polecenia,
(
to nie jest specjalny.
- Jeśli parser szuka tokenu polecenia i znajdzie
(
, uruchom nową instrukcję złożoną i zwiększ licznik nawiasów
- Jeśli licznik nawiasów jest> 0,
)
kończy instrukcję złożoną i zmniejsza licznik nawiasów.
- Jeśli osiągnięto koniec linii, a licznik nawiasów jest> 0, to następna linia zostanie dołączona do instrukcji złożonej (zaczyna się ponownie od fazy 0)
- Jeśli licznik nawiasów wynosi 0, a parser szuka polecenia, wówczas
)
działa podobnie do aREM
instrukcji, o ile bezpośrednio następuje po niej ogranicznik tokenu, znak specjalny, nowa linia lub koniec pliku
- Wszystkie znaki specjalne tracą znaczenie z wyjątkiem
^
(możliwe jest łączenie wierszy)
- Po osiągnięciu końca linii logicznej całe „polecenie” jest odrzucane.
- Każde polecenie jest przetwarzane na serię tokenów. Pierwszy token jest zawsze traktowany jako żeton polecenia (po
@
usunięciu elementu specjalnego i przeniesieniu przekierowania na koniec).
- Wiodące ograniczniki znaczników przed znacznikiem polecenia są usuwane
- Podczas analizowania tokenu polecenia
(
działa jako ogranicznik tokenu polecenia, oprócz standardowych ograniczników tokenu
- Obsługa kolejnych tokenów zależy od polecenia.
- Większość poleceń po prostu łączy wszystkie argumenty po tokenie polecenia w token z pojedynczym argumentem. Wszystkie ograniczniki tokenu argumentów są zachowywane. Opcje argumentów zwykle nie są analizowane do fazy 7.
- Trzy polecenia mają specjalną obsługę - IF, FOR i REM
- IF jest podzielone na dwie lub trzy odrębne części, które są przetwarzane niezależnie. Błąd składni w konstrukcji IF spowoduje fatalny błąd składniowy.
- Operacja porównania to rzeczywiste polecenie, które przechodzi przez całą drogę do fazy 7
- Wszystkie opcje IF są w pełni analizowane w fazie 2.
- Kolejne ograniczniki znaczników zwijają się w jedno miejsce.
- W zależności od operatora porównania zostanie zidentyfikowany jeden lub dwa tokeny wartości.
- Blok poleceń True to zestaw poleceń występujących po warunku i jest przetwarzany tak, jak każdy inny blok poleceń. Jeśli ma być używane ELSE, wówczas blok True musi być umieszczony w nawiasach.
- Opcjonalny blok poleceń False to zestaw poleceń występujących po ELSE. Ponownie, ten blok poleceń jest analizowany normalnie.
- Bloki poleceń Prawda i Fałsz nie przechodzą automatycznie do kolejnych faz. Ich dalsze przetwarzanie jest kontrolowane przez fazę 7.
- FOR jest podzielone na dwie części po DO. Błąd składniowy w konstrukcji FOR spowoduje fatalny błąd składniowy.
- Część przez DO jest rzeczywistym poleceniem iteracji FOR, które przepływa przez całą fazę 7
- Wszystkie opcje FOR są w pełni analizowane w fazie 2.
- Klauzula IN w nawiasach jest traktowana
<LF>
jako <space>
. Po przeanalizowaniu klauzuli IN wszystkie tokeny są łączone w celu utworzenia pojedynczego tokenu.
- Kolejne separatory znaczników bez znaku zmiany znaczenia / bez cudzysłowu zwijają się w jedno miejsce w całym poleceniu FOR poprzez DO.
- Część po DO to blok poleceń, który jest analizowany normalnie. Późniejsze przetwarzanie bloku poleceń DO jest kontrolowane przez iterację w fazie 7.
- REM wykryty w fazie 2 jest traktowany dramatycznie inaczej niż wszystkie inne polecenia.
- Tylko jeden token argumentu jest analizowany - parser ignoruje znaki po pierwszym tokenie argumentu.
- Polecenie REM może pojawić się na wyjściu fazy 3, ale polecenie nigdy nie jest wykonywane, a oryginalny tekst argumentu jest powtarzany - znaki ucieczki nie są usuwane, z wyjątkiem ...
- Jeśli istnieje tylko jeden token argumentu, który kończy się znakiem bez zmiany znaczenia,
^
który kończy wiersz, token argumentu jest odrzucany, a kolejny wiersz jest analizowany i dołączany do REM. Powtarza się, dopóki nie będzie więcej niż jeden żeton lub nie będzie ostatniego znaku ^
.
- Jeśli żeton polecenia zaczyna się od
:
i jest to pierwsza runda fazy 2 (nie jest to restart z powodu CALL w fazie 6), to
- Token jest zwykle traktowany jako niezrealizowana etykieta .
- Pozostała część linii jest analizowany jednak
)
, <
, >
, &
i |
nie ma specjalnego znaczenia. Cała pozostała część wiersza jest traktowana jako część etykiety „polecenie”.
^
Nadal jest wyjątkowy, co oznacza, że linia kontynuacja może być używany do dołączania późniejszą linię do etykiety.
- Niezrealizowanej Label w nawiasach bloku spowoduje śmiertelny błąd składni, chyba że następuje bezpośrednio poleceniem lub Wykonane Etykieta w następnym wierszu.
(
nie ma już specjalnego znaczenia dla pierwszego polecenia, które następuje po niewykonanej etykiecie .
- Polecenie jest przerywane po zakończeniu analizowania etykiet. Kolejne fazy nie odbywają się w przypadku etykiety
- Istnieją trzy wyjątki, które mogą spowodować, że etykieta znaleziona w fazie 2 będzie traktowana jako etykieta wykonana, która kontynuuje analizę w fazie 7.
- Jest przekierowania, które poprzedza etykieta pozornych i jest
|
rura lub &
, &&
czy ||
polecenie konkatenacji na linii.
- Istnieje przekierowanie, które poprzedza token etykiety, a polecenie znajduje się w bloku w nawiasach.
- Token etykiety jest pierwszym poleceniem w wierszu w bloku umieszczonym w nawiasach, a powyższy wiersz kończy się niewykonaną etykietą .
- Poniższe zdarzenia mają miejsce, gdy wykonywana etykieta zostanie odkryta w fazie 2
- Etykieta, jej argumenty i przekierowanie są wyłączone z jakiegokolwiek wyjścia echa w fazie 3
- Wszelkie kolejne połączone polecenia w wierszu są w pełni analizowane i wykonywane.
- Więcej informacji na temat wykonanych etykiet i niezrealizowanych etykiet można znaleźć na stronie https://www.dostips.com/forum/viewtopic.php?f=3&t=3803&p=55405#p55405
Faza 3) Powtórz przeanalizowane polecenie (polecenia) Tylko wtedy, gdy blok poleceń nie rozpoczął się @
, a funkcja ECHO była WŁĄCZONA na początku poprzedniego kroku.
Faza 4) %X
Rozszerzenie zmiennej FOR : Tylko wtedy, gdy polecenie FOR jest aktywne i polecenia po DO są przetwarzane.
- W tym momencie faza 1 przetwarzania wsadowego będzie już konwertować zmienną FOR, taką jak
%%X
na %X
. W wierszu poleceń obowiązują różne reguły rozszerzania procentowego dla fazy 1. Jest to powód, dla którego w wierszach poleceń używane są zmienne FOR, %X
ale pliki wsadowe %%X
.
- W nazwach zmiennych FOR rozróżniana jest wielkość liter, ale
~modifiers
nie.
~modifiers
mają pierwszeństwo przed nazwami zmiennych. Jeśli następujący po nim znak ~
jest zarówno modyfikatorem, jak i prawidłową nazwą zmiennej FOR, a istnieje kolejny znak, który jest aktywną nazwą zmiennej FOR, to znak jest interpretowany jako modyfikator.
- Nazwy zmiennych FOR są globalne, ale tylko w kontekście klauzuli DO. Jeśli procedura jest wywoływana z klauzuli FOR DO, wówczas zmienne FOR nie są rozwijane w ramach procedury CALLed. Ale jeśli procedura ma swoje własne polecenie FOR, wówczas wszystkie aktualnie zdefiniowane zmienne FOR są dostępne dla wewnętrznych poleceń DO.
- Nazwy zmiennych FOR mogą być ponownie używane w zagnieżdżonych FORach. Wewnętrzna wartość FOR ma pierwszeństwo, ale po zamknięciu INNER FOR przywracana jest zewnętrzna wartość FOR.
- Jeśli ECHO było włączone na początku tej fazy, to faza 3) jest powtarzana, aby pokazać przeanalizowane polecenia DO po rozwinięciu zmiennych FOR.
---- Od tego momentu każde polecenie zidentyfikowane w fazie 2 jest przetwarzane oddzielnie.
---- Fazy od 5 do 7 są zakończone dla jednej komendy przed przejściem do następnej.
Faza 5) Opóźnione rozwinięcie: Tylko jeśli opóźnione rozwijanie jest włączone, polecenie nie znajduje się w bloku w nawiasach po żadnej stronie potoku , a polecenie nie jest „nagim” skryptem wsadowym (nazwa skryptu bez nawiasów, CALL, konkatenacja poleceń, lub rura).
- Każdy token polecenia jest niezależnie analizowany pod kątem opóźnionego rozwinięcia.
- Większość poleceń analizuje dwa lub więcej tokenów - token polecenia, token argumentów i każdy token miejsca docelowego przekierowania.
- Polecenie FOR analizuje tylko token klauzuli IN.
- Polecenie JEŻELI analizuje tylko wartości porównania - jedną lub dwie, w zależności od operatora porównania.
- Dla każdego przeanalizowanego tokenu najpierw sprawdź, czy jakikolwiek zawiera
!
. Jeśli nie, to token nie jest analizowany - ważne dla ^
postaci. Jeśli token zawiera !
, zeskanuj każdy znak od lewej do prawej:
- Jeśli jest to daszek (
^
), następny znak nie ma specjalnego znaczenia, sam daszek jest usuwany
- Jeśli jest to wykrzyknik, poszukaj następnego wykrzyknika (daszki nie są już obserwowane), rozwiń do wartości zmiennej.
- Kolejne otwarcia
!
są zwinięte w jeden!
- Wszelkie pozostałe niesparowane
!
zostaną usunięte
- Rozszerzanie zmiennych na tym etapie jest „bezpieczne”, ponieważ znaki specjalne nie są już wykrywane (nawet
<CR>
lub <LF>
)
- Aby uzyskać pełniejsze wyjaśnienie, przeczytaj drugą połowę tego z tego samego wątku dbenham
- Exclamation Point Phase
Faza 5.3) Przetwarzanie potoku : tylko wtedy, gdy polecenia znajdują się po obu stronach potoku
Każda strona potoku jest przetwarzana niezależnie i asynchronicznie.
- Jeśli polecenie jest wewnętrzne dla cmd.exe, jest to plik wsadowy lub jeśli jest to blok poleceń w nawiasach, to jest wykonywane w nowym wątku cmd.exe przez
%comspec% /S /D /c" commandBlock"
, więc blok poleceń otrzymuje ponownie fazę, ale tym razem w trybie wiersza poleceń.
- Jeśli blok poleceń ujętych w nawiasy, wszystkie
<LF>
z poleceniem przed i po są konwertowane na <space>&
. Inni <LF>
są pozbawieni.
- To jest koniec przetwarzania poleceń potoku.
- Zobacz Dlaczego opóźnione rozwinięcie kończy się niepowodzeniem, gdy znajduje się w bloku kodu potokowym? aby uzyskać więcej informacji na temat analizy i przetwarzania potoków
Faza 5.5) Wykonywanie przekierowania: Każde przekierowanie wykryte w fazie 2 jest teraz wykonywane.
Faza 6) Przetwarzanie CALL / podwajanie Caret: Tylko jeśli token polecenia to CALL lub jeśli tekst przed pierwszym występującym standardowym ogranicznikiem tokena to CALL. Jeśli CALL jest analizowany z większego tokenu polecenia, to nieużywana część jest dodawana do tokenu argumentów przed kontynuowaniem.
- Przeskanuj token argumentów w poszukiwaniu niecytowanego
/?
. Jeśli zostanie znaleziony w dowolnym miejscu na żetonach, przerwij fazę 6 i przejdź do fazy 7, gdzie zostanie wydrukowana POMOC dla WEZWANIA.
- Usuń pierwszą
CALL
, aby można było ułożyć wiele połączeń CALL
- Podwój wszystkie karety
- Zrestartuj fazy 1, 1.5 i 2, ale nie kontynuuj do fazy 3
- Wszelkie podwójne karetki są redukowane z powrotem do jednego daszka, o ile nie są cytowane. Ale niestety cytowane karetki pozostają podwojone.
- Faza 1 trochę się zmienia
- Błędy rozszerzenia w kroku 1.2 lub 1.3 przerywają wywołanie, ale błąd nie jest krytyczny - przetwarzanie wsadowe jest kontynuowane.
- Zadania fazy 2 zostały nieco zmienione
- Każde nowo pojawiające się przekierowanie bez cytowania, bez zmiany znaczenia, które nie zostało wykryte w pierwszej rundzie fazy 2, jest wykrywane, ale jest usuwane (łącznie z nazwą pliku) bez faktycznego wykonywania przekierowania
- Każdy nowo pojawiający się niecytowany, nieskrócony daszek na końcu wiersza jest usuwany bez wykonywania kontynuacji wiersza
- CALL jest przerywane bez błędu, jeśli zostanie wykryta którakolwiek z poniższych sytuacji
- Nowo pojawiające się bez cytowania, bez zmiany znaczenia
&
lub|
- Wynikowy token polecenia zaczyna się od niecytowanego, bez znaku zmiany znaczenia
(
- Pierwszy token po usuniętym CALL zaczął się od
@
- Jeśli wynikowe polecenie jest pozornie prawidłowym IF lub FOR, to wykonanie zakończy się niepowodzeniem z błędem stwierdzającym, że
IF
lubFOR
nie jest rozpoznawane jako polecenie wewnętrzne lub zewnętrzne.
- Oczywiście CALL nie jest przerywany w tej drugiej rundzie fazy 2, jeśli wynikowy token polecenia jest etykietą zaczynającą się od
:
.
- Jeśli wynikowym tokenem polecenia jest CALL, zrestartuj fazę 6 (powtarza się, aż nie będzie więcej CALL)
- Jeśli wynikowym tokenem polecenia jest skrypt wsadowy lub etykieta:, wówczas wykonanie CALL jest w pełni obsługiwane przez pozostałą część Fazy 6.
- Umieść bieżącą pozycję pliku skryptów wsadowych na stosie wywołań, aby wykonanie mogło zostać wznowione z właściwej pozycji po zakończeniu CALL.
- Skonfiguruj tokeny argumentów% 0,% 1,% 2, ...% N i% * dla CALL, używając wszystkich wynikowych tokenów
- Jeśli token polecenia jest etykietą rozpoczynającą się od
:
, to
- Uruchom ponownie fazę 5. Może to mieć wpływ na to, co: etykieta jest WYWOŁANA. Ale ponieważ tokeny% 0 itd. Zostały już ustawione, nie zmieni to argumentów, które są przekazywane do procedury CALLed.
- Wykonaj etykietę GOTO, aby ustawić wskaźnik pliku na początku podprogramu (zignoruj inne tokeny, które mogą występować po: etykiecie). Zobacz Faza 7, aby zapoznać się z zasadami działania GOTO.
- W przeciwnym razie przenieś kontrolę do określonego skryptu wsadowego.
- Wykonywanie etykiety lub skryptu CALLed: jest kontynuowane do momentu osiągnięcia EXIT / B lub końca pliku, w którym to momencie stos CALL jest zdejmowany i wykonywanie jest wznawiane od zapisanej pozycji pliku.
Faza 7 nie jest wykonywana dla skryptów CALLed lub: etykiet.
- W przeciwnym razie wynik fazy 6 przechodzi do fazy 7 w celu wykonania.
Faza 7) Wykonaj: Polecenie jest wykonywane
- 7.1 - Wykonaj polecenie wewnętrzne - jeśli token polecenia jest umieszczony w cudzysłowie, pomiń ten krok. W przeciwnym razie spróbuj przeanalizować wewnętrzne polecenie i wykonać.
- Poniższe testy są wykonywane w celu ustalenia, czy niecytowany token polecenia reprezentuje polecenie wewnętrzne:
- Jeśli token polecenia dokładnie pasuje do polecenia wewnętrznego, wykonaj je.
- W przeciwnym razie podziel token polecenia przed pierwszym wystąpieniem
+
/
[
]
<space>
<tab>
,
;
lub =
Jeśli poprzedzający tekst jest poleceniem wewnętrznym, zapamiętaj to polecenie
- Jeśli w trybie wiersza poleceń lub jeśli polecenie pochodzi z bloku w nawiasach, jeśli prawda lub fałsz, blok poleceń, blok polecenia FOR DO lub jest związane z konkatenacją poleceń, wykonaj polecenie wewnętrzne
- W przeciwnym razie (musi być samodzielnym poleceniem w trybie wsadowym) przeskanuj bieżący folder i ŚCIEŻKĘ w poszukiwaniu pliku .COM, .EXE, .BAT lub .CMD, którego nazwa podstawowa jest zgodna z oryginalnym tokenem polecenia
- Jeśli pierwszy pasujący plik to .BAT lub .CMD, przejdź do 7.3.exec i wykonaj ten skrypt
- W przeciwnym razie (nie znaleziono dopasowania lub pierwsze dopasowanie to .EXE lub .COM) wykonaj zapamiętane polecenie wewnętrzne
- W przeciwnym razie podziel token polecenia przed pierwszym wystąpieniem
.
\
lub :
Jeśli poprzedzający tekst nie jest poleceniem wewnętrznym, to goto 7.2 W
przeciwnym razie poprzedzający tekst może być poleceniem wewnętrznym. Zapamiętaj to polecenie.
- Złam token polecenia przed pierwszym wystąpieniem
+
/
[
]
<space>
<tab>
,
;
lub =
Jeśli poprzedzający tekst jest ścieżką do istniejącego pliku, przejdź do 7.2 W przeciwnym razie
wykonaj zapamiętane polecenie wewnętrzne.
- Jeśli polecenie wewnętrzne jest analizowane z większego tokenu polecenia, nieużywana część tokenu polecenia jest uwzględniana na liście argumentów
- Tylko dlatego, że token polecenia jest analizowany jako polecenie wewnętrzne, nie oznacza, że zostanie wykonany pomyślnie. Każde polecenie wewnętrzne ma własne zasady dotyczące sposobu analizowania argumentów i opcji oraz dozwolonej składni.
- Wszystkie polecenia wewnętrzne, jeśli
/?
zostaną wykryte, wyświetlą pomoc zamiast wykonywać swoją funkcję . Większość rozpoznaje, /?
czy pojawia się gdziekolwiek w argumentach. Ale kilka poleceń, takich jak ECHO i SET, wyświetla pomoc tylko wtedy, gdy pierwszy argument token zaczyna się od /?
.
- SET ma kilka interesujących semantyki:
- Jeśli polecenie SET ma cudzysłów przed nazwą zmiennej i włączonymi rozszerzeniami
set "name=content" ignored
-> wartość =content
to tekst między pierwszym znakiem równości a ostatnim cudzysłowem jest używany jako treść (z wyłączeniem pierwszego równego i ostatniego cudzysłowu). Tekst po ostatnim cudzysłowie jest ignorowany. Jeśli po znaku równości nie ma cudzysłowu, to reszta wiersza jest używana jako treść.
- Jeśli polecenie SET nie ma cudzysłowu przed nazwą
set name="content" not ignored
-> wartość =, "content" not ignored
cała pozostała część wiersza po równości jest używana jako treść, w tym wszelkie możliwe cudzysłowy.
- Oceniane jest porównanie JEŻELI iw zależności od tego, czy warunek jest prawdziwy, czy fałszywy, przetwarzany jest odpowiedni już przeanalizowany zależny blok poleceń, zaczynając od fazy 5.
- Klauzula IN polecenia FOR jest odpowiednio iterowana.
- Jeśli jest to FOR / F, który iteruje wyjście bloku poleceń, to:
- Klauzula IN jest wykonywana w nowym procesie cmd.exe za pośrednictwem CMD / C.
- Blok poleceń musi przejść przez cały proces analizy po raz drugi, ale tym razem w kontekście wiersza poleceń
- ECHO zacznie działać WŁĄCZONY, a opóźnione rozszerzanie będzie zwykle wyłączane (w zależności od ustawienia rejestru)
- Wszystkie zmiany środowiska wprowadzone przez blok poleceń klauzuli IN zostaną utracone po zakończeniu procesu potomnego cmd.exe
- Dla każdej iteracji:
- Zdefiniowano wartości zmiennych FOR
- Już przeanalizowany blok poleceń DO jest następnie przetwarzany, zaczynając od fazy 4.
- GOTO używa następującej logiki do zlokalizowania: etykieta
- Etykieta jest analizowana z pierwszego tokenu argumentu
- Skrypt jest skanowany pod kątem następnego wystąpienia etykiety
- Skanowanie rozpocznie się od aktualnej pozycji pliku
- Po osiągnięciu końca pliku skanowanie wraca do początku pliku i jest kontynuowane do pierwotnego punktu początkowego.
- Skanowanie zatrzymuje się przy pierwszym wystąpieniu znalezionej etykiety, a wskaźnik pliku jest ustawiany na linię znajdującą się bezpośrednio po etykiecie. Wykonywanie skryptu jest wznawiane od tego momentu. Zauważ, że udane prawdziwe GOTO natychmiast przerwie każdy przeanalizowany blok kodu, w tym pętle FOR.
- Jeśli etykieta nie zostanie znaleziona lub brakuje tokenu etykiety, operacja GOTO kończy się niepowodzeniem, drukowany jest komunikat o błędzie, a stos wywołań jest przerywany. To skutecznie działa jako EXIT / B, z wyjątkiem wszystkich już przeanalizowanych poleceń w bieżącym bloku poleceń, które następują po GOTO, są nadal wykonywane, ale w kontekście CALLer (kontekst, który istnieje po EXIT / B)
- Zobacz https://www.dostips.com/forum/viewtopic.php?f=3&t=3803, aby uzyskać dokładniejszy opis reguł używanych do analizowania etykiet.
- Zarówno RENAME, jak i COPY akceptują symbole wieloznaczne dla ścieżki źródłowej i docelowej. Ale Microsoft wykonuje okropną robotę dokumentując, jak działają symbole wieloznaczne, szczególnie w przypadku ścieżki docelowej. Przydatny zestaw reguł dotyczących symboli wieloznacznych można znaleźć w artykule Jak polecenie RENAME systemu Windows interpretuje symbole wieloznaczne?
- 7.2 - Wykonaj zmianę głośności - W przeciwnym razie, jeśli token polecenia nie zaczyna się od cudzysłowu, ma dokładnie dwa znaki, a drugi znak to dwukropek, zmień głośność
- Wszystkie tokeny argumentów są ignorowane
- Jeśli nie można znaleźć woluminu określonego przez pierwszy znak, przerwij działanie z błędem
- Token polecenia
::
zawsze spowoduje błąd, chyba że SUBST jest używany do zdefiniowania woluminu dla. ::
Jeśli SUBST jest używany do zdefiniowania woluminu dla ::
, to wolumin zostanie zmieniony i nie będzie traktowany jako etykieta.
- 7.3 - Wykonaj polecenie zewnętrzne - w przeciwnym razie spróbuj traktować polecenie jako polecenie zewnętrzne.
- Jeśli w trybie linii dowodzenia i sterowania nie jest podane, a nie rozpoczyna specyfikacji objętościowego białego przestrzeni,
,
, ;
, =
i +
następnie przerwać polecenie Token na pierwsze wystąpienie <space>
,
;
lub =
i poprzedzić resztę do argumentu tokenu (s).
- Jeśli drugim znakiem tokenu polecenia jest dwukropek, sprawdź, czy można znaleźć wolumin określony przez pierwszy znak.
Jeśli nie można znaleźć woluminu, przerwij z błędem.
- Jeśli w trybie wsadowym token polecenia zaczyna się od
:
, to goto 7.4
Zauważ, że jeśli token etykiety zaczyna się od ::
, to nie zostanie osiągnięty, ponieważ poprzedni krok zostanie przerwany z błędem, chyba że SUBST zostanie użyty do zdefiniowania woluminu dla ::
.
- Zidentyfikuj polecenie zewnętrzne do wykonania.
- Jest to złożony proces, który może obejmować bieżący wolumin, bieżący katalog, zmienną PATH, zmienną PATHEXT i / lub skojarzenia plików.
- Jeśli nie można zidentyfikować prawidłowego polecenia zewnętrznego, przerwij z błędem.
- Jeśli w trybie wiersza poleceń, a token polecenia zaczyna się od
:
, to goto 7.4
Zauważ, że rzadko jest to osiągane, ponieważ poprzedni krok zostanie przerwany z błędem, chyba że token polecenia zaczyna się od ::
, a SUBST jest używany do zdefiniowania woluminu dla::
, a cały token polecenia jest prawidłową ścieżką do polecenia zewnętrznego.
- 7.3.exec - Wykonaj polecenie zewnętrzne.
- 7.4 - Ignoruj etykietę - Zignoruj polecenie i wszystkie jego argumenty, jeśli token polecenia zaczyna się od
:
.
Zasady zawarte w 7.2 i 7.3 mogą uniemożliwić etykiecie osiągnięcie tego punktu.
Parser wiersza poleceń:
Działa jak BatchLine-Parser, z wyjątkiem:
Faza 1) Procentowa ekspansja:
- Nie
%*
, %1
itp. Rozwijanie argumentów
- Jeśli var jest niezdefiniowane, to
%var%
pozostaje niezmieniona.
- Brak specjalnego traktowania
%%
. Jeśli var = content, to %%var%%
rozwija się do %content%
.
Faza 3) Powtórz przeanalizowane polecenie (a)
- Nie jest to wykonywane po fazie 2. Jest wykonywane tylko po fazie 4 dla bloku poleceń FOR DO.
Faza 5) Opóźniona rozbudowa: tylko wtedy, gdy włączona jest opcja Opóźniona rozbudowa
- Jeśli zmienna jest niezdefiniowana,
!var!
pozostaje niezmieniona.
Faza 7) Wykonaj polecenie
- Próby CALL lub GOTO a: etykieta powodują błąd.
- Jak już udokumentowano w fazie 7, wykonana etykieta może spowodować błąd w różnych scenariuszach.
- Etykiety wykonywane wsadowo mogą powodować błąd tylko wtedy, gdy zaczynają się od
::
- Etykiety wykonane w wierszu poleceń prawie zawsze powodują błąd
Parsowanie wartości całkowitych
Istnieje wiele różnych kontekstów, w których cmd.exe analizuje wartości całkowite z ciągów, a reguły są niespójne:
SET /A
IF
%var:~n,m%
(rozwinięcie zmiennej podciąg)
FOR /F "TOKENS=n"
FOR /F "SKIP=n"
FOR /L %%A in (n1 n2 n3)
EXIT [/B] n
Szczegóły dotyczące tych reguł można znaleźć w sekcji Zasady dotyczące sposobu analizowania liczb przez program CMD.EXE
Dla każdego, kto chce ulepszyć reguły parsowania cmd.exe, na forum DosTips znajduje się temat do dyskusji, w którym można zgłaszać problemy i proponować.
Mam nadzieję, że to pomaga
Jan Erik (jeb) - Oryginalny autor i odkrywca faz
Dave Benham (dbenham) - Wiele dodatkowych treści i edycji